Draw form

Материал из Eludia
Перейти к: навигация, поиск
Она может взрывать горы. Она может летать. Она поднимает тяжести. Она дробит руду. Она заменяет кухонную плиту, детскую коляску, дальнобойное орудие...

Ю. Олеша, «Зависть».

Содержание

Процедура draw_form генерирует HTML-код, соответствующий форме ввода. Как правило, каждая процедура draw_item_of_$_REQUEST{type} содержит единственный вызов draw_form, хотя это вовсе не обязательно.

Форма состоит из:

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

В подавляющем большинстве случаев каждая форма рассчитана на 2 режима показа: просмотра и редактирования:

  • в режиме просмотра ($_REQUEST{__read_only}) все поля показываются в виде текста, однако доступны разнообразные дополнительные кнопки действий (например, "Удалить", "Восстановить", "Опубликовать" и т. п.), а также прочая навигация;
  • в режиме редактирования (!$_REQUEST{__read_only}) поля допускают ввод данных, однако из всей навигации доступны только кнопки "применить" и "отмена".

Описания полей ввода

Все поля одной формы выравниваются при помощи общей таблицы.

Каждое описание поля — это ссылка на хэш с опциями. Некоторые опции могут быть заданы только непосредственно в вызове draw_form, часть может определяться по умолчанию на основании схемы данных. При этом описание поля ищется по значению name в разделе {columns} описания таблицы, имя которой равно $_REQUEST {__the_table}. Данный параметр автоматически устанавливается процедурой sql_select_hash при первом использовании в рамках текущего HTTP-запроса. В подавляющем большинстве случаев процедура извлечения данных для экрана-формы начинается как раз с вызова sql_select_hash или равносильного ему вызова sql, где нужная таблица упоминается первой в JOIN-выражении.

Из каждого такого описания (кроме типа banner) при автоматической вёрстке формы генерируется 2 клетки: для наименования и для самого поля.

Отдельные поля верстаются в столбец, массивы полей — в строку, при этом количество столбцов базовой таблицы определяется наибольшей длиной массива описаний. Для строк с меньшим количеством клеток выравнивание производится за счёт увеличения colspan последней из них.

Списки полей, упомянутых в описаниях типа hgroup, верстаются в одну клетку вместе со своими наименованиями и не влияют на количество столбцов базовой таблицы.

Поля типа banner всегда занимают одну полную строку с единственной клеткой (имеющей, соответственно, максимальный возможный colspan).

Опции, общие для всех типов полей

За редким исключением, каждому описанию поля соответствует один HTML-элемент INPUT. Его атрибут name — это значение опции name с приписанным префиксом '_'. Значение для поля ввода обычно не задаётся напрямую, а берётся по умолчанию из переменной, передаваемой в качестве 3-го аргумента draw_form (обычно она называется $data).

Таким образом, при пустом value для поля с именем 'label' будет выбрано значение $data -> {label} и сгенерирован <input name="_label" ... >.

{
  label     => ..., # отображаемый заголовок поля (по умолчанию — REMARKS из описания поля),
# value     => ..., # значение для текущего поля (используется редко),
  name      => ..., # имя передаваемого параметра и одновременно имя компоненты $data,
  off       => ..., # если непусто, то поле скрыто
  read_only => ..., # если непусто, то поле отображается как static даже при !$_REQUEST {__read_only}
  ...
},

Типы полей и их специфические опции

Текстовые

Поля этой группы передают на сервер текст, введённый пользователем.

string
Form field string.gif

Однострочное поле для ввода строки. Тип поля string принимается по умолчанию, явно указывать его не обязательно.

size    => ..., # видимый размер поля
max_len => ..., # максимальная длина вводимого текста 
picture => ..., # формат числовых значений (см. Number::Format)
date
Form field date.gif

Поле для ввода даты. Введённые значения рекомендуется обрабатывать процедурой vld_date.

# format    => ..., # Формат даты/времени, например, '%d.%m.%Y' (почти не применяется).
text
Form field text.gif

Многострочное поле для ввода длинного текста.

rows    => ..., # количество строк
cols    => ..., # количество столбцов
password

Поле для пароля, аналогичное string, но с маскированным вводом.

size => ..., # размер поля

Ссылки на справочники

Поля этой группы передают на сервер id элементов справочников, выбранных пользователем.

select
Form field select.gif

Выпадающий список для выбора одного элемента из списка. Список значений должен состоять иэ ссылок на хэши с компонентами id и label.

Последняя строка может соответствовать не фиксации значения, а переходу на другой экран со специальным параметром $_REQUEST {__select}: так можно реализовать выбор с попутным дополнением справочника.

