Хак с Form API в Drupal 7: создаём HTML5‑поля (number, email, tel) без лишних модулей

Drupal 7 предлагает мощный Form API для построения форм. Однако при работе с HTML5‑атрибутами можно столкнуться с неожиданным ограничением: если вы попытаетесь задать тип поля numberemail или tel стандартным способом, Drupal проигнорирует ваше значение и оставит тип text (или тот, который определён через #type).

Рассмотрим ситуацию: нам нужно поле для ввода числа с шагом 10 и ограничениями от 0 до 100. Логично использовать HTML5‑тип number:

Но на выходе мы получим <input type="text" ...>. Почему? Потому что Drupal при рендеринге элемента проставляет тип, основываясь на #type (в данном случае textfield), и атрибут type из #attributes перезаписывается внутренним значением.

Опытные разработчики Drupal 7 знают небольшой хак: если добавить пробел в начало ключа атрибута, Drupal не сможет его сопоставить со своим внутренним списком и просто склеит все атрибуты в итоговом теге. В результате в HTML появятся два атрибута type.

После рендеринга получится примерно такой HTML:

Когда мы добавляем в #attributes элемент с ключом ' type' (с пробелом), Drupal воспринимает его как обычный атрибут, но из-за пробела в имени ключа внутренний механизм Form API не распознаёт его как атрибут type, подлежащий перезаписи. Однако при финальном рендеринге функция drupal_attributes() обрабатывает массив атрибутов и обрезает пробелы в именах ключей. В результате в итоговой разметке атрибут появляется уже без пробела, как обычный type="number".

Как это работает?

Можно заметить интересную деталь: в реальном HTML-коде, который генерирует Drupal, наш атрибут type="number" появляется до стандартного type="text", а не после, как можно было бы ожидать. При этом поле всё равно работает как числовое. Давайте разберёмся почему так происходит, и почему хак не перестаёт работать из-за повторяющихся атрибутов.

Формально это невалидный HTML — атрибут не должен повторяться. Однако браузеры при разборе HTML достаточно либеральны и, как правило, применяют первое встретившееся значение атрибута, игнорируя последующие. В нашем случае браузер видит сначала type="number" и создаёт числовое поле, а второй type="text" просто не оказывает влияния. Именно поэтому хак работает, даже если стандартный type идёт после.

Конечно, поведение браузеров в такой ситуации чётко не специфицировано, и разные версии или браузеры могут теоретически обрабатывать это иначе. Но многолетняя практика использования этого приёма в Drupal 7 показывает, что во всех современных браузерах (Chrome, Firefox, Safari, Edge) поле становится именно того типа, который указан первым.

Мало букафф? Читайте есчо !

Вывод меню с фиксированной глубиной в Drupal

Март 25, 2019 г.

Блок меню core модуля menu позволяет вывести всю иерархию меню полностью, но иногда требуется показать только 1-2 верхних уровня. Посмотрим как организовать такой вывод. Drupal в модуле menu использует функцию menu_tree('ИМЯ МЕНЮ'), чтобы рендерить ...

Читать

Примеры работы с EntityFieldQuery

Декабрь 7, 2017 г.

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

Читать

Удаление nodequeue программно

Май 28, 2021 г.

Небольшой сниппет (snippet) по удалению сущностей nodequeue из кода. Может быть полезно при миграции данных. Удобно оперировать с машинным именем нод-кью, но функция удаления требует ID, потому код обычно обретает следующие формы: [crayon-6a0c28304cf9a226356271/] ...

Читать

Вывод строки запроса построенного в db_select

Апрель 11, 2019 г.

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

Читать
 

Комментарии к «Хак с Form API в Drupal 7: создаём HTML5‑поля (number, email, tel) без лишних модулей»

Понравилась статья? Есть вопросы? - пишите в комментариях.



Комментарий: