Wysiwyg button with form #3

Welcome to the second article in my tutorial about building a wysiwyg button for drupal 7 which enables use to inserting tokens.

This will be a four step tutorial

  1. Step one will be building the module and a simple wysiwyg button
  2. Step two will cover a simple wysiwyg button
  3. Step three will expand the button with a multi field form
  4. Step four will make this form dynamic with ajax callbacks for removing and adding fields

This next part will cover how to expand the javascript wysiwyg button to include a form with multiple textfields which will the generate the token for displaying our entity.

First we need a form which will allow the user to enter the id of the entity to display using the token. For this we will make a drupal form in our .module file.

function ting_token_insert_form($form, &$form_state) {
  drupal_add_library('system', 'ui.dialog');
  $form['#tree'] = TRUE;
 
  $form['objects'] = array(
    '#type' => 'fieldset',
    '#title' => t('Entities'),
    '#prefix' => '<div id="ting-token-fieldset-wrapper">',
    '#suffix' => '</div>',
  );
 
  $form['objects']['entity1'] = array(
    '#type' => 'textfield',
    '#title' => t('Entity id'),
    '#default_value' => '',
  );
  $form['objects']['entity2'] = array(
    '#type' => 'textfield',
    '#title' => t('Entity id'),
    '#default_value' => '',
  );
 
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
    '#attributes' => array(
      'class' => array('form-save-ids'),
    ),
  );

  return $form;
}

Now with the form ready we need to create a way for our javascript to retrieve it, and for this we need a menu hook and a custom content function.

/**
 * implements hook_menu
 */
function example_menu() {
  $items = array();
  $items['example/insert/nojs'] = array(
    'page callback' => 'example_get_insert_form',
    'page arguments' => array(2),
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  $items['example/insert/ajax'] = array(
    'delivery callback' => 'ajax_deliver'
  ) + $items['example/insert/nojs'];
  return $items;
}

function example_get_insert_form($ajax) {
  $is_ajax = $ajax === 'ajax';
  $form = drupal_get_form('example_insert_form', $ids);
  if ($is_ajax) {
    $form = drupal_render($form);
    die($form);
  }
  else {
    return $form;
  }
}

The menu hook is pretty strait forward, it uses drupals ajax system to handle the data return. The example_get_insert_form returns a rendered form is the parameter is ajax and a form render array if it's not. Now we are ready to rewrite our javascript.

// $Id$
(function ($) {
 
Drupal.wysiwyg.plugins['tokenInsert'] = {
 
  /**
   * Return whether the passed node belongs to this plugin (note that "node" in this context is a JQuery node, not a Drupal node).
   *
   * We identify code managed by this example plugin by giving it the HTML class
   * 'tokenInsert'.
   */
  isNode: function(node) {
    res = $(node).is('.tokenInsert');
    return ($(node).is('.tokenInsert'));
  },
 
  /**
   * Invoke is called when the toolbar button is clicked.
   */
  invoke: function(data, settings, instanceId) {
    // Typically, an icon might be added to the WYSIWYG, which HTML gets added
    // to the plain-text version.
    if (data.format == 'html') {
      var content = this._getIds(data.content);
      if(content !== '') {
        settings.ids = content
      } else {
        settings.ids = '';
      }
    }
    else {
      var content = '<!--exampleInsert-->';
    }
    if (typeof content !== 'undefined') {
      Drupal.wysiwyg.plugins.tokenInsert.insert_form(data, settings, instanceId);
    }
  },
  insert_form: function (data, settings, instanceId) {
    // Location, where to fetch the dialog.
    var aurl = Drupal.settings.basePath + 'example/insert/ajax';
    var dialogdiv = $('<div id="example-insert-dialog"></div>');
    dialogdiv.load(aurl, function(){
      var dialogClose = function () {
        try {
          dialogdiv.dialog('destroy').remove();
        } catch (e) {};
      };
      var btns = {};
      btns[Drupal.t('Cancel')] = function () {
        $(this).dialog("close");
      };
      var $this = this;
      dialogdiv.find('.form-save-ids').click(function(evt) {
        evt.preventDefault();
        var ids = [],
          $items = dialogdiv.find('#ting-token-fieldset-wrapper .form-text');
        $items.each(function() {
          ids.push($(this).val());
        });
        settings.tingIds = ids;
        var content = Drupal.wysiwyg.plugins['tokenInsert']._getPlaceholder(settings);
        Drupal.wysiwyg.instances[instanceId].insert(content);
        dialogdiv.dialog("close");
      });
      dialogdiv.dialog({
        modal: true,
        autoOpen: false,
        closeOnEscape: true,
        resizable: true,
        draggable: true,
        autoresize: true,
        namespace: 'jquery_ui_dialog_default_ns',
        dialogClass: 'jquery_ui_dialog-dialog',
        title: Drupal.t('Insert'),
        buttons: btns,
        width: '70%',
        close: dialogClose
      });
      dialogdiv.dialog("open");
      Drupal.attachBehaviors();
    });
  },
  /**
   * Replace all <!--exampleInsert--> tags with the icon.
   */
  attach: function(content, settings, instanceId) {
    content = content.replace(/<!--exampleInsert-->/g, this._getPlaceholder(settings));
    return content;
  },
 
  /**
   * Replace the icons with <!--exampleInsert--> tags in content upon detaching editor.
   */
  detach: function(content, settings, instanceId) {
    var $content = $('<div>' + content + '</div>');
    $.each($('.exampleInsert', $content), function (i, elem) {
      elem.parentNode.removeChild(elem);
    });
    return $content.html();
  },
 
  /**
   * Helper function to return a HTML placeholder.
   */
  _getPlaceholder: function (settings) {
    if(settings.ids) {
      return '[ting:teaser:' + settings.ids.join() + ']';
    }
    return '';
  },
 
  /**
   * Helper function to return ids from a placeholder.
   */
  _getIds: function (content) {
    var ids = ''
    if(content.indexOf('[ting:teaser:') === 0 && content.indexOf(']') === (content.length - 1)) {
      content = content.replace('[ting:teaser:', '');
      content = content.replace(']', '');
      ids = content.split(',');
    }
    return ids;
  }
};
 
})(jQuery);

We can now insert two entities using our new insert form, but we still want more. We want to be able to insert multiple ids using ajax to add and remove id's, so stay tuned for the next tutorial.

16 Dec 2013