Категория:
Опубликовано:

Делаем AJAX-кнопку с HTML-значением

Drupal HTML AJAX Button

Form API у Drupal - прекрасен. Любая форма собирается "на УРА".

Но, все же есть недостатки...

По умолчанию, для всех кнопок, Drupal использует HTML-элемент input, а он, не поддерживает вставку HTML-содержимого в значение. Это очень удобная фича для создания красочных кнопок, например с иконками. Ею можно пользоваться с помощью HTML-элемента button.

Есть несколько финтов ушами (о них тоже расскажу) с помощью которых можно соорудить кнопку (button) из FAPI. Но они исключают важную, на мой взгляд, особенность - они не работают с AJAX'ом.

Далее приведу рецепт победы над этим недугом.

Простая кнопка

Сначала, как обещал, простой вариант вывода кнопки:

$form['my_button'] = array(
  '#prefix' => '<button type="submit">',
  '#suffix' => '</button>',
  '#markup' => '<i class="my-icon-class"></i>',
);

Как видите - все просто. Добавляем элемент с разметкой, назначаем ему суффикс и префикс, и мостим туда всю нужную разметку.

Такой-себе костылик...

Кнопка с AJAX-обработчиком

Теперь рассмотрим как сделать "правильную" кнопку, в которой все будет работать.

Конечно же, мы будем переопределять.

Переопределять мы будем темизацию кнопок. По умолчанию, определена в файле form.inc, находящегося в папке includes. Вот содержание функции:

/**
 * Returns HTML for a button form element.
 *
 * @param $variables
 *   An associative array containing:
 *   - element: An associative array containing the properties of the element.
 *     Properties used: #attributes, #button_type, #name, #value.
 *
 * @ingroup themeable
 */
function theme_button($variables) {
  $element = $variables['element'];
  $element['#attributes']['type'] = 'submit';
  element_set_attributes($element, array('id', 'name', 'value'));

  $element['#attributes']['class'][] = 'form-' . $element['#button_type'];
  if (!empty($element['#attributes']['disabled'])) {
    $element['#attributes']['class'][] = 'form-button-disabled';
  }

  return '<input' . drupal_attributes($element['#attributes']) . ' />';
}

В файле template.php, нужной темы, определяем функцию в которой будем использовать новое свойство кнопок - #htmlbutton. Вот код:

/**
 * Returns HTML for a button form element.
 *
 * @param $variables
 *   An associative array containing:
 *   - element: An associative array containing the properties of the element.
 *     Properties used: #attributes, #button_type, #name, #value, #htmlbutton.
 */
function THEME_NAME_button($variables) {

  $element = $variables['element'];
  $element['#attributes']['type'] = 'submit';
  element_set_attributes($element, array('id', 'name', 'value'));  

  $element['#attributes']['class'][] = 'form-' . $element['#button_type'];
  if (!empty($element['#attributes']['disabled'])) {
    $element['#attributes']['class'][] = 'form-button-disabled';
  }
  
  // Добавим дополнительную проверку нового свойства
  // и в зависимости от его наличия будем выводить нужный тип кнопки
  if (isset($element['#htmlbutton']) && $element['#htmlbutton']) {
    $value = $element['#value'];
    unset($element['#attributes']['value']);
    return '<button' . drupal_attributes($element['#attributes']) . '>' . $value . '</button>';
  }
  else {
    return '<input' . drupal_attributes($element['#attributes']) . ' />';
  }
}

Не забываем заменить "THEME_NAME" на имя темы, и сбросить кеш.

Теперь, для вывода кнопки с HTML нужно добавить свойство #htmlbutton, и все это может работать с AJAX'ом:

$form['my_button'] = array(
  '#type'       => 'button',
  '#htmlbutton' => TRUE, // Наше новое свойство
  '#value'      => '<i class="my-icon-class"></i>',
  '#ajax'       => array(
    'callback' => 'my_ajax_callback',
  ),
);

Все остальные кнопки будут выводится как положено - INPUT'ами.

Переопределяем все кнопки

Если нужно переопределить абсолютно все кнопки на сайте, можно сделать следующим способом:

function MY_THEME_button($variables) {

  $element = $variables['element'];
  $label   = $element['#value'];
  element_set_attributes($element, array('id', 'name', 'value', 'type'));

  $element['#attributes']['class'][] = 'form-' . $element['#button_type'];
  if (!empty($element['#attributes']['disabled'])) {
    $element['#attributes']['class'][] = 'form-button-disabled';
  }

  return '<button' . drupal_attributes($element['#attributes']) . '>'. $label .'</button>';
}

И не нужно будет менять или добавлять новые свойства кнопкам.

Примерно таким же образом переопределяются кнопки в Bootstrap-темах.

Если у Вас возникли вопросы, замечания, предложения или просто благодарность - пишите в комментариях.
Делитесь полезными материалами в социальных сетях.

Комментарии

Отличная статья, очень выручила. Я уже думал бросить эту затею с программированием кнопки. Делал так но ajax тогда переставал работать))
function shop_form_alter(&$form, &$form_state, $form_id) { 
  if (strpos($form_id, 'commerce_cart_add_to_cart_form') !== FALSE) {
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Buy'),
      '#class' => 'btn-buy',
    );
  }
Рад что пригодилось )