Диалоговая кнопка BUEditor + стандартная drupal-форма для внутреннего линкинга

Аватар пользователя popovtv popovtv 10 мая 2011 в 1:40

Вашему вниманию предлагается статья, в которой описывается способ встраивания стандартного функционала форм Drupal в редактор BUEditor для удобного добавления ссылок на внутренние материалы сайта.

Форма после использования

Начну с дисклеймера. К сожалению, не имею возможностей разбирать весь процесс создания по косточкам, т.к. было потрачено немало времени и допущено и исправлено множество ошибок прежде, чем получился результат, достойный публикации. Тратить это время здесь смысла большого не имеет, лучше идти дальше. Вот решение - пользуйтесь, экспериментируйте, дорабатывайте, делитесь. Здесь же постараюсь описать все, что необходимо для реализации задуманного функционала. Описание дается для блоками, а не построчно.

Инструменты

  • Module API
  • Drupal form API
  • Ajax
  • JQuery
  • BUEditor

Предыстория

Основным редактором на нашем научном портале является BUEditor, т.к. есть твердая необходимость форматировать текст с использованием модуля DruTeX. Ну и просто постараться сохранить предсказуемый вид для исходных текстов (в отличие от wysiwyg-редактора) для их дальнейшего использования по-жизни. По мере наполнения появилась необходимость для кросс-линкинга между статьями, терминами словаря и другими видами материалов. Все это осложнялось отсутствием таких возможностей для BUEditor, в отличие от других редакторов, для которых есть такой модуль как Linkit. Потратив некоторое время на изучение матчасти (Drupal form API), было принято решение, что во что бы то ни стало нужно прикрутить стандартную форму Drupal к диалогам BUEditor. Ведь autocomplete уже реализован, стили сделаны, а пока форма ждет ответа, там бегает кружёк и выпадет готовая менюха - вообщем просто и красиво.

Первым делом начал искать, что было сделано. Например - http://www.drupal.ru/node/12619, но по делу там ничего не нашел. Начал экспериментировать с маленьким неофициальным модулем ajax-demo и его autocomplete-возможностями. Все быстро встало на свои места. Дальше появился вопрос - как заставить друпаловскую форму залезть в диалог редактора?

Кстати, бился с поиском до последнего, т.к. не сторонник, чтобы на сайте был такой hand-made. Но готовых решений нет и был вынужден изменить своим же принципам.

Hands on

Итак, приступаем.

Первым делом надо сделать свой модуль (назвал его callbacks), в который войдет основной функционал, а именно:

  • Описание формы
  • Описание функций обращения к базе
  • Клиентский js-функционал
  • Стили ответа

callbacks.info

; $Id$

name = callbacks module
core = "6.x"
version = "6.x-1.1"

callbacks.module


// $Id$

/**
 * Implementation of hook_init().
 */

function callbacks_init(){
    
variable_set('callbacks_link_form_var'drupal_get_form('callbacks_link_form'));
}

/**
 * Implementation of hook_menu().
 */
function callbacks_menu() {
  return array(
    
'callback/link' => array(
      
'access arguments' => array('access content'),
      
'page callback' => 'callbacks_link_func',
      
'type' => MENU_CALLBACK,
    ),
  );
}

/**
* Retrieve a pipe delimited string of autocomplete suggestions for existing users
*/
function callbacks_link_func($string) {
  
$matches = array();
  
$dst "";
  
$result db_query_range("SELECT nid, language, type, title FROM {node} n WHERE LOWER(n.title) LIKE LOWER('%s%%')"$string010);
  while (
$node db_fetch_object($result)) {

    

$get_alias db_query("SELECT dst FROM {url_alias} WHERE src = 'node/%s'"$node->nid );
    if( 
$alias db_fetch_object($get_alias) )
      
$dst $alias->dst;
    else
      
$dst "node/" $node->nid;

    

$matches[$node->nid] = array(
      
'type' => check_plain($node->type),
      
'title' => check_plain($node->title),
      
'alias' => check_plain($dst),
      
'lang' => check_plain($node->language),
    );
  }

  

$results = array();
  if (
count($matches)) {
    foreach( 
$matches as $key_nid => $values ) {
      
$text '';
//      $text .= '['. $key_nid .']
';
      $text .= ''$values['title'] .'
';
      
$text .= '['$values['type'] . ':' . ( $values['lang'] ? $values['lang'] : 'any' ) . ']
';
      
$text .= ''$values['alias'] .'
';
      
$text .= "
";
      
$dst $values['alias'];
      
$results[$dst] = $text;
    }
  }

  

drupal_json($results);
}

/**
 * Defines a form.
 */
function callbacks_link_form() {

  

drupal_add_js(drupal_get_path('module''callbacks') . '/js/callbacks.js');
  
drupal_add_css(drupal_get_path('module''callbacks') . '/css/callbacks.css');

  return array(
    

'link-path-ac' => array(
      
'#autocomplete_path' => 'callback/link',
      
'#title' => t('URL or Title'),
      
'#description' => t('Start type title to get its internal URL'),
      
'#type' => 'textfield',
      
'#required' => TRUE,
    ),
    
'link-text' => array(
      
'#title' => t('Link text'),
      
'#description' => t('Select text in editor or enter link text'),
      
'#type' => 'textfield',
    ),
    
'cancel' => array(
      
'#value' => t('Cancel'),
      
'#attributes' => array('class' => 'callbacks-button'),
      
'#type' => 'button',
    ),
     
'add-link' => array(
      
'#value' => t('Add link'),
      
'#attributes' => array('class' => 'callbacks-button'),
      
'#type' => 'button',
    ),
  );
}
?>