values   => $data -> {...},                   
  # список значений, как правило, формируемый add_vocabularies

empty    => '[Выберите ...]',
  # заголовок пустой строки (если пусто, пустой строки нет) 

other    => '/?type=...'                      
  # ссылка на экран редактирования справочника

# detail => ['id_voc_city', 'id_voc_street'], 
  # список имён зависимых полей
radio
Form field radio.gif

Группа радио-кнопок для выбора одного значения из списка, аналогично select.

values => $data -> {...},   # список значений

Каждая радиокнопка может сопровождаться дополнительным полем ввода, которое видно только при выборе данной кнопки. Зачастую при этом используется тип hgroup, позволяющий привязать к кнопке целую группу полей:

{
  label => 'Офицер ли это',
  name => 'is_officer',
  values => [
   {
    id => 0,
    label => 'нет',
    type => 'hgroup',
    items => [
     # поля для паспортных данных
    ],
   },
   {
    id => 1,
    label => 'да',
    type => 'hgroup',
    items => [
     # поля для номера офицерского удостоверения
    ],
   },
  ]
}
checkboxes
Form field checkboxes.gif

Группа галочек для множественного выбора из списка вариантов. Сам список имеет формат, аналогичный тому, что используется для select, однако может иметь иерархическую структуру: каждый элемент id/label может сопровождаться элементом items со ссылкой на список такой же структуры. В этом случае отображается дерево, у котрого для доступа к дочернему элементу должен быть отмечен родительский.

values => $data -> {...}, # список опций
height => ...,            # если задано, то фиксирует высоту окна с прокруткой
cols   => ...,            # количество столбцов (если список большой, а ширины хватает)

У хэша, передаваемого 2-м параметром draw_form, и традиционно называемого $data, данному полю должна соответствовать ссылка на список id. Если нужный набор id вычисляется по единственной таблице типа "многие-ко-многим", то его удобно извлечь, прмиенив опцию ids процедуры add_vocabularies.

Векторные значения

В Eludia никогда не используются множественные HTML-поля ввода с одинаковыми именами. Все checkbox'ы, логически соответствующие одному полю, имеют разные значения атрибута name. При этом к исходному имени поля как постфиксы приписываются соответствующие id. Например, checkbox для поля 'id_user', соответствующий записи с id=3, имеет атрибут name="_id_user_3", а для id=7 — name="_id_user_7".

Таким образом, если у поля checkboxes c name=user отмечены строки с id=3 и id=7, то при обработке запроса $_REQUEST {_id_user_3} и $_REQUEST {_id_user_7} будут иметь значение 1.

Для получения списка id, заданных таким образом, можно пользоваться функцией get_ids. В подавляющем большинстве случаев с этим списком нужно просто привести в соответствие содержимое связной таблицы: для этого служит процедура sql_store_ids. Которую опять-таки в стандартный ситуациях не обязательно вызывать явно: add_vocabularies заготовит параметры, а do_update_DEFAULT осуществит вызов автоматически.

Кроме того, при предварительной обработке параметров будут установлены следующие значения:

$_REQUEST {_id_user}      = [3, 7]   # можно не вызывать get_ids

$_REQUEST {'_id_user,-1'} = '3,7,-1' # для подстановки в SQL-выражение IN (...)
tree

Поле для множественного выбора, аналогичное checkboxes или radio, однако отображаемое иначе: в виде дерева, любая вершина которого может содержать или не содержать поле для галочки / радиокнопки. Поддеревья в данном случае раскрываются независимо от отмечания полей.

values	=> [
		{id => 1, label => 'Дерево групп', parent => 0}, 
		{id => 2, label => 'Группа 1', parent => 1, is_checkbox => 1}, # или is_radio => 1
		{id => 3, label => 'Группа 2', parent => 2, is_checkbox => 1}, # -- "" --

		...

		{id => n, label => 'Группа 2', parent => p, is_checkbox => 1}, # -- "" --
],
Form field tree.gif
is_checkbox / is_radio: проблема с $_REQUEST

Долгое время tree рассматривалось исключительно как аналог checkboxes. Поэтому для tree, как и для checkboxes, производится преобразование %_REQUEST на предмет векторных значений. По этой причине в настоящее время, если содержимое дерева с именем id_dep заявлено с опциями is_radio, то $_REQUEST {_id_dep} = [] вне зависимости от выбранного значения. Возможно, это будет исправлено, но для совместимости с checkboxes сейчас рекомендуется брать нужное значение из %_REQUEST_VERBATIM.

suggest

Ввод с подсказкой, сочетающий в себе select и string.

