editor.module in Editor 6
Same filename and directory in other branches
Extendable WYSIWYG editor @author Tj Holowaychuk <http://www.350designs.com/> @package Editor
File
editor.moduleView source
<?php
/**
* @file
* Extendable WYSIWYG editor
* @author Tj Holowaychuk <http://www.350designs.com/>
* @package Editor
*/
// @todo: plugin event bindings
// @todo: plugin handlers not 'types', these may provide/handle additional attributes such as AJAX callbacks
// handler args? how to deal with this using editor_plugin_create().
// @todo: some plugins should be able to be enabled however not necessarily need to be a visible toolbar item
// @todo: status bar, method in JS to add/change status,
// @todo: display path in status bar
// @todo: support the textarea resizeing
// @todo: CSS sprites for core plugin images
// @todo: visibility API integration in D5
// @todo: repopulate option dialogs... automatically, no plugin code
// @todo: handling pasting of code and have paste listener plugins?
// @todo: object handles and transforming
// @todo: right click content menus?
// @todo: toggling html view (create revsion)
// @todo: settings page
// @todo: crossbrowser support
// @todo: setting to instantiate displaying textarea
// @todo: pass selection object to plugin handlers?
// @todo: disable anchor tags in preview
// @todo: show revision info in status bar
// @todo: other selection methods such as selectChildren blah blah
// @todo: listen for undo and redo keys
// @todo: dispatch more events
// @todo: _ExecPaste()
// @todo: change PIDHandler to PIDInit
// @todo: overridable or weighted paste handlers?
// @todo: select all
// @todo: only store revisions when the undo/redo plugins are enabled etc
// @todo: try catch blocks & Drupal.js implementations
/* -----------------------------------------------------------------
Hook Implementations
------------------------------------------------------------------ */
/**
* Implementation of hook_perm();
*
* @todo: implement. access should also check on callbacks as well
*/
function editor_perm() {
return array(
'administer editor',
'access editor',
);
}
/**
* Implementation of hook_menu().
*/
function editor_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/editor',
'title' => t('Text Editor'),
'description' => t('Visual text editor options and configuration.'),
'access' => user_access('administer editor'),
);
$items[] = array(
'path' => 'admin/editor/editor',
'title' => t('Editor'),
'callback' => 'editor_settings',
'access' => user_access('administer editor'),
);
}
return $items;
}
/**
* @todo: just testing take this out
*/
function editor_editor_plugin_api($op, &$plugin, $a1 = NULL, $a2 = NULL) {
switch ($op) {
case 'alter':
break;
}
}
/* -----------------------------------------------------------------
General Functionality
------------------------------------------------------------------ */
function editor_attach() {
$plugins = editor_invoke_plugins();
$profile = editor_profile_get('large');
$module_path = drupal_get_path('module', 'editor');
// Settings
$data = array(
'editor' => array(
'toolbars' => editor_display_toolbars($profile),
),
);
// Plugin settings
if (count($plugins)) {
foreach ($plugins as $plugin) {
$data['editor']['plugins'][$plugin->pid] = $plugin;
}
}
// @todo: check permissions, styles etc
drupal_add_css($module_path . '/editor.css');
drupal_add_js($module_path . '/editor.js');
drupal_add_js($module_path . '/editor.plugins.js');
drupal_add_js($data, 'setting');
}
/**
* @todo: handle different toolbars etc? or all themeing?
*/
function editor_display_toolbars($profile) {
$items = array();
$plugins = editor_profile_plugins($profile);
$plugin_count = count($plugins);
if (count($plugins)) {
foreach ($plugins as $i => $plugin) {
// Ignore processing hidden plugins
if ($plugin->type == 'hidden') {
continue;
}
// Check for spacers
if ($plugin == '|') {
// No need for spacers at the beginning or end or the toolbars
if ($i != 0 && $i != $plugin_count - 1) {
$items[] = theme('editor_spacer');
}
continue;
}
// Invoke alter op
editor_invoke_plugin_api('alter', $plugin);
$plugin_type = editor_plugin_type_get($plugin->type);
// Type must be available
if ($plugin && $plugin_type) {
// Theme must be available
$theme = 'theme_' . $plugin_type->theme;
if (function_exists($theme)) {
$args = array();
$args[] = $plugin_type->theme;
$args[] = $plugin;
if (count($plugin->theme_args)) {
// @todo: $args += array()??
foreach ($plugin->theme_args as $arg) {
$args[] = $arg;
}
}
$items[] = @call_user_func_array('theme', $args);
}
}
}
}
return theme('editor_toolbar', implode(' ', $items));
}
/**
* Return a plugin type object or FALSE.
*/
function editor_profile_get($prid) {
$profiles = editor_invoke_profiles();
if (count($profiles)) {
foreach ($profiles as $i => $profile) {
if ($profile->prid == $prid) {
return $profile;
}
}
}
return FALSE;
}
/**
* Return plugins based on a profile's placeholders.
*/
function editor_profile_plugins($profile) {
$plugins = array();
if (count($profile->profile_array)) {
foreach ($profile->profile_array as $pid) {
if ($pid != '|') {
$plugin = editor_plugin_get($pid);
if ($plugin->pid) {
$plugins[] = $plugin;
}
}
else {
$plugins[] = '|';
}
}
}
return $plugins;
}
/**
* Parase a profile string into a usable array of pid's and placeholders.
*
* @return array
*
* @todo: rename profile_string and profile_array
*/
function editor_profile_parse_string($profile_string) {
if (is_string($profile_string)) {
if ($profile_array = preg_split('/[\\s,]+/', $profile_string)) {
return $profile_array;
}
else {
return FALSE;
}
}
}
/**
* Create a profile object.
*
* @param string $prid
* A unique identifier. This may be something similar to
* 'basic', or 'full'.
*
* @param string $profile_string
* A string of pid's and placeholders used which is parsed
* later parsed into an array. The following place holders
* are available.
*
* - '|': spacer
*
* @param string $name
* A human readable string which should be wrapped in t().
*
* @param string $description
* (optional) Description wrapped in t().
*
* @returns object
*/
function editor_profile_create($prid, $name, $profile_string, $description = '') {
$profile = new stdClass();
$profile->prid = $prid;
$profile->name = $name;
$profile->profile_string = $profile_string;
$profile->description = $description;
return $profile;
}
/**
* Return a plugin type object or FALSE.
*/
function editor_plugin_type_get($ptid) {
$plugin_types = editor_invoke_plugin_types();
if (count($plugin_types)) {
foreach ($plugin_types as $i => $plugin_type) {
if ($plugin_type->ptid == $ptid) {
return $plugin_type;
}
}
}
return FALSE;
}
/**
* Return a plugin object or FALSE.
*/
function editor_plugin_get($pid) {
$plugins = editor_invoke_plugins();
if (count($plugins)) {
foreach ($plugins as $i => $plugin) {
if ($plugin->pid == $pid) {
return $plugin;
}
}
}
return FALSE;
}
/**
* Create a plugin object.
*
* @param string $pid
* A unique identifier. This may be something similar to
* 'align_left', 'image', or 'link'.
*
* @param string $name
* A human readable string which should be wrapped in t().
*
* @param string $type
* A plugin type ptid.
*
* @param string $description
* (optional) Description wrapped in t().
*
* @param string $options
* (optional) Markup which is displayed within the options panel.
*
* @param array $theme_args
* (optional) An array of arguments which will be passed to the theme function.
*
* @param array $dependencies
* (optional) An array of plugins to which this plugin is dependant of.
*
* @returns object
*/
function editor_plugin_create($pid, $name, $type, $description = '', $options = array(), $theme_args = array(), $dependencies = array()) {
$plugin = new stdClass();
$plugin->pid = $pid;
$plugin->name = $name;
$plugin->type = $type;
$plugin->description = $description;
$plugin->options = $options;
$plugin->theme_args = $theme_args;
$plugin->dependencies = $dependencies;
return $plugin;
}
/**
* Create a plugin type object.
*
* @param string $ptid
* A unique identifier. This may be something similar to
* 'button', or 'select'.
*
* @param string $name
* A human readable string which should be wrapped in t().
*
* @param string $theme
* A theme function name without the 'theme_' prefix.
*
* @param string $description
* (optional) Description wrapped in t().
*
* @returns object
*/
function editor_plugin_type_create($ptid, $name, $theme, $description = '') {
$plugin_type = new stdClass();
$plugin_type->ptid = $ptid;
$plugin_type->name = $name;
$plugin_type->theme = $theme;
$plugin_type->description = $description;
return $plugin_type;
}
/**
* Invokes hook_editor_plugin_api().
*
* This hook provides modules with access to different
* phases which fire during the plugin process allowing
* manipulation. These phases are detailed below see the
* $op parameter.
*
* @param string $op
* - 'alter': Allows altering of the plugin object before it is rendered.
* - 'response': The plugin has returned its own data which you may alter.
*
* @param object $plugin
*
* @param mixed $a1
*
* @param mixed $a2
*/
function editor_invoke_plugin_api($op, &$plugin, $a1 = NULL, $a2 = NULL) {
foreach (module_implements('editor_plugin_api') as $module) {
$function = $module . '_editor_plugin_api';
$function($op, $plugin, $a1, $a2);
}
}
/**
* Invokes hook_editor_profiles().
*
* This hook provides modules with access to provide
* their own editor profiles.
*
* @see editor_profile_create()
*
* @returns array
* Profiles
*/
function editor_invoke_profiles() {
static $profiles;
require_once 'editor.profiles.inc';
if (!isset($profiles)) {
$profiles = module_invoke_all('editor_profiles');
if (count($profiles)) {
foreach ($profiles as &$profile) {
$profile->profile_array = editor_profile_parse_string($profile->profile_string);
}
}
}
return $profiles;
}
/**
* Invokes hook_editor_plugins().
*
* The editor plugins hook allows for 'plugin types'
* which are displayed within the editor toolbar. This may
* range from buttons, select fields, etc.
*
* @see editor_plugin_create()
*
* @returns array
* Plugins
*/
function editor_invoke_plugins() {
static $plugins;
require_once 'editor.plugins.inc';
if (!isset($plugins)) {
$plugins = module_invoke_all('editor_plugins');
}
return $plugins;
}
/**
* Invokes hook_editor_plugin_types().
*
* The editor plugin types hook allows modules to provide
* 'types' of plugins such as buttons or select fields.
*
* @see editor_plugin_type_create()
*
* @returns array
* Plugins
*/
function editor_invoke_plugin_types() {
static $plugin_types;
require_once 'editor.plugins.types.inc';
if (!isset($plugin_types)) {
$plugin_types = module_invoke_all('editor_plugin_types');
}
return $plugin_types;
}
/* -----------------------------------------------------------------
Themes
------------------------------------------------------------------ */
/**
* Theme an editor toolbar.
*
* @param string $content
*
* @return string
* Markup.
*/
function theme_editor_toolbar($content) {
return '<div class="editor-toolbar">' . $content . '<div class="clear-block"></div></div>';
}
/**
* Theme a spacer.
*
* @return string
* Markup.
*/
function theme_editor_spacer() {
return '<div class="editor-spacer"></div>';
}
Functions
Name | Description |
---|---|
editor_attach | |
editor_display_toolbars | @todo: handle different toolbars etc? or all themeing? |
editor_editor_plugin_api | @todo: just testing take this out |
editor_invoke_plugins | Invokes hook_editor_plugins(). |
editor_invoke_plugin_api | Invokes hook_editor_plugin_api(). |
editor_invoke_plugin_types | Invokes hook_editor_plugin_types(). |
editor_invoke_profiles | Invokes hook_editor_profiles(). |
editor_menu | Implementation of hook_menu(). |
editor_perm | Implementation of hook_perm(); |
editor_plugin_create | Create a plugin object. |
editor_plugin_get | Return a plugin object or FALSE. |
editor_plugin_type_create | Create a plugin type object. |
editor_plugin_type_get | Return a plugin type object or FALSE. |
editor_profile_create | Create a profile object. |
editor_profile_get | Return a plugin type object or FALSE. |
editor_profile_parse_string | Parase a profile string into a usable array of pid's and placeholders. |
editor_profile_plugins | Return plugins based on a profile's placeholders. |
theme_editor_spacer | Theme a spacer. |
theme_editor_toolbar | Theme an editor toolbar. |