CMS.Fields: создание произвольного типа поля
В CMS.Fields.Types
есть множество типов полей, но на всех не угодишь, поэтому может понадобиться создать свой тип.
Для этого необхидимо:
- Создать класс, реализующий тип поля (наследуемый от
CMS.Fields.AbstractField
) - Зарегистрировать его с помощью вызова
CMS::field_type('type_name', 'Class.Name')
- при необходимости создать шаблон
- при необходимости добавить css и js файлы
- при необходимости реализовать контейнер
Базовый класс CMS.Fields.AbstractField
Класс, реализующий тип поля, должен наследоваться от базового CMS.Fields.AbstractField
, в котором уже много чего есть.
Чаще всего переопределяются методы:
-
form_fields
для задания своих элементов формы -
assign_from_object
,assign_to_object
для присвоения данных из объекта в форму и наоборот -
action
для реализации ajax действий -
preprocess
для переопределения/добавления параметров шаблона -
preprocess_layout
для переопределения/добавления параметров обрамления, а так же для добавления css и js файлов. -
view_value
для переопределения отображения в списке таблицы -
stdunset($data)
при добавлении параметров в описание типа поля (таких как caption, tab, ...) не забудьте прописать их в этом методе (причины сложны и запутаны)
protected function stdunset($data) { $res = parent::stdunset($data); return $this->punset($res, 'text-wrap', 'flat', 'level_up', 'create_tree'); }
Если ничего не переопределять/добавлять, то получится тип input.
Пройдемся по основным методам, которые могут быть полезны.
Во всех методах $name
- имя поля, $data
- его описание, $form
- объект формы, $object
, $item
- db entity.
-
is_upload()
если возвращает true, то контроллер администрирования табличных данных будет корректно обрабатывать загрузку файлов. По умолчанию возвращает false -
view($view = null)
возвращает или устанавливает (если передан аргумент) текущий шаблон -
form_fields($form,$name,$data)
добавляет к форме необходимые поля, по умолчанию добавляется input с именем $name. Часто переопределяется. -
enable_multilang()
если возвращает true, то считается что поле поддерживает многоязычность. По умолчанию false. -
data_langs($data)
возвращает поддерживаемые языки -
assign_from_object($form,$object,$name,$data)
осуществляет запись данных в форму из редактируемого объекта. В простейшем случае: $form[$name] = $value. Часто переопределяется. -
assign_to_object($form,$object,$name,$data)
осуществляет запись данных из формы в редактируемый объект. В простейшем случае: $object[$name] = $form[$name]. Часто переопределяется. -
action($name,$data,$action,$item=false,$fields = array())
вызывается контроллером администрирования табличных данных при обращении по ссылке $controller->field_action_url($name, $action, $item, $parms = array()). Чаще всего используется для реализации ajax действий. Здесь $action - имя действия (например 'rotate'), $fields - набор описаний полей. -
action_url($name,$data,$action,$item=false,$args=false)
если необходимо по-особенному формировать ссылку для действия, то в этом методе. -
on_before_action, on_after_action
вызываются соответственно до и после срабатывания действия -
process_uploads($name,$parms,$uploads,$item,$extra)
вызывается при обработке загрузки файлов. Здесь определяется куда и как сохранять файлы. -
stdunset($data)
удаляет из описания элементы, которые не должны попасть в атрибуты тега. -
use_styles, use_scripts
сокращения для$this->view->use_styles
-
template($data=array(), $name = 'template')
возвращает путь к шаблону с именем $name. Сначала шаблон ищется в текущем каталоге (где находится модуль), затем в библиотечных шаблонах. Для указания произвольного места для шаблона можно переопределить метод dir. -
layout($layout=false,$data=array())
возвращает путь к обрамлению с именем $layout -
draw, render ($name,$data, $template = 'template', $parms = array())
отображение шаблона с именем $template и параметрами $parms -
draw_in_layout, render_in_layout ($name,$data,$layout=false, $template = 'template', $parms = array())
отображение шаблона с именем $template внутри обрамления $layout. -
create_template, create_layout
методы для создания шаблонов, отображаемых методами описанными чуть выше -
preprocess ($template, $name, $data)
$template - не имя, а экземпляр шаблона. С помощью методов update_parm и replace_parm можно менять параметры шаблона. Рекомендуется делать это в методе preprocess, дабы не засорять шаблон. -
layout_preprocess ($l, $name, $data)
аналогично preprocess, но параметры задаются для обрамления.
Шаблоны
Как уже упоминалось путь к шаблону определяется в методе template
. По умолчанию шаблон будет искаться в той же директории, где лежит файл модуля, в котором определяется тип поля.
Это сделано для удобства создания кастомных типов. Так же можно переопределить метод dir(), тогда шаблоны будут искаться в директории, которую вернет этот метод.
Т.е. в простейшем случае каталог с типом поля выглядит так:
- FieldNameModule.php
- template.phtml
Для обрамлений (layout) действуют все те же правила.
В шаблон поступает множество параметров (см. методы preprocess и layout_preprocess):
-
form
объект формы (Forms.Form) -
tagparms
массив параметров, относящихся к тегу (напирмер style) -
name
имя поля -
data
массив с описанием поля -
type_object
объект типа поля (CMS.Fields.AbstractField) -
item
объект редактируемой записи, если имеется (ORM Entity) -
item_id
идентификатор записи, если имеется. -
caption
заголовок -
rcaption
заголовок, который обычно выводится справа от элемента формы -
current_lang
текущий установленный язык -
ccont
html элемент label с заголовком
Каждый тип поля может добавлять свои параметры. Желательно не засорять шаблоны и добавлять/переопределять переменные шаблона в методах preprocess, layout_preprocess.
В простейшем случае шаблон выглядит так (а так же если не переопределять шаблон):
<?= $this->forms->input($_name,$tagparms) ?>
Множество примеров шаблонов можно найти в tao/views/fields.
css и js для своего типа поля
Как упоминалось выше, добавлять файлы к шаблону желательно в preprocess_layout
.
Для двустрочных стилей или скриптов можно пользоваться (в шаблоне):
$this->append_to('css', ".puper-filed-txt {color:red;}\n"); $this->append_to('js', "$(function() {alert('aaa')});\n")
Сложные скрипты и стили стоит помещать в отдельные файлы.
Далее о некоторых рекомендациях написания js скриптов для типов полей.
В случае multivalue поля блок js используется для инициализации.
Например в TreeSelect:
$code = "; $(function() { $('div.tree_select').filter('.name_{$name}').each( function() { TAO.fields.tree_select($(this)); } )});"; $l->append_to('js', $code);
Здесь мы находим нужный нам элемент и применяем к нему необходимые действия, которые вынесены в TAO.fields (о чем ниже).
Т.е. выполняем инициализацию одного элемента. Это используется в поле multivalue при ajax добавлении нового элемента.
Соотвественно, если вы хотите, чтобы ваше поле было совместимо с multivalue, то следуйте этим рекомендациям.
Так же, если js скрипт представляет собой некий отдельный функционал, то стоит поместить его в TAO.fields для того, чтобы его можно было применять для динамически добавляемых элементов и т.д. Примером может служить тот же TreeSelect:
TAO = TAO || {} TAO.fields = TAO.fields || {} TAO.fields.tree_select = function (select) { ... }
Может возникнуть сложность в том, что в js скрипт нужно передать какие-то параметры. Это можно решить несколькими способами.
Например, можно сформировать html элемент (например input), в котором будут присутствовать необходимые параметры. Обычно их записывают в атрибуты с именами, начинающимися с data-, например: data-field-name="$name"
. Тогда в скрипте можно легко считать необходимые параметры. Более сложные случаи можно решить с помощью вспомогательного метода шаблона add_scripts_settings
(пример из CMS.Controller.TreeTable):
Templates_HTML::add_scripts_settings(array('tree' => array( 'edit_icon' => '/files/_assets/images/edit.gif', 'delete_icon' => '/files/_assets/images/del.gif', 'fields' => $this->tree_fields() )));
Тогда в js скрипте необходимые параметры будут доступны:
alert(TAO.settings.tree.edit_icon); alert(TAO.settings.tree.fields.feld_name);
Сам объект TAO создается в tao/files/scripts/tao.js.
Самый банальный и непредпочтительный способ: помещаем весь js код в шаблон и вставляем непосредственно туда переменные из шаблона.
Получим некую путаницу всего со всем, но это будет работать как быстрый и простой способ решения проблемы.
Готовые типы полей
Готовые типы полей полезны не только для использования, но и как источник примеров для реализации своего типа поля.
Например:
- Attaches: ajax action, загрузка файлов, js, шаблоны.
- Autocomplete: ajax action, js. Используется ExtJS.
- Image: ajax actions, js, шаблоны, загрузка файлов, контейнер.
- Gallery: объединяет в себя attaches и image и добавляет свои возможности.
- TreeSelect: js, preprocess, шаблоны.
- Multivalue: переопределения всего и сразу :-). Довольно сложный пример для понимания.
- ...