Enhanced Wysiwyg Tools For The Point-and-Click Editor

Through recent work, a requirement came across to allow editors, with no strong HTML experience, to be able to create advanced HTML elements inside of the body content. Instead of risking mistakes from bad HTML being created by editors, we decided that being able to create these elements through the Wysiwyg editor in a "point-and-click" fashion would be the best method to give the editors a little freedom, and prevent headaches for the developers.

From that, the Wysiwyg Tools Plus module was born.

Geoff Maxey
#Development | Posted

Through recent work, a requirement came across to allow editors, with no strong HTML experience, to be able to create advanced HTML elements inside of the body content. Instead of risking mistakes from bad HTML being created by editors, we decided that being able to create these elements through the Wysiwyg editor in a "point-and-click" fashion would be the best method to give the editors a little freedom, and prevent headaches for the developers.

From that, the Wysiwyg Tools Plus module was born.

And this is what it can do… so far: http://www.youtube.com/watch?v=ttjaoBhsycU

The functionality for the tabs and accordions within the module work along three facets. The first being hooked into the main Wysiwyg module. The next being, the functionality within the editor application to create the elements. The last persists in the final rendering of the content on the display side.

To start, the module must interact with the main Wysiwyg module and make itself aware of the new plug-ins. This is done using the hook_wysiwyg_include_directory hook function. In this function, the directory within this module directory is returned. The main Wysiwyg will now include the "plugins" directory as the base where it will detect our key plug-in includes and other files.

1
2
3
4
5
6
7
8
9
/*
* implements hook_wysiwyg_include_directory()
*/
function wysiwyg_tools_plus_wysiwyg_include_directory($type) {
  switch($type) {
    case 'plugins':
      return "plugins";
  }
}

Wysiwyg will automatically search for files with the *.inc extension within the given directory. Each file, Wysiwyg interprets as a definition for plug-ins or even groups of plug-ins. Using a hook_plugin function within the include file an associative array is built out detailing each plug-in and its’ corresponding javascript and CSS files, as well as, any icons for the buttons themselves.

A quick example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * Implementation of hook_plugin
 */
function wysiwyg_tools_plus_tabber_plugin() {
  return array(
    'tabber' => array(
      'path' => drupal_get_path('module', 'wysiwyg_tools_plus') . '/plugins',
      'js file' => 'tabber.js',
      'js path' => drupal_get_path('module', 'wysiwyg_tools_plus') . '/plugins',
      'css path' => drupal_get_path('module', 'wysiwyg_tools_plus') . '/plugins',
      'css file' => 'tabber.css',
      'icon title' => 'Tab',
      'icon path' => drupal_get_path('module', 'wysiwyg_tools_plus') . '/plugins/icons',
      'icon file' => 'tab.png',
      'buttons' => array('tabber' => t('Tabs')),
      'load' => <span class="caps">TRUE</span>,
      'internal' => <span class="caps">FALSE</span>,
      'settings' => array(),                                   
   ),
...

With the module registered with the main Wysiwyg module, in a sense, and the plug-ins enabled and ready to use, the actions must be built for when a user actually clicks on the plug-in.

For the tabbed and accordion content, the basic concept was to allow the user to enter text, highlight the text, click a button, and have a new element created. So, for each of the four available actions, the content would be wrapped in specific tags with a class indicating what it is.

To perform the wraps, a new method is created, that when invoked, would take the content (user’s highlighted text), wrap it, and return it.

Example:

1
2
3
4
5
6
7
(function ($) {
        Drupal.wysiwyg.plugins.tabber = {
          invoke: function(data,settings,instanceId) {
                        Drupal.wysiwyg.instances[instanceId].insert('<div class="tabber">&nbsp;' + data.content + '</div>');
                },
        }
}(jQuery));

The last element needed, is the final content rendering. To add the rendering jQuery to the content on the display side, hook_preprocess_node() is used. There, the rendering jQuery and CSS are added to the page.
Example:

1
2
3
4
5
6
7
/**
 * implements hook_preprocess_node()
 */
function wysiwyg_tools_plus_preprocess_node(&$vars) {
        drupal_add_js(drupal_get_path('module', 'wysiwyg_tools_plus') . '/js/tab_builder.js');
        drupal_add_css(drupal_get_path('module', 'wysiwyg_tools_plus') . '/css/wysiwyg_tools_plus.css');
}

Though many developers would consider the Wysiwyg to be “cheating” when it comes to entering content into a site, it still stands that many of the editors that are actually entering the content are not as web savvy as would be preferred (or as savvy as they think they are). With the extensibility available in Wysiwyg, tools can be built to allow the “armchair developer,” and his mouse, the power to create cool enhanced content without the headaches from bad code and markup.

Geoff Maxey