Черновики у меня в комментариях
Мне тут хочется пару проектов на 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МБ на домен, да и диск пользователя забивать жалко. Поэтому я сохраняю время записи, возможно когда-нибудь буду вычищать очень уж старые черновики.
Если предположить, что сервер может лежать, то было бы клёво ещё записывать при сабмите, а удалять только после положительного ответа сервера.
Комментарий для ramil1017.ya.ru:
Да, так и надо сделать.
Только так и происходит.
Правда, похоже, ещё наблюдаются глюки. Надо программировать на свежую голову.
Комментарий для ramil1017.ya.ru:
Глюки поправил и сделал сохранение перед сабмитом.
Комментарий для Евгения Степанищева:
Я бы предложил вот так хранить (удобнее для работы):
localStorage.setItem(’bolkComment’, JSON.stringify({
draft1: {
content: o.val(),
date: new Date()
}
}));
Комментарий для chikuyonok.ru:
Мне ночью лениво было смотреть поддерживается ли нативный JSON (а библиотеку тянуть не хочется) в тех же браузерах, где есть localStorage/globalStorage. Подозреваю, что в FF 2.0 этого нет, но его поддержку (фактически в коде она есть) можно и убрать.
Похоже, что в IE9 localStorage именно что резиновое.
При первой попытке его забить удаётся записать ~5MБ, после очистки при повторной попытке уже ~7.5МБ на тот же домен, затем ~20 и ~99, а дальше скрипт может неожиданно упасть с ошибкой типа «память кончилась». Любопытно.
Комментарий для PastorGL.ya.ru:
Хм… :) Забавно.
Комментарий для 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. Осталось узнать как дела у мобильных браузеров обстоят.
Опера при переполнении стораджа только что предложила увеличить лимит для текущего сайта.
Комментарий для fulc.ru:
Когда у тебя хранилище могло заполниться уже? А посмотри что у тебя там?
Комментарий для Евгения Степанищева:
А с какой целью? Как упражнение или была какая-то надобность?
Спрашиваю потому, что эту фишку пора уже активно использовать. Нужны всяческие идеи и примеры, а то свою голову клинит консерватизмом. Столько времени изгонять мысли о персистенстности данных на клиенте, и внезапно осознать, что уже приплыли, что применять можно и нужно.
Комментарий для fulc.ru:
Как оно выглядело, не помните? Внятно, не пугающе?
Непонятное сообщение может не только домохозяйку отпугнуть от сайта. Типа такого: «Сообщение модуля безопасности: этот сайт запрашивает увеличение квоты жёсткого диска! Рразрешить/Запрретить?!». Брр.
Комментарий для boltai-shaltai:
Черновики, которые я тут сделал, я несколько месяцев назад реализовал в нашей внутренней Вики. Тогда мы ещё считали, что IE7 надо поддерживать.
Подкажите, а что дает «|| null» в цепочки логических вычислений (первая строка)?
Комментарий для Назар:
Да ничего особенного. Просто переменная становится null, а не undefined.
Шикарно, у меня уже с этого сайта 56 записей в сторадже. Кстати, можно посмотреть их количество написав в строке браузера javascript:localStorage.length; а удалять их можно там же в строке браузера: javascript:localStorage.clear();
Кстати, я думаю сделать небольшой счетчик, который будет «смотреть» количество накопившихся записей и если они превысят определенный порог, то вывести сообщение пользователю, что у него много данных в хранилище и предложить перейти на страницу очистки (делается ненавязчиво в виде небольшого баннера). Потом вывести список сохраненных в хранилище данных и даты их последнего обращения с кнопочками или ссылками для их удаления. Или вообще предложить полностью почистить все данные из хранилища.
Комментарий для orcinus.ru:
Зачем? При существующих объёмах жёстких дисков эти 56 записей — копейки.
Комментарий для Евгения Степанищева:
В принципе — логично. Но у некоторых браузеров всё-таки есть предел по объему. Я сейчас на своём сайте экспериментирую с локалстораджем и у меня несколько сотен записей. Но ведь это всё-равно не будет продолжаться вечность. Хочу ещё использовать его для хранения черновиков на корпоративном сайте, так, что там можно будет развернуться и проэкспериментировать на полную мощность.
Комментарий для orcinus.ru:
На всех браузерах он есть, закреплён в стандарте — 10МБ.