Россия, Звенигород |
Формы и меню
7.5. Альтернатива: таблицы стилей
Как и в случае статического содержимого и кнопок, Mozilla дублирует большую часть информации о формах и меню в системе стилей.
Возможно, самые важные особенности стилей - те правила, которые определяют XBL-связку, относящуюся к данному XUL-тегу. Атрибут type (для <button>, <toolbarbutton> и <textbox> ) и атрибут editable (для <menulist> ) - все они указываются в правилах стиля. Эти правила определяют для основного XUL-тега конкретную связку, которая в итоге влияет на содержимое тега, его внешний вид и поведение. Изучив XBL, вы сможете добавлять собственные связки и соответствующие правила стилей. Атрибут type затем может предоставить другие варианты элементов управления.
7.5.1. CSS-стили из HTML-форм
Некоторые стандартные стили HTML-форм доступны и для XUL-форм. Они перечислены в таблице 7.2. Более подробную информацию о новых стилях можно найти в черновике документа CSS 3: http://www.w3.org/TR/1999/WDcss3-userint-19990916.
Стили, относящиеся к контурам, до определенной степени соответствуют стилям границ (см. раздел "Альтернатива: таблицы стилей" "Верстка с XUL" , "Проектирование с XUL"). Значения -moz-all для стиля -moz-user-select позволяют быть выбранными нескольким элементам форм. Это полезно, если вы разрабатываете графическую среду разработки для XUL и хотите иметь возможность группировать элементы формы одним действием.
7.5.2. Собственные типы отображения элементов управления
Тег <menupopup> основывается на следующем стиле:
display: -moz-popup
Свойство стиля -moz-appearance заставляет данный тег принимать внешний вид, характерный для графической среды пользователя. Такие типы отображения работают для следующих тегов, описанных в этой лекции:
radio checkbox textfield menulist menulist-button menulist-text menulist-textfield checkbox-container radio-container
7.6. Практика: события и формы в NoteTaker
После многих лекций, в которых мы закладывали фундамент приложения, у нас наконец-то появились некоторые полезные элементы управления. В этом разделе мы избавимся от некоторых накопившихся в окне NoteTaker несуразностей и заменим их нормальными элементами XUL-форм. Мы избавимся от файла .properties и будем отправлять собранные в форме данные на web-сервер. Если диалог будет появляться в результате HTTP-запроса GET, значения параметров из этого запроса также будут использоваться.
Прежде всего, займемся наведением порядка. Мы откажемся от атрибута subpanel и функции handle_click(). Если мы еще хотим отключать какое-либо содержимое, имеет смысл делать это теперь собственными средствами тегов. То есть все источники событий и половина действий и описаний клавиш будут выброшены. Задача, которую решает load_data(), все еще актуальна, но текущая реализация нам больше не подходит.
Наконец, мы избавимся от вспомогательных стилей boxes.css / boxesTemp.css и их тегов <box>. Вместо них у нас будут:
- однострочное поле <textbox> для раздела Summary ;
- многострочное поле <textbox> для раздела Details ;
- два тега <checkbox> для раздела Options ;
- четыре небольших поля <textbox> для раздела Size.
Как показано в листинге 7.4, соответствующие теги очень просты.
<textbox id="dialog.summary"/> <textbox id="dialog.details multiline="true" flex="1"/> <checkbox id="dialog.chop-query" dir="rtl" label="Chop Query" checked="true"/> <checkbox id="dialog.home-page" dir="rtl" label="Home Page" checked="true"/> <textbox id="dialog.width" value="100" maxwidth="3" size="3"/> <textbox id="dialog.height" value="90" maxwidth="3" size="3"/> <textbox id="dialog.top" value="80" maxwidth="3" size="3"/> <textbox id="dialog.left" value="70" maxwidth="3" size="3"/>Листинг 7.4. Новые теги элементов форм для диалога NoteTaker
После внесения этих изменений и некоторой корректировки размещения диалог должен быть похож на снимок на рисунке 7.5.
Перед заменой load_data() мы немного поэкспериментируем. DOM-объекты тегов XUL-форм очень похожи на DOM-объекты тегов HTML-форм. Мы можем многое сделать, обратившись к стандарту DOM 2 HTML или XBL-связкам <checkbox> и так далее, либо просто вспоминая разные трюки, использовавшиеся на web-страницах. Заменим этот код в load_data():
desc = document.createElement("description"); desc.setAttribute("value",value); box = document.getElementById("dialog." + names); box.appendChild(desc);
на этот:
if (box.value) box.value = value;
Так как у большинства элементов форм есть свойство value, нам удалось загрузить большую часть файла .properties в форму одним простым действием.
Поработав над формой, мы бы хотели теперь обработать вводимые пользователем данные: описание заметки. Теперь мы хотим читать данные формы и заполнять ее. Есть много мест, куда можно отправить информацию, но мы попробуем воспользоваться web-сервером. Возможно, когда-нибудь эту заметку можно будет просмотреть из любого браузера Mozilla.
Чтобы сохранить заметку NoteTaker, мы используем уже знакомый по этой лекции код, только слегка адаптируем его и поместим в метод action(). Мы также сохраним массив имен ( names ), который ранее был локальным для load_data(), но сейчас мы сделаем его глобальным. В листинге 7.5 показан новый алгоритм.
if (task == "save") { var req = new XMLHttpRequest(); // Request var params = ""; var i = names.length -1; // build up params while (i>=0) { var widget = document.getElementById ("dialog." + names); if (widget.tagName == "checkbox") params += names + "=" + widget.checked + ";"; else params += names + "=" + widget.value + ";"; i--; } params = encodeURI(params); req.open("POST", "test.cgi"); req.send(params); if ( req.status / 100 != 2 ) // HTTP 2xx Response? throw("Save attempt failed"); }Листинг 7.5. Отправка заметки NoteTaker на web-сервер
Конечно, на web-сервере должен быть test.cgi или его аналог. Если мы запускаем приложение из chrome, test.cgi можно заменить на любой адрес любого сервера.
NoteTaker работает с классическим браузером, поэтому вряд ли он будет загружаться с удаленного сервера. Тем не менее возможно, что во время создания окна ему будут передаваться какие-то аргументы. Так как программное окружение нашего приложения то же, что и у остального chrome, эти аргументы могут передаваться любым способом. Один простой способ - добавить в конец URL NoteTaker параметры в стиле HTTP-запроса GET. Сейчас предполагается
chrome://notetaker/content/editDialog.xul
но тот же документ можно загрузить с помощью
chrome://notetaker/content/editDialog.xul?top=440;left=200
Эта информация далее может быть прочитана с помощью AOM-свойства window.location. Мы сделаем это, создав новую задачу для метода action(), которую назовем load. В отличие от остальных задач, которые как-либо связаны с графическим интерфейсом, эта функция - чистый скрипт. Новый обработчик onload тега <window> будет:
onload="action('load')"
Код, добавляемый в метод action(), показан в листинге 7.6. Объект window.location - один из немногих AOM-объектов, которые доступны и в HTML-, и в XUL-документах. Он предоставляет объект с помощью интерфейса nsIDOMLocation и полезен в XUL только в описанном случае.
if (task == "load" ) { var pair, widget; params = window.location.toString(); if ( params.indexOf("?") == -1 ) return; params = params.replace(/.*\?/,""); params = params.split(/[;&]/); i = params.length – 1; while (i >=0 ) { pair = params.split(/=/); pair[0] = decodeURI(pair[0]); pair[1] = decodeURI(pair[1]); widget = document.getElementById("dialog."+ pair[0]) if (widget.tagName == "checkbox") widget.checked = ( pair[1] == "true" ); else widget.value = pair[1]; i--; } }Листинг 7.6. Чтение параметров из URL в стиле GET-запроса
В этом коде используется поддержка регулярных выражений из ECMAScript 1.3. Метод replace() применяется для удаления всех символов до символа ?, с которого начинается строка параметров. split() разделяет оставшуюся строку на массив строк с разделением везде, где происходит совпадение с шаблоном регулярного выражения. В нашем случае совпадение происходит на каждом символе ; или &. Наконец, каждая пара параметр=значение снова разбивается, и ее половинки используются для поиска элемента формы с соответствующим идентификатором. Затем этот элемент обновляется.