Черновики у меня в комментариях

Мне тут хочется пару проектов на PHP доделать, а я что-то давненько, порядка полугода, на нём не программировал вообще. Всё больше Пайтон и Google Go. Поэтому я взялся внести несколько изменений в движок своего сайта, которые давно руки чесались сделать.

В том числе сделал то, что давно просили — черновики в комментариях. Работает только в современных браузерах — IE 8.0+, FF 3.5+, Safari 4.0+, Chrome 4.0+, Opera 10.5+, а так же iOS 2.0+ и Андроид 2.0+. Только такой список, так как сохранение происходит в localStorage.

localStorage — это клиентская база данных «ключ и значение», которые есть сейчас уже во всех распространённых браузерах. Преимущество хранения черновиков именно в ней — черновик сохраняется вне зависимости от того рухнул сервер или нет, ведь localStorage сохраняет данные на диске клиента.

Кстати, я делал библиотеку эмуляции localStorage для IE 6 и 7 (используется behavior userData), но у себя использовать не буду, ни к чему поощрять некрофилию.

Работает всё следующим образом (детально можно посмотреть в исходниках любой страницы с комментариями): когда пользователь делает паузу в наборе комментария, мой JS вызывает localStorage.setItem, где ключём является URL страницы плюс имя поля (у меня их три — имя пользователя, сам комментарий и кому этот комментарий был адресова).

После отправки комментария в теле полученной страницы приходят вызовы localStorage.removeItem, которые удаляют сохранённые значения.

Наконец, если страница была загружена не в результате отправки комментария, вызываются localStorage.getItem, чтобы получить сохранённые значения и подставить их в соответствующие поля.

Вообще-то к localStorage можно обращаться как к массиву, но моя библиотека эмуляции localStorage этот интерфейс не эмулирует. На случай, если я сменю гнев на милость и захочу поддержать IE 6 и 7, я решил пользоваться явными вызовами методов.

Код, с использованием JQuery, получился вот такой:
// globalStorage — это для FF 2.0, но я не уверен, что это правда работает
var storage = window.localStorage || window.globalStorage && window.globalStorage[location.hostname] || null;

if (storage) {
    var savedraft = function s() {
         if (s.hnd) {
             clearTimeout(s.hnd);
         }
        	
         var o = $(this);
        	
         s.hnd = setTimeout(function() {
             try { // если не хватит места, будет исключение
                 var prefix = location.pathname + '#';
                 storage.setItem(prefix + o.attr('name'), o.val());
                 storage.setItem(prefix + '?', +new Date()); // сохраняю время, возможно в будущем буду подчищать старые черновики
             } catch (o) {}
        }, 500);
    }
	
    // каждый элемент, который надо сохранять, имеет класс draft	
    $.each($('.draft'), function(_, value) {
        var o = $(value),
              key = location.pathname + '#' + o.attr('name'),
              v = storage.getItem(key);

	if (savedsuccessfully) { // внешний флаг, что черновик больше не нужен — всё сохранено на сервере		
                  storage.removeItem(key);
              } else if (v !== null) {
                  o.val(v);
              }
              o.keypress(savedraft).change(savedraft);
        })
    }
localStorage не резиновое, у разных браузеров значения различаются, но в целом, там около 5МБ на домен, да и диск пользователя забивать жалко. Поэтому я сохраняю время записи, возможно когда-нибудь буду вычищать очень уж старые черновики.
20 июня 2011 00:42

Рамиль К (ramil1017.ya.ru)
20 июня 2011, 07:16

Если предположить, что сервер может лежать, то было бы клёво ещё записывать при сабмите, а удалять только после положительного ответа сервера.

bolk (bolknote.ru)
20 июня 2011, 09:28, ответ предназначен Рамиль К (ramil1017.ya.ru):

Если предположить, что сервер может лежать, то было бы клёво ещё записывать при сабмите
Да, так и надо сделать.
а удалять только после положительного ответа сервера.
Только так и происходит.

bolk (bolknote.ru)
20 июня 2011, 09:28

Правда, похоже, ещё наблюдаются глюки. Надо программировать на свежую голову.

bolk (bolknote.ru)
20 июня 2011, 09:55, ответ предназначен Рамиль К (ramil1017.ya.ru):

Глюки поправил и сделал сохранение перед сабмитом.

Сергей Чикуёнок (chikuyonok.ru)
20 июня 2011, 12:40, ответ предназначен bolk (bolknote.ru):

Я бы предложил вот так хранить (удобнее для работы):

localStorage.setItem('bolkComment', JSON.stringify({
    draft1: {
        content: o.val(),
        date: new Date()
    }
}));

bolk (bolknote.ru)
20 июня 2011, 14:11, ответ предназначен Сергей Чикуёнок (chikuyonok.ru):

Мне ночью лениво было смотреть поддерживается ли нативный JSON (а библиотеку тянуть не хочется) в тех же браузерах, где есть localStorage/globalStorage. Подозреваю, что в FF 2.0 этого нет, но его поддержку (фактически в коде она есть) можно и убрать.

PastorGL.ya.ru (инкогнито)
20 июня 2011, 16:46

Похоже, что в IE9 localStorage именно что резиновое.

При первой попытке его забить удаётся записать ~5MБ, после очистки при повторной попытке уже ~7.5МБ на тот же домен, затем ~20 и ~99, а дальше скрипт может неожиданно упасть с ошибкой типа "память кончилась". Любопытно.

bolk (bolknote.ru)
20 июня 2011, 17:08, ответ предназначен PastorGL.ya.ru

Хм… :) Забавно.

bolk (bolknote.ru)
20 июня 2011, 21:26, ответ предназначен Сергей Чикуёнок (chikuyonok.ru):

JSON.stringify поддерживают (http://robertnyman.com/javascript/javascript-native-json.html):

IE8, FF3.5, Опера 10.5, Google Chrome 4.0+; Safari 4.0+.

Гм. Выглядит подходяще под список localStorage. Осталось узнать как дела у мобильных браузеров обстоят.

Vladimir Moskva (fulc.ru)
21 июня 2011, 01:55

Опера при переполнении стораджа только что предложила увеличить лимит для текущего сайта.

bolk (bolknote.ru)
21 июня 2011, 09:10, ответ предназначен Vladimir Moskva (fulc.ru):

Когда у тебя хранилище могло заполниться уже? А посмотри что у тебя там?

boltai-shaltai (инкогнито)
24 июня 2011, 15:14, ответ предназначен bolk (bolknote.ru):

Кстати, я делал библиотеку эмуляции localStorage для IE 6 и 7
А с какой целью? Как упражнение или была какая-то надобность?
Спрашиваю потому, что эту фишку пора уже активно использовать. Нужны всяческие идеи и примеры, а то свою голову клинит консерватизмом. Столько времени изгонять мысли о персистенстности данных на клиенте, и внезапно осознать, что уже приплыли, что применять можно и нужно.

boltai-shaltai (инкогнито)
24 июня 2011, 15:21, ответ предназначен Vladimir Moskva (fulc.ru):

Опера при переполнении стораджа только что предложила увеличить лимит для текущего сайта
Как оно выглядело, не помните? Внятно, не пугающе?

Непонятное сообщение может не только домохозяйку отпугнуть от сайта. Типа такого: "Сообщение модуля безопасности: этот сайт запрашивает увеличение квоты жёсткого диска! Рразрешить/Запрретить?!". Брр.

bolk (bolknote.ru)
24 июня 2011, 19:04, ответ предназначен boltai-shaltai

А с какой целью? Как упражнение или была какая-то надобность?
Черновики, которые я тут сделал, я несколько месяцев назад реализовал в нашей внутренней Вики. Тогда мы ещё считали, что IE7 надо поддерживать.

Назар (инкогнито)
27 июня 2011, 13:34

Подкажите, а что дает "|| null" в цепочки логических вычислений (первая строка)?

bolk (bolknote.ru)
27 июня 2011, 15:16, ответ предназначен Назару

Да ничего особенного. Просто переменная становится null, а не undefined.

Orcinus Orca (orcinus.ru)
23 сентября 2011, 10:49

Шикарно, у меня уже с этого сайта 56 записей в сторадже. Кстати, можно посмотреть их количество написав в строке браузера javascript:localStorage.length; а удалять их можно там же в строке браузера: javascript:localStorage.clear();

Orcinus Orca (orcinus.ru)
23 сентября 2011, 11:59

Кстати, я думаю сделать небольшой счетчик, который будет "смотреть" количество накопившихся записей и если они превысят определенный порог, то вывести сообщение пользователю, что у него много данных в хранилище и предложить перейти на страницу очистки (делается ненавязчиво в виде небольшого баннера). Потом вывести список сохраненных в хранилище данных и даты их последнего обращения с кнопочками или ссылками для их удаления. Или вообще предложить полностью почистить все данные из хранилища.

bolk (bolknote.ru)
23 сентября 2011, 15:35, ответ предназначен Orcinus Orca (orcinus.ru):

Зачем? При существующих объёмах жёстких дисков эти 56 записей — копейки.

Orcinus Orca (orcinus.ru)
24 сентября 2011, 18:46, ответ предназначен bolk (bolknote.ru):

В принципе - логично. Но у некоторых браузеров всё-таки есть предел по объему. Я сейчас на своём сайте экспериментирую с локалстораджем и у меня несколько сотен записей. Но ведь это всё-равно не будет продолжаться вечность. Хочу ещё использовать его для хранения черновиков на корпоративном сайте, так, что там можно будет развернуться и проэкспериментировать на полную мощность.

bolk (bolknote.ru)
26 сентября 2011, 14:58, ответ предназначен Orcinus Orca (orcinus.ru):

На всех браузерах он есть, закреплён в стандарте — 10МБ.

Ваше имя или адрес блога (можно OpenID):

Текст вашего комментария, не HTML:

Кому бы вы хотели ответить (или кликните на его аватару)