Опубликован: 10.12.2007 | Уровень: специалист | Доступ: платный
Лекция 7:

Формы и меню

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.

Таблица 7.2. Расширения стилей для XUL, соответствующие HTML-формам
Свойство или селектор Значения Описание
:-moz-drag-over (селектор) Любой элемент, над которым мышью перетаскивается объект
:-moz-selection (селектор) В версии 1.2.1 почти полная поддержка ::selection из CSS 3
-moz-key-equivalent См. черновик стандарта Эквивалент key-equivalent из черновика CSS 3
-moz-outline-radius Те же, что и для margin, но используйте пикселы Эти атрибуты похожи на атрибут margin, но они определяют скругленность углов границы или контура
-moz-outline-radius-topleft -moz-outline-radius-topright -moz-outline-radius-bottomleft -moz-outline-radius-bottomright Пикселы Скругленность конкретного угла; 0 означает отсутствие скругления
-moz-outline То же, что и для outline Почти полная поддержка outline из CSS 2
-moz-outline-color То же, что и для color Почти полная поддержка outline-color из CSS 2
-moz-outline-style То же, что и для border-style Почти полная поддержка outline-style из CSS 2
-moz-outline-width То же, что и для border-width Почти полная поддержка outline-width из CSS 2
-moz-user-focus См. черновик стандарта Эквивалент user-focus из черновика CSS 3
-moz-user-input См. черновик стандарта Эквивалент user-input из черновика CSS 3
-moz-user-modify См. черновик стандарта Эквивалент user-modify из черновика CSS 3
-moz-user-select См. черновик стандарта плюс -moz-all Эквивалент user-select из черновика CSS 3

Стили, относящиеся к контурам, до определенной степени соответствуют стилям границ (см. раздел "Альтернатива: таблицы стилей" "Верстка с 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>. Вместо них у нас будут:

  1. однострочное поле <textbox> для раздела Summary ;
  2. многострочное поле <textbox> для раздела Details ;
  3. два тега <checkbox> для раздела Options ;
  4. четыре небольших поля <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.

Диалог на основе форм

Рис. 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() разделяет оставшуюся строку на массив строк с разделением везде, где происходит совпадение с шаблоном регулярного выражения. В нашем случае совпадение происходит на каждом символе ; или &. Наконец, каждая пара параметр=значение снова разбивается, и ее половинки используются для поиска элемента формы с соответствующим идентификатором. Затем этот элемент обновляется.

Дмитрий Гуменюк
Дмитрий Гуменюк
Россия, Звенигород
Konstantin Grishko
Konstantin Grishko
Россия, Москва, Московский финансово-промышленный университет "Синергия", Москва