Ctools modal API. Работа с модальными окнами

Последнее время появляются все больше и больше сайтов с попапами. Благодаря Эрлу Майлзу мы имеем замечательный инструмент - Ctools, представляющий мощный API для друпалера. Сегодня мы рассмотрим modal API и научимся с ним работать.

В качестве примера будем открывать форму обратной связи в модальном окне. Но прежде чем начать, я быстренько пробегусь по командам AJAX-фреймворка.

  • ajax_command_after($selector, $html, $settings = NULL) – вставляет содержимое $html после селектора $selector;
  • ajax_command_alert($text) – выводит алерт с текстом $text;
  • ajax_command_append($selector, $html, $settings = NULL) – добавляет содержимое $html в конец элемента с селектором $selector;
  • ajax_command_before($selector, $html, $settings = NULL) – вставляет содержимое $html перед селектором $selector;
  • ajax_command_changed($selector, $asterisk = '') – помечает селектор $selector классом ajax-changed;
  • ajax_command_css($selector, $argument) – устанавливает css свойства $argument у элемента с селектором $selector;
  • ajax_command_data($selector, $name, $value) – изменяет внутренние данные элемента с селектором $selector;
  • ajax_command_html($selector, $html, $settings = NULL) – изменяет содержимое элемента с селектором $selector на содержимое $html;
  • ajax_command_insert($selector, $html, $settings = NULL) – вставляет содержимое $html в селектор $selector;
  • ajax_command_invoke($selector, $method, array $arguments = array()) – выполняет jQuery метод $method для элемента с селектором $selector;
  • ajax_command_prepend($selector, $html, $settings = NULL) – вставляет содержимое $html в начало элемента с селектором $selector;
  • ajax_command_remove($selector) – удаляет элемент с селектором $selector;
  • ajax_command_replace($selector, $html, $settings = NULL) – заменяет элемент с селектором $selector на содержимое $html;
  • ajax_command_restripe($selector) – обновляет классы odd/event у строк таблицы с селектором $selector;
  • ajax_command_settings($argument, $merge = FALSE) – передаёт данные в глобальный массив настроек Друпала Drupal.settings.

Это команды, которые предоставляет ядро Друпала. Модуль Ctools предоставляет дополнительные ajax команды. Для их использования необходимо вызвать функцию ctools_include('ajax'). Список этих команд:

  • ctools_ajax_command_attr($selector, $name, $value) – меняет атрибут $name на значение $value у элемента с селектором $selector;
  • ctools_ajax_command_redirect($url, $delay = 0, $options = array()) – отправляет клиента по адресу $url с задержкой $delay;
  • ctools_ajax_command_reload() – перезагружает текущую страницу;
  • ctools_ajax_command_submit($selector) – отправляет форму с селектором $selector.

Для работы с модальными окнами нам потребуются дополнительные ajax команды, которые также предоставляет модуль Ctools. Для их использования необходимо вызвать функцию ctools_include('modal'). Список этих команд:

  • ctools_modal_command_dismiss() – закрывает модальное окно;
  • ctools_modal_command_display($title, $html) – открывает модальное окно с заголовком $title и содержимым $html;
  • ctools_modal_command_loading() – показывает экран загрузки в модальном окне;
  • ctools_modal_form_wrapper($form_id, $form_state) – выводит форму $form_id в попапе.

Переходим к написанию модуля.

Шаг 1. Для начала нам нужно объявить страницу в hook_menu, к которой будет обращаться ajax:

/**
 *  Implementation of hook_menu()
 */
function example_menu() {
  $items = array();

  $items['example/%ctools_js/contact'] = array(
    'title' => 'Contact',
    'page callback' => 'example_contact_page_callback',
    'page arguments' => array(1),
    'access arguments' => array('access site-wide contact form'),
    'delivery callback' => 'ajax_deliver',
    'theme callback' => 'ajax_base_page_theme',
  );

  return $items;
}

Шаг 2. Далее нам нужно в page callback написать открытие модального окна:

/**
 * @param null $js
 * @return array
 */
function example_contact_page_callback($js = NULL) {
  
  // Если у пользователя выключен JavaScript в браузере, то отправляют его на обычную форму обратной связи.
  if (!$js) {
    drupal_goto('contact');
  }
  
  // Подключаем библиотеку для работы с модальным окном с помощью ajax команд.
  ctools_include('modal');

  $form_state = array(
    'title' => t('Contact'), // Используется для заголовка модального окна.
    'ajax' => TRUE,
    'build_info' => array(
      'args' => array(),
    ),
  );
  
  // Подключаем файл, в котором описана функция формирующая форму.
  form_load_include($form_state, 'inc', 'contact', 'contact.pages'); 

  $commands = array();

  // Формируем форму в модальном окне.
  $commands = ctools_modal_form_wrapper('contact_site_form', $form_state);
  
  // Если форма была успешно отправлена, то выводим сообщение об этом и закрываем модальное окно.
  if (!empty($form_state['executed'])) {
    $commands = array();
     
    // Выводим сообщение об успешной отправке формы.
    $commands[] = ajax_command_html('#messages-wrapper', theme('status_messages'));

    // Закрываем модальное окно.
    $commands[] = ctools_modal_command_dismiss();
  }

  return array('#type' => 'ajax', '#commands' => $commands);
}

Шаг 3. Необходимо создать блок, в котором будет выводится ссылка, по клику на которую будет открываться модальное окно:

/**
 * Implements hook_block_info().
 */
function example_block_info() {
  $blocks['example_contact'] = array(
    'info' => t('Contact modal link'),
    'cache' => DRUPAL_NO_CACHE,
  );

  return $blocks;
}

/**
 * Implements hook_block_view().
 */
function example_block_view($delta = '') {
  $block = array();

  if ($delta == 'example_contact') {
    
    // В этой функции подключаются необходимые библиотеки, js и css файлы (если нужны), а так же устанавливаются 
    // настройки для модального окна. Эту функцию мы опишем позже
    _example_include_modal();

    $block['content'] = ctools_modal_text_button(t('Contact'), 'example/nojs/contact', t('Contact'), 'ctools-modal-example-contact-style');
  }

  return $block;
}

Шаг 4. Необходимо написать подключение всех нужных библиотек, js и css файлов (если нужны), а также установить настройки для модального окна в функции "_example_include_modal":

function _example_include_modal() {

  static $added = FALSE;
  if ($added == FALSE) {
    $added = TRUE;

    // Include the CTools tools that we need.
    ctools_include('modal');
    ctools_include('ajax');
    ctools_modal_add_js();
    
    // Создаем массив с настройками для модального окна.
    $example_style = array(
      'example-contact-style' => array(
        'modalSize' => array(
          'type' => 'fixed', // Тип модального окна. фиксированный или резиновый.
          'width' => 420, // Ширина модального окна.
          'height' => 'auto', // Высота модального окна.
        ),
        'modalOptions' => array(
          'opacity' => (float) 0.3, // Прозрачность фона.
          'background-color' => '#000000', // Цвет фона.
        ),
        'closeText' => '', // Текст для закрытия модального окна.
        'loadingText' => '', // Текст, отображаемый в момент загрузки модального окна.
        'animation' => 'fadeIn', // Эффект появления модального окна.
        'animationSpeed' => 'fast', // Скорость анимации.
      ),
    );

    // Подключаем настройки для модального окна.
    drupal_add_js($example_style, 'setting');
  }
}

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

P.S. Не забываем добавить нашему модулю зависимость от модулей Ctools и Contact.

Benya