{
	name   => 'id_voc_goods',
	label  => 'Что',
	type   => 'suggest',
	size   => 60,
	values => sub {sql (voc_goods => [
		'id',
		['label LIKE ?%' => $_REQUEST {_id_voc_goods__label}],
		[LIMIT => [15]],
	])},
	href   => "/?type=voc_goods&id=$data->{id_voc_goods}",
},
Draw form field suggest.gif

Нередактируемые

П[севдоп]оля этой группы служат не для ввода, а для оформления данных.

Поле-заглушка, в действительности представляющее собой промежуточный заголовок на форме. В отличие от подавляющего большинства типов полей, занимает не 2 клетки таблицы, а 1. Не имеет привязки к данным, надпись определяется опцией label.

Draw form field banner.gif
static
Form field static.gif

Поскольку любое поле может быть отображено как static (при $_REQUEST {__read_only} или локальном read_only), следующие опции имеют смысл для всех полей.

 href       => ..., # гиперссылка с теущего поля
 add_hidden => ..., # непустое значение обеспечивает генерацию hidden-поля с текущим значением

А эта опция имеет смысл только для тех static, что получаются из checkboxes в режиме read_only:

 separator  => ..., # по умолчанию '< br >', но можно поставить, скажем, ", "

Часто приходится показывать на форме статическое поле, значение которого берётся не из текущей записи (обычно доступной как переменная $data), а родительской. В этом случае можно определить его напрямую:

 value      => $data -> {some_parent_object} -> {label};

а можно воспользоваться одной из более удобных форм, на ваш вкус:

 name       => 'some_parent_object.label';   # для тех, кто скучает по java
 name       => 'some_parent_object / label'; # для фанатов XPath

(подходит любой разделитель из символов, не могущих быть частью C-идентификатора)

article

Горизонтальная врезка в тело формы, аналогичная banner, однако представляющая собой не однострочный заголовок, а текст из (как правило) нескольких абзацев.

Ещё отличия от banner: связь с данными по полю name, такая же, как для всех текстовых полей, а опция label в данном случае не имеет смысла.

Draw form field article.gif

Прочие

hgroup
Form field hgroup.gif

Группа полей, отображаемых в одной ячейке последовательно по горизонтали. Если задана опция read_only, то она тиражируется на все элементы.

items   => [...], # ссылка на список описаний элементов

Каждому подполю предшествует его наименоdание (label) с двоеточием на конце. Иногда бывает нужно подавить вывод этого двоеточия, для этого служит опция no_colon:

{

 label => 'Время',
 type  => 'hgroup',

 items => [

  {
   name => 'hours',
   size => 2,
  },

  {
   label => 'ч.',
   no_colon => 1,
   name => 'minutes',
   size => 2,
  },

  {
   label => 'мин.',
   no_colon => 1,
  },

 ],
},
checkbox

Поле для галочки. Отмеченное, передаёт значение 1, неотмеченное — 0.

checked => ..., # если истина, то отмечен вне зависимости от value
file
Form field file.gif

Поле выбора файла для загрузки. Для полей этого типа автоматически приписывается опция href, позволяющая воспользоваться процедурой do_download_$_REQUEST{type}. Если таковая не определена, то вызывается do_download_DEFAULT. Чтобы она корректно работала, достаточно просто следовать шаблонам, заложенным в StEludio.

size  => ..., # размер поля
files
Form field files.gif

Расширяемая группа файловых полей. Данные о файлах, указываемых в этих полях, сохраняются не в той таблице, где хранятся скалярные атрибуты формы, а в другой, относящейся к ней как много-к-1. Например, если требуется хранить множество файлов для документа (таблица docs), то имеет смысл завести таблицу doc_files со ссылкой id_doc и стандартными файловыми столбцами (file_name, file_size, file_type, file_path и, возможно, file_body). Эту дополнительную таблицу и её поле-ссылку необходимо указать в опции field. Для записи файлов в БД служит процедура sql_upload_files. Данная процедура с параметром {name => 'file'} вызывается в do_update_DEFAULT, так что для единственной группы с именем file код обработчика разрабатывать не требуется.

В режиме просмотра поле содержит имена загруженных файлов со ссылками, активизирующими действие download для типа, совпадающего по имени с таблицей. Данные извлекаются автоматически.

Если требуется обработка множественных файлов, для которой описанный способ хранения данных не подходит, можно воспользоваться процедурой upload_files.

size  => ...,               # размер поля (одинаковый для всех)
field => 'dos_files.id_doc' # таблица и её поле, ссылающееся на текущий $_REQUEST {id}
color
Form field color.gif

Поле для выбора цвета. Значения представляются в обычном HTML-формате #RRGGBB. Специфических опций не имеет.

Описания кнопок-действий

Centered toolbar button.gif

У draw_form есть 3 аналогичных опции: left_buttons, additional_buttons и right_buttons, являющиеся списками описаний кнопок, расположенных, соответственно: левее OK, между OK и Cancel и, наконец, правее Cancel на стандартной панели. Типичное описание кнопки имеет вид:

{
 icon    => '...',             # имя GIF-файла иконки
 label   => '...',             # надпись
 href    => {action => '...'}, # гиперссылка
 target  => 'invisible',       # целевое окно/фрейм
 hotkey  => {code => F..},     # горячая клавиша
 confirm => "Вы уверены, что..?",
 off     =>                    # условие отключения
  !$_REQUEST {__read_only}
  || ...
  , 
 keep_esc => 1                 # только для перехода на экран с возвратом!
},

Если href не содержит параметра action (то есть соответствующий запрос не предполагает действия, хотя бы псевдодействия print), то опции confirm и target, очевидно, не имеют смысла. Зато именно в этом случае (как правило, это переход на экран, с которого в дальнейшем потребуется вернуться), стоит поставить опцию keep_esc для корректного функционирования Esc.

В список right_buttons часто включается результат функции del, которая генерирует описание кнопки "удалить" или "восстановить" в зависимости от состояния текущей записи.

Закладки (меню)

Form menu.gif

Набор закладок предназначен для навигации по родственным формам, которые представляют один и тот же объект с разных точек зрения (например: скалярные реквизиты договора; его список актов и его же список платежей). Соответственно, такой набор описаний должен дублироваться минимум на 2 экранах. По этой причине его обычно выносят в функцию с именем __$_REQUEST{type}_menu, описанную в файле Content/menu.pm:

sub __contrat_menu {

 return [
  {
   type   => 'contrat',
   label  => 'Основные реквизиты (F2)',
   hotkey => {code => F2},
  },
  {
   type   => 'contrat_acts',
   label  => 'Акты (F6)',
   hotkey => {code => F6},
  },
  {
   type   => 'contrat_pays',
   label  => 'Платежи (F7)',
   hotkey => {code => F7},
  },
 ]
 
}

Далее эта функция используется в опции menu при вызове draw_form:

...
menu => __contrat_menu ();
...

Для каждого описания автоматически генерируется href, сохраняющий все параметры запроса, кроме type, и обеспечивающий корректную в смысле esc навигацию (перемещеие по закладкам не считаются заходами на новые экраны).

Обычно переключение type при сохранении id — это всё, что требуется, однако в некоторых случаях приходится прописывать ссылки напрямую. Это вполне возможно, только следует позаботиться о том, чтобы на соответствующем экране текущая ссылка оказалась подсвеченной:

 ...
  {
   href      => {type => 'contrat_report', template => 1},
   label     => 'Отчёт №1 (F6)',
   hotkey    => {code => F6},
   is_active => $_REQUEST {type} eq 'contrat_report' && $_REQUEST {template} == 1
  },
  {
   href      => {type => 'contrat_report', template => 2},
   label     => 'Отчёт №2 (F7)',
   hotkey    => {code => F7},
   is_active => $_REQUEST {type} eq 'contrat_report' && $_REQUEST {template} == 2
  },
 ...

Прочие опции

Общие

off 
если истина, то форма не отображается;

Управление стандартными кнопками

no_edit 
если истина, то кнопка "редактировать" не отображается (часто вычисляется в зависимости от полномочий текущего пользователя);
no_ok 
если истина, то кнопки "OK" и "редактировать" не отображаются.
no_cancel 
если истина, то кнопка "вернуться" не отображается.
esc 
ссылка с кнопки "вернуться" (рекомендуется не задавать явно за исключением особо нестандартных случаев)
bottom_toolbar 
HTML панели с кнопками в целом. Основной сценарий использования: значение ' ' для подавленя вывода панели.
label_ok 
нестандартная надпись на кнопке ОК ("применить")
label_cancel 
нестандартная надпись на кнопке Cancel ("отмена")
left_buttons 
список кнопок, добавляемых левее "редактировать"
additional_buttons 
список кнопок, добавляемых между "редактировать" и "вернуться"
right_buttons 
список кнопок, добавляемых правее "вернуться"

Управление параметрами формы

name 
имя HTML-формы (form/@name), по умолчанию 'form'.
action 
действие, по умолчанию 'update'.
target 
целевое окно, по умолчанию 'invisible'.
keep_params 
список имён параметров, значения которых будут переданы через hidden-поля. По умолчанию передаются только type и id.
Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
Разработчику
Администратору
Инструменты