Хак с 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) поле становится именно того типа, который указан первым.

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

Ctools modal закрытие при клике вне модального окна

Июнь 28, 2019 г.

Привычное для пользователей поведение модального окна изначально не реализовано в ctools. Давайте добавим немного js, реализующего нужный функционал. Код универсален для модального окна создаваемого ctools, т.к. привязан к верстке окна: [crayon-69f19748639c0249827918/] ...

Читать

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

Апрель 11, 2019 г.

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

Читать

Подключаем suggestions list в диалог CKeditor - Link

Август 10, 2021 г.

Link - это штатный диалог, который используется в CKeditor для редактирования ссылок. И выглядит он как показано на картинке сверху. Он хорошо выполняет ...

Читать

Формирование одиночного чекбокса в Drupal 7 Webform

Ноябрь 23, 2025 г.

В Webform для Drupal 7 нет отдельного типа элемента, который отвечал бы за одиночный чекбокс. Если возникает задача добавить в форму знакомую всем галочку ...

Читать
 

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

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



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