Можно ли хранить настройки интернет-сайта у себя на компьютере? Можно, если сайт правильно спроектирован: при выборе настроек пользователем, на стороне клиента браузер записывает информацию в cookie. Примеры: http://ir2.ru/static/dhtml3.js

DHTML: хранение настроек пользователя

Для чего нужен Dynamic HTML

  1. Улучшить восприятие страницы и сделать работу с ней более удобной.
    • Скрыть-отобразить часть текста.
      • Выпадающее меню.
      • Скрыть-показать примечания (сноски).
      • Свернуть-развернуть ряд произвольных элементов.
      • Поиск по списку (отбор элементов).
    • Изменить оформление при наведении мыши.
      • Изменение формы курсора.
      • Изменение цвета активных элементов.
      • Изменение цвета строк таблицы.
      • Всплывающие подсказки.
    • Проверка вводимых пользователем данных (валидация) до отправки на сервер.
    • Хранение настроек пользователя.
    • Невидимая (ненавязчивая) защита от спама.
    • Визуальный (wysiwyg) редактор HTML.
    • Уменьшение объёма страницы и трафика (дублирование элементов).
    • Редактирование большой таблицы базы данных.
  2. Оптимизация взаимодействия веб-сервера с клиентом.
    • Фоновые http-запросы с помощью динамического элемента script (или так называемого Ajax'а).
    • Исправление ошибок или небрежностей серверных скриптов (движка).
  3. Создание инструментов разработки.
    • Отображение объектов DOM.
    • Отображение скорости работы браузера.
    • Редактирование большой таблицы базы данных.

11. Можно ли хранить настройки интернет-сайта у себя на компьютере?

Да, если сайт правильный. Только вот зачем это может понадобиться? Очень просто. В начале этой страницы есть список задач, которые можно решить с помощью DHTML. Список при открытии страницы отображается в свёрнутом виде – только три пункта верхнего уровня. Подпункты разворачиваются при наведении мыши на заголовки разделов. Если список вам уже знаком по предыдущим статьям, вам нет необходимости разворачивать его часто. Но если всё-таки вам захочется несколько раз взглянуть на него целиком, постоянная необходимость ёрзать над ним мышкой может поднадоесть. Ну, либо вас просто может раздражать активное поведение списка при случайных движениях мышкой.

Поэтому мы сделали над списком такое окошечко (элемент checkbox), щёлкнув по которому вы а) развернёте весь список, б) запишете состояние списка к себе на компьютер, в ма-аленький файл (?) cookie (куки). Вопрос после слова файл стоит потому, что никто на самом деле не знает, как выглядят куки – файлы это или какие-то записи в базе данных sqlite. И это правильно, потому что нам всё равно, как выглядят куки – главное, что они работают: если вы закроете страницу и вообще окно браузера, а завтра опять откроете, верхний список будет отображаться в том состоянии, в котором вы его оставили в прошлый раз.

И ещё одну кнопочку-флажок до кучи – чтобы вообще убрать список. Всё работает прямо на этой странице. Код javascript, обеспечивающий изменения страницы, находится здесь: dhtml3.js. Для правильного отображения элементов необходимо также правило CSS: #roll ul {display:none;}, означающее, что вложенные в наш список (id=roll) подпункты (элементы UL) изначально на странице не отображаются. Система хранения выбранного пользователем вида страницы работает независимо от сервера: если вы сохраните страницу к себе на компьютер (со всеми сопутствующими файлами, полностью), система останется работоспособной при открытии файла локально.

Принципиальная схема сохранения настроек достаточно проста: 1) при щелчке по активному элементу (у нас это checkbox) в куки записывается «переменная» с неким цифровым значением; 2) при следующем открытии страницы это значение считывается из куки и страница отображается в соответствии с ним.

Код javascript, однако, получился довольно длинным. Но не из-за системы хранения, а из-за вариантов отображения списка. На «интерфейс» всегда уходит много материала. Невинная попытка сделать структуру страницы чуть более понятной легко может вырасти в целую javascript-функцию. Мы споткнулись на LABEL. Этот элемент содержит описание для checkbox'а («флажка»); он удобен, в частности, тем, что для достижения результата щёлкать можно не только по флажку, но и по его описанию. Чтобы лишний раз обратить внимание пользователя на это удобство, мы решили для описаний флажков (label) назначить форму курсора pointer («указатель» в виде руки). Обычно для этого бывает достаточно правила CSS:

label (cursor: pointer;)

Но в данном случае закрались смутные сомненья: ведь ИЕ (в некоторых своих версиях) понимает только слово hand, т.е. по команде pointer он ничего делать не будет. Проверять, в каком браузере открыта страница, – не очень хорошая практика. Идеально было бы проверить, допустимо ли в данном браузере значение pointer для свойства элементов cursor. Но как это сделать? Решение немного ниже.

Логика перевода пожеланий пользователя в цифры

У нас два флажка, по которым для изменения отображения страницы пользователь может щёлкать или не щёлкать. Таким образом, возникает четыре состояния флажков (и страницы):

Флажок «Убрать»Флажок «Развернуть»Состояние спискаЧисловой вид
СвободенСвободенСвёрнут и виден0 (00)
СвободенОтмеченРазвёрнут и виден1 (01)
ОтмеченСвободенСвёрнут и не виден2 (10)
ОтмеченОтмеченРазвёрнут и не виден3 (11)

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

Вполне очевидным стало решение присвоить состоянию флажка «Свободен» цифру 0, а состоянию «Отмечен» – 1. Тогда для отображения всего набора состояний можно будет использовать двухбитовое число, левый бит в котором будет обозначать состояние флажка «Убрать», а правый – «Развернуть». Именно эти числа – 0, 1, 2 или 3 и записываются в куки в качестве значения параметра, названного нами rollstatus. Формируется число статуса так:

  • переменной rollstatus присваивается значение "0";
  • если флажок «Убрать» отмечен, прибавляем к rollstatus "2";
  • если флажок «Развернуть» отмечен, прибавляем к rollstatus "1";
 rollstatus=0;
 rollstatus+=(rollmove.checked)?2:0;
 rollstatus+=(rollch.checked)?1:0;

При чтении куки нам нужно обратное действие: по значению статуса определить состояние флажков (и способ отображения списка). Это, наверное, проще всего сделать с помощью побитовых операторов. То есть для того чтобы узнать, была ли добавлена к числу статуса единица (правый бит), нужно побитово сравнить число статуса с единицей. В данном случае результатом сравнения должно быть совпадение, поэтому сравниваем с помощью оператора &: флажок «Развернуть» должен быть отмечен, если истинно значение выражения (1 & rollstatus). А истинно оно будет для следующих чисел:

status11 & status
0(00)01false
1(01)01true
2(10)01false
3(11)01true

Для получения значения левого бита статуса сравниваем его с двойкой: флажок «Убрать» нужно отметить, если истинно значение выражения (2 & rollstatus).

Стиль внедрения javascript

Стараемся как можно меньше нагружать атрибуты HTML-элементов обращением к javascript. Например, присваиваем нашим флажкам функции по событию onclick в тексте файла dhtml3.js, а не в тексте страницы:

var rollch=document.getElementById("rollch");
rollch.onclick=rollswitch;

Список («свиток», элемент roll) развёртывается при движении мышкой тоже по событию onmouseover, присвоенному всему документу в тексте скрипта: document.onmouseover=mover;, а уже функция mover(e) проверяет, над каким элементом мышь, и решает, что после этого делать.

Элементы «свитка» (списка), у которых есть вложенные подпункты, подчёркиваются на экране, как ссылки (и курсор у них не text, а default – стрелка). После наведения на них мыши, подпункты становятся видимыми, и подчёркивание убирается. Всё это тоже делается через внешний javascript (в той же функции mover(e)).

Во имя той же оптимизации мы читаем-записываем куки не гигантской фукнцией (многочисленные варианты которой кишмя кишат в интернете), а «в одну строку» (ну, в крайнем случае, в две):

//прочитать значение куки rollstatus
var rollstatus=/rollstatus\s*\=\s*(\d+)/im.exec(document.cookie);
rollstatus=rollstatus && rollstatus[1];
//записать значение куки rollstatus
document.cookie="rollstatus="+rollstatus+"; expires=" + expires+"; path=/";

Необходимо, правда, сначала вычислить expires. Это делается стандартным способом (тут трудно что-либо улучшить), один раз, при загрузке страницы:

var expires = new Date(); 
expires.setTime(expires.getTime()+36*24*60*60*1000);
expires = expires.toGMTString();

12. Допустимо ли определённое значение CSS в данном браузере?

Проверить наличие какого-нибудь свойства DOM для конкретного браузера несложно: нужно спросить, не равно ли это свойство значению false. Например, так:

if (document.all) alert("document.all: OK!");
else alert("document.all: нет такой фигни!");

Но как спросить у браузера, готов ли он выполнить команду cursor: pointer;? Мы не нашли другого способа, кроме как попытаться заставить браузер выполнить эту команду, а потом проверить значение свойства cursor. Такой способ допустим благодаря двум особенностям: 1) при неправильной команде («невалидном» значении) фатальной ошибки не возникает и работа всех подсистем браузера (CSS, javascript) продолжается нормально; 2) при попытке назначить невалидное значение CSS, данное значение, каким бы оно ни было до этого момента, становится пустым. Таким образом, мы смело задаём значение какому-то свойству, а потом просто спрашиваем у браузера, каким стало это значение:

//hack IE-'hand'
var ls=document.getElementsByTagName("LABEL");
for (var el in ls) {
 elem=ls[el];
 if (1==elem.nodeType) {
/*Так можно проверить, существует ли значение 'pointer'*/
  elem.style.cursor="pointer";
  if (!elem.style.cursor) elem.style.cursor="hand";
/*Конец проверки значения свойства cursor*/
 }
}
//hack IE-'hand' end
© 2010, «Деловая неделя», Михаил Гутентог

Комментарии