summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsun2008-10-14 21:45:10 (GMT)
committer sun2008-10-14 21:45:10 (GMT)
commiteb71483269e175aa58ba0ea053dc10938f35f56c (patch)
tree580466dcc7703df3c0f9ef702b37736f8e35872e
parent94b665fabf55b5bb712eb26a21c425675e0b7f1b (diff)
#321216 by sun: Replaced Wysiwyg Editor module with Wysiwyg module.6.x-0.4
-rw-r--r--CHANGELOG.txt1
-rw-r--r--editors/tinymce.inc4
-rw-r--r--wysiwyg.admin.inc (renamed from wysiwyg_editor.admin.inc)47
-rw-r--r--wysiwyg.api.php63
-rw-r--r--wysiwyg.css (renamed from wysiwyg_editor.css)2
-rw-r--r--wysiwyg.info5
-rw-r--r--wysiwyg.install103
-rw-r--r--wysiwyg.js (renamed from wysiwyg_editor.js)0
-rw-r--r--wysiwyg.module896
-rw-r--r--wysiwyg.plugins.inc (renamed from wysiwyg_editor.plugins.inc)4
-rw-r--r--wysiwyg_editor.info4
-rw-r--r--wysiwyg_editor.install78
-rw-r--r--wysiwyg_editor.module740
13 files changed, 891 insertions, 1056 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index c206b4b..a8f5342 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -10,6 +10,7 @@ Wysiwyg 6.x-x.x, xxxx-xx-xx
Wysiwyg 6.x-0.4, 2008-10-14
---------------------------
+#321216 by sun: Replaced Wysiwyg Editor module with Wysiwyg module.
#321086 by sun: Fixed (old-style) Teaser break plugin breaks TinyMCE 3.
#316507 by sun: Code clean-up; editor settings should be cloned for init, too.
#282717 by sun: Fixed FCKeditor default settings while FCKeditor maintainers get
diff --git a/editors/tinymce.inc b/editors/tinymce.inc
index b949e6c..5a5bb01 100644
--- a/editors/tinymce.inc
+++ b/editors/tinymce.inc
@@ -148,12 +148,12 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) {
// later.
$init['extensions'] = array();
// $init['extended_valid_elements'] are just stacked, unique'd later, and
- // transformed into a comma-separated string in wysiwyg_editor_add_settings().
+ // transformed into a comma-separated string in wysiwyg_add_editor_settings().
// @todo Needs a complete plugin API redesign using arrays for
// tag => attributes definitions and array_merge_recursive().
$init['extended_valid_elements'] = array();
- $plugins = wysiwyg_editor_get_plugins($editor['name']);
+ $plugins = wysiwyg_get_plugins($editor['name']);
foreach ($config['buttons'] as $plugin => $buttons) {
foreach ($buttons as $button => $enabled) {
// Iterate separately over buttons and extensions properties.
diff --git a/wysiwyg_editor.admin.inc b/wysiwyg.admin.inc
index 53cf11e..1a40d14 100644
--- a/wysiwyg_editor.admin.inc
+++ b/wysiwyg.admin.inc
@@ -1,7 +1,6 @@
<?php
// $Id$
-
/**
* @file
* Integrate Wysiwyg editors into Drupal.
@@ -12,7 +11,7 @@
*
* @todo Move into hook_menu(), resp. FAPI functions.
*/
-function wysiwyg_editor_admin($arg = '', $name = '') {
+function wysiwyg_admin($arg = '', $name = '') {
switch ($arg) {
case 'add':
$breadcrumb[] = l(t('Home'), NULL);
@@ -22,27 +21,27 @@ function wysiwyg_editor_admin($arg = '', $name = '') {
$breadcrumb[] = l(t('Wysiwyg Profiles'), 'admin/settings/wysiwyg/profile');
drupal_set_breadcrumb($breadcrumb);
$profile = new stdClass;
- return drupal_get_form('wysiwyg_editor_profile_form', $profile);
+ return drupal_get_form('wysiwyg_profile_form', $profile);
case 'edit':
drupal_set_title(t('Edit Wysiwyg Editor profile'));
- return drupal_get_form('wysiwyg_editor_profile_form', wysiwyg_editor_load_profile($name));
+ return drupal_get_form('wysiwyg_profile_form', wysiwyg_load_profile($name));
case 'delete':
- wysiwyg_editor_profile_delete($name);
+ wysiwyg_profile_delete($name);
drupal_set_message(t('Wysiwyg profile %name has been deleted.', array('%name' => $name)));
drupal_goto('admin/settings/wysiwyg/profile');
break;
default:
- return wysiwyg_editor_profile_overview();
+ return wysiwyg_profile_overview();
}
}
/**
* Return an HTML form for profile configuration.
*/
-function wysiwyg_editor_profile_form($form_state, $profile) {
+function wysiwyg_profile_form($form_state, $profile) {
// Merge in defaults.
settype($profile, 'array');
$profile += array(
@@ -172,10 +171,10 @@ function wysiwyg_editor_profile_form($form_state, $profile) {
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => TRUE,
- '#theme' => 'wysiwyg_editor_admin_button_table',
+ '#theme' => 'wysiwyg_admin_button_table',
);
- $plugins = wysiwyg_editor_get_plugins($profile->settings['editor']);
+ $plugins = wysiwyg_get_plugins($profile->settings['editor']);
// Generate the button list.
foreach ($plugins as $name => $meta) {
if (isset($meta['buttons']) && is_array($meta['buttons'])) {
@@ -354,11 +353,11 @@ function wysiwyg_editor_profile_form($form_state, $profile) {
}
/**
- * Form submit callback for wysiwyg_editor_profile_form_build().
+ * Submit callback for Wysiwyg profile form.
*
- * @see wysiwyg_editor_profile_form()
+ * @see wysiwyg_profile_form()
*/
-function wysiwyg_editor_profile_form_submit($form, &$form_state) {
+function wysiwyg_profile_form_submit($form, &$form_state) {
// Count enabled plugins for this profile.
$plugin_count = 0;
foreach ($form_state['values']['buttons'] as $plugin => $buttons) {
@@ -373,8 +372,8 @@ function wysiwyg_editor_profile_form_submit($form, &$form_state) {
// Delete existing profile(s) with the current profile name.
if (!empty($form_state['values']['old_name'])) {
- db_query("DELETE FROM {wysiwyg_editor_profile} WHERE name = '%s' OR name = '%s'", $form_state['values']['name'], $form_state['values']['old_name']);
- db_query("DELETE FROM {wysiwyg_editor_role} WHERE name = '%s' OR name = '%s'", $form_state['values']['name'], $form_state['values']['old_name']);
+ db_query("DELETE FROM {wysiwyg_profile} WHERE name = '%s' OR name = '%s'", $form_state['values']['name'], $form_state['values']['old_name']);
+ db_query("DELETE FROM {wysiwyg_role} WHERE name = '%s' OR name = '%s'", $form_state['values']['name'], $form_state['values']['old_name']);
}
// Remove FAPI values.
@@ -382,16 +381,16 @@ function wysiwyg_editor_profile_form_submit($form, &$form_state) {
unset($form_state['values']['submit'], $form_state['values']['form_id'], $form_state['values']['op'], $form_state['values']['form_token']);
// Insert new profile data.
- db_query("INSERT INTO {wysiwyg_editor_profile} (name, settings, plugin_count) VALUES ('%s', '%s', %d)", $form_state['values']['name'], serialize($form_state['values']), $plugin_count);
+ db_query("INSERT INTO {wysiwyg_profile} (name, settings, plugin_count) VALUES ('%s', '%s', %d)", $form_state['values']['name'], serialize($form_state['values']), $plugin_count);
foreach ($form_state['values']['rids'] as $rid => $value) {
- db_query("INSERT INTO {wysiwyg_editor_role} (name, rid) VALUES ('%s', %d)", $form_state['values']['name'], $rid);
+ db_query("INSERT INTO {wysiwyg_role} (name, rid) VALUES ('%s', %d)", $form_state['values']['name'], $rid);
}
if (isset($form_state['values']['old_name'])) {
- drupal_set_message(t('Wysiwyg Editor profile %name has been updated.', array('%name' => $form_state['values']['name'])));
+ drupal_set_message(t('Wysiwyg profile %name has been updated.', array('%name' => $form_state['values']['name'])));
}
else {
- drupal_set_message(t('Wysiwyg Editor profile %name has been created.', array('%name' => $form_state['values']['name'])));
+ drupal_set_message(t('Wysiwyg profile %name has been created.', array('%name' => $form_state['values']['name'])));
}
drupal_goto('admin/settings/wysiwyg/profile');
}
@@ -399,7 +398,7 @@ function wysiwyg_editor_profile_form_submit($form, &$form_state) {
/**
* Layout for the buttons in the Wysiwyg Editor profile form.
*/
-function theme_wysiwyg_editor_admin_button_table(&$form) {
+function theme_wysiwyg_admin_button_table(&$form) {
$buttons = array();
// Flatten forms array.
@@ -432,7 +431,7 @@ function theme_wysiwyg_editor_admin_button_table(&$form) {
/**
* Display overview of setup Wysiwyg Editor profiles; menu callback.
*/
-function wysiwyg_editor_profile_overview() {
+function wysiwyg_profile_overview() {
$output = '';
$usable = TRUE;
@@ -470,7 +469,7 @@ function wysiwyg_editor_profile_overview() {
return $output;
}
- $profiles = wysiwyg_editor_load_profile();
+ $profiles = wysiwyg_load_profile();
if ($profiles) {
$roles = user_roles(FALSE, 'access wysiwyg editor');
$header = array(t('Profile'), t('Editor'), t('Roles'), t('Operations'));
@@ -491,8 +490,8 @@ function wysiwyg_editor_profile_overview() {
/**
* Remove a profile from the database.
*/
-function wysiwyg_editor_profile_delete($name) {
- db_query("DELETE FROM {wysiwyg_editor_profile} WHERE name = '%s'", $name);
- db_query("DELETE FROM {wysiwyg_editor_role} WHERE name = '%s'", $name);
+function wysiwyg_profile_delete($name) {
+ db_query("DELETE FROM {wysiwyg_profile} WHERE name = '%s'", $name);
+ db_query("DELETE FROM {wysiwyg_role} WHERE name = '%s'", $name);
}
diff --git a/wysiwyg.api.php b/wysiwyg.api.php
new file mode 100644
index 0000000..e4d0251
--- /dev/null
+++ b/wysiwyg.api.php
@@ -0,0 +1,63 @@
+<?php
+// $Id$
+
+/**
+ * hook_wysiwyg_plugin(). Return an array of editor plugins.
+ *
+ * Each wysiwyg editor as well as each contrib module implementing an editor
+ * plugin has to return an associative array of available plugins. Each module
+ * can add one or more plugins and editor buttons.
+ *
+ * Notes for TinyMCE:
+ * A module is able to override almost all TinyMCE initialization settings.
+ * However, modules should only make use of that if a plugin really needs to,
+ * because customized configuration settings may clash with overrides by another
+ * module. TinyMCE automatically assigns the baseURL of your plugin to the plugin
+ * object. If you need to load or access additional files from your plugin
+ * directory, retrieve the path via this.baseURL. tinyMCE.baseURL returns the
+ * path of TinyMCE and not your module. For example:
+ * @code
+ * initInstance: function(inst) {
+ * tinyMCE.importCSS(inst.getDoc(), this.baseURL + '/myplugin.css');
+ * },
+ * @endcode
+ *
+ * @param string $editor
+ * An (lowercase) editor name to return plugins for.
+ * @return array
+ * An associative array having internal plugin names as keys, an array of
+ * plugin meta-information as values:
+ * - type: 'external' (optional); if omitted, wysiwyg editors will likely
+ * search for the plugin in their own plugins folder.
+ * - title: A human readable title of the plugin.
+ * - description: A (one-line) description of the plugin.
+ * - path: The patch to the javascript plugin.
+ * - callback: A Drupal menu callback returning the plugin UI. A plugin
+ * should return a callback *or* a path.
+ * - icon: An icon (usually 16x16 pixels) for the plugin button (optional).
+ * - ... Any other custom editor settings (optional).
+ *
+ * @todo Move this template into hooks.php.
+ */
+function hook_wysiwyg_plugin($editor) {
+ switch ($editor) {
+ case 'tinymce':
+ return array(
+ 'myplugin' => array(
+ 'type' => 'external',
+ 'title' => t('My plugin title'),
+ 'description' => t('My plugin title'),
+ // Regular callback URL for external TinyMCE plugins.
+ 'path' => drupal_get_path('module', 'mymodule') .'/myplugin',
+ // Wysiwyg wrapper plugin AJAX callback.
+ 'callback' => url('myplugin/browse'),
+ 'icon' => drupal_get_path('module', 'mymodule') .'/myplugin/myplugin.png',
+ 'extended_valid_elements' => array('tag[attribute1|attribute2=default_value]'),
+ // Might need to be set later on; after retrieving customized editor
+ // layout.
+ 'theme_advanced_buttons1' => array(t('Button title (optional)') => 'myplugin'),
+ ),
+ );
+ }
+}
+
diff --git a/wysiwyg_editor.css b/wysiwyg.css
index f50dbb4..106724a 100644
--- a/wysiwyg_editor.css
+++ b/wysiwyg.css
@@ -1,6 +1,6 @@
/* $Id$ */
-/* TinyMCE */
+/* TinyMCE 2.x */
.mceToolbarTop a, .mceToolbarBottom a { float: left; }
.mceSeparatorLine { float: left; margin-top: 3px; }
.mceSelectList { float: left; margin-bottom: 1px; }
diff --git a/wysiwyg.info b/wysiwyg.info
new file mode 100644
index 0000000..84f13c3
--- /dev/null
+++ b/wysiwyg.info
@@ -0,0 +1,5 @@
+; $Id$
+name = Wysiwyg
+description = Allows users to edit contents with client-side editors.
+package = User interface
+core = 6.x
diff --git a/wysiwyg.install b/wysiwyg.install
new file mode 100644
index 0000000..651cd4b
--- /dev/null
+++ b/wysiwyg.install
@@ -0,0 +1,103 @@
+<?php
+// $Id$
+
+/**
+ * Implementation of hook_schema().
+ */
+function wysiwyg_schema() {
+ $schema = array();
+ $schema['wysiwyg_profile'] = array(
+ 'description' => t('Stores Wysiwyg Editor profiles.'),
+ 'fields' => array(
+ 'name' => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
+ 'settings' => array('type' => 'text', 'size' => 'normal'),
+ 'plugin_count' => array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+ ),
+ 'primary key' => array('name'),
+ );
+ $schema['wysiwyg_role'] = array(
+ 'description' => t('Stores user role access permissions for Wysiwyg Editor profiles.'),
+ 'fields' => array(
+ 'name' => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
+ 'rid' => array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+ ),
+ 'primary key' => array('name', 'rid'),
+ );
+ return $schema;
+}
+
+/**
+ * Implementation of hook_install().
+ */
+function wysiwyg_install() {
+ drupal_install_schema('wysiwyg');
+ // Import data from old editor modules.
+ wysiwyg_migrate_wysiwyg_editor();
+ wysiwyg_migrate_tinymce();
+}
+
+/**
+ * Implementation of hook_uninstall()
+ */
+function wysiwyg_uninstall() {
+ drupal_uninstall_schema('wysiwyg');
+}
+
+/**
+ * Migrate from Wysiwyg Editor.
+ */
+function wysiwyg_migrate_wysiwyg_editor() {
+ if (db_table_exists('wysiwyg_editor_profile')) {
+ // Import Wysiwyg Editor profiles.
+ db_query('INSERT INTO {wysiwyg_profile} (name, settings, plugin_count) SELECT name, settings, plugin_count FROM {wysiwyg_editor_profile}');
+ // Import Wysiwyg Editor profile role associations.
+ db_query('INSERT INTO {wysiwyg_role} (name, rid) SELECT name, rid FROM {wysiwyg_editor_role}');
+
+ // Disable Wysiwyg Editor module.
+ module_disable(array('wysiwyg_editor'));
+ drupal_set_message(t('Wysiwyg Editor module can be safely uninstalled now.'));
+ }
+}
+
+/**
+ * Migrate from TinyMCE.
+ */
+function wysiwyg_migrate_tinymce() {
+ if (db_table_exists('tinymce_settings')) {
+ $schema = db_result(db_query("SELECT schema_version FROM {system} WHERE name = 'tinymce'"));
+ if ($schema >= 1) {
+ // Import TinyMCE settings.
+ db_query('INSERT INTO {wysiwyg_profile} (name, settings) SELECT name, settings FROM {tinymce_settings}');
+ // Import TinyMCE profile role associations.
+ db_query('INSERT INTO {wysiwyg_role} (name, rid) SELECT name, rid FROM {tinymce_role}');
+
+ // Migrate profile configurations.
+ // Convert buttons/plugins into an associative array and fix plugin count.
+ $profiles = db_query("SELECT name, settings, plugin_count FROM {wysiwyg_profile}");
+ while ($profile = db_fetch_array($profiles)) {
+ $settings = unserialize($profile['settings']);
+ if (isset($settings['form_id'])) {
+ $old_buttons = (isset($settings['buttons']) ? $settings['buttons'] : array());
+ $settings['buttons'] = array();
+ $plugin_count = 0;
+ foreach ($old_buttons as $old_button => $enabled) {
+ list($plugin, $button) = explode('-', $old_button, 2);
+ $settings['buttons'][$plugin][$button] = 1;
+ $plugin_count++;
+ }
+ // We can't use update_sql() here because of curly braces in serialized
+ // array.
+ db_query("UPDATE {wysiwyg_profile} SET settings = '%s', plugin_count = %d WHERE name = '%s'", serialize($settings), $plugin_count, $profile['name']);
+ }
+ }
+
+ // Disable TinyMCE module.
+ module_disable(array('tinymce'));
+ drupal_set_message(t('TinyMCE module can be safely uninstalled now.'));
+ }
+ else {
+ drupal_set_message(t('To migrate your existing TinyMCE settings to Wysiwyg Editor, please update TinyMCE module to the latest official release, and re-install Wysiwyg Editor module.'));
+ }
+ }
+}
+
diff --git a/wysiwyg_editor.js b/wysiwyg.js
index 019d357..019d357 100644
--- a/wysiwyg_editor.js
+++ b/wysiwyg.js
diff --git a/wysiwyg.module b/wysiwyg.module
index 4c5cf1c..dcf4725 100644
--- a/wysiwyg.module
+++ b/wysiwyg.module
@@ -3,289 +3,733 @@
/**
* @file
- * Implements a WYSIWYG API/framework/controller for Drupal.
- * Implements a generic WYSIWYG editor (wrapper) module for Drupal.
+ * Integrate client-side editors with Drupal.
*/
/**
+ * Implementation of hook_menu().
+ */
+function wysiwyg_menu() {
+ $items = array();
+ $items['admin/settings/wysiwyg/profile'] = array(
+ 'title' => 'Wysiwyg',
+ 'page callback' => 'wysiwyg_admin',
+ 'description' => 'Configure client-side editor profiles.',
+ 'access arguments' => array('administer site configuration'),
+ 'file' => 'wysiwyg.admin.inc',
+ );
+ return $items;
+}
+
+/**
+ * Implementation of hook_theme().
+ */
+function wysiwyg_theme() {
+ return array(
+ 'wysiwyg_admin_button_table' => array('arguments' => array('form')),
+ );
+}
+
+/**
+ * Implementation of hook_help().
+ */
+function wysiwyg_help($path, $arg) {
+ switch ($path) {
+ case 'admin/settings/wysiwyg/profile':
+ case 'admin/help#wysiwyg':
+ $output = '<p>'. t('Profiles can be defined based on user roles. A Wysiwyg Editor profile can define which pages receive this Wysiwyg Editor capability, what buttons or themes are enabled for the editor, how the editor is displayed, and a few other editor functions. Lastly, only users with the %permission <a href="!url">user permission</a> are able to use Wysiwyg Editor.', array('%permission' => 'access wysiwyg editor', '!url' => url('admin/user/permissions'))) .'</p>';
+ return $output;
+ }
+}
+
+/**
* Implementation of hook_perm().
- *
- * Considerations:
- * - Allow to access an editor.
- * - Allow to access a particular editor profile.
*/
function wysiwyg_perm() {
- // Implement common permissions.
- $permissions = array('use wysiwyg editor', 'administer wysiwyg settings');
- // Fetch editors or editor profiles.
-
- return $permissions;
+ return array('access wysiwyg editor');
}
/**
- * Implementation of hook_menu().
+ * Implementation of hook_elements().
+ *
+ * Before Drupal 7, there is no way to easily identify form fields that are
+ * input format enabled. This is a workaround: We assign a form #after_build
+ * processing callback that is executed on all forms after they have been
+ * completely built, so that form elements already are in their effective order
+ * and position.
+ *
+ * @see wysiwyg_process_form()
+ *
+ * @todo Remove #wysiwyg_style; the GUI for an editor should be solely handled
+ * via profiles, when profiles are attached to an input format. It makes no
+ * sense to display TinyMCE's simple GUI/theme for the user signature, when
+ * the input format allows users to use advanced HTML and hence, editor
+ * plugins. Fix this here, in wysiwyg_process_element(), and lastly
+ * in wysiwyg_get_editor_config().
*/
-function wysiwyg_menu($may_cache) {
- $items = array();
-
- if ($may_cache) {
- // General wysiwyg settings, including editor selection, editor/user roles
- // mapping.
-
- // Editor profile setup and custom wysiwyg controller overrides.
- // Note: Depends on resulting implementation of wysiwyg_controller()
-
- // Enable/disable default editor plugins and Drupal plugins.
-
- // Configure editor-specific layout, including layout of plugins.
-
- // Generic Drupal plugin wrapper callback (AJAX).
+function wysiwyg_elements() {
+ $type = array();
+ if (user_access('access wysiwyg editor')) {
+ // @todo Derive editor theme from input format.
+ $type['textarea'] = array('#wysiwyg_style' => 'advanced');
+ $type['form'] = array('#after_build' => array('wysiwyg_process_form'));
+ }
+ return $type;
+}
+
+/**
+ * Implementation of hook_form_alter().
+ */
+function wysiwyg_form_alter(&$form, &$form_state) {
+ // Disable 'teaser' textarea.
+ if (isset($form['body_field'])) {
+ unset($form['body_field']['teaser_js']);
+ $form['body_field']['teaser_include'] = array();
}
-
- return $items;
}
/**
- * Handle an editor profile.
+ * Process a textarea for Wysiwyg Editor.
+ *
+ * This way, we can recurse into the form and search for certain, hard-coded
+ * elements that have been added by filter_form(). If an input format selector
+ * or input format guidelines element is found, we assume that the preceding
+ * element is the corresponding textarea and use it's #id for attaching
+ * client-side editors.
*
- * This function should adopt the implementation of node objects in Drupal. It
- * should at least allow to load, save and duplicate an editor profile. Since
- * not all editors support the same settings, the array of settings probably
- * needs to be stored serialized in the database.
+ * @see wysiwyg_elements(), filter_form()
+ */
+function wysiwyg_process_form(&$form) {
+ // Iterate over element children; resetting array keys to access last index.
+ if ($children = array_values(element_children($form))) {
+ foreach ($children as $index => $item) {
+ $element = &$form[$item];
+
+ // filter_form() always uses the key 'format'. We need a type-agnostic
+ // match to prevent false positives. Also, there must have been at least
+ // one element on this level.
+ if ($item === 'format' && $index > 0) {
+ // Make sure we either match a input format selector or input format
+ // guidelines (displayed if user has access to one input format only).
+ if ((isset($element['#type']) && $element['#type'] == 'fieldset') || isset($element['format']['guidelines'])) {
+ // The element before this element is the target form field.
+ $field = &$form[$children[$index - 1]];
+
+ // Disable #resizable to avoid resizable behavior to hi-jack the UI,
+ // but load the behavior, so the 'none' editor can attach/detach it.
+ $extra_class = '';
+ if (!empty($field['#resizable'])) {
+ // Due to our CSS class parsing, we can add arbitrary parameters
+ // for each input format.
+ $extra_class = ' wysiwyg-resizable-1';
+ $field['#resizable'] = FALSE;
+ drupal_add_js('misc/textarea.js');
+ }
+
+ // Determine the available input formats. The last child element is a
+ // link to "More information about formatting options". When only one
+ // input format is displayed, we also have to remove formatting
+ // guidelines, stored in the child 'format'.
+ $formats = element_children($element);
+ array_pop($formats);
+ unset($formats['format']);
+ foreach ($formats as $format) {
+ // Default to 'none' editor (Drupal's default behaviors).
+ $editor = 'none';
+ $theme = '';
+ // Fetch the profile associated to this input format.
+ $profile = wysiwyg_get_profile($format);
+ if ($profile) {
+ $editor = $profile->settings['editor'];
+ // Check editor theme (and reset it if not/no longer available).
+ $theme = wysiwyg_get_editor_themes($profile, $field['#wysiwyg_style']);
+
+ // Add profile settings for this input format.
+ wysiwyg_add_editor_settings($profile, $theme);
+ // Add plugin settings for this input format.
+ wysiwyg_add_plugin_settings($profile);
+
+ $theme = ' wysiwyg-theme-'. $theme;
+ }
+
+ // Use a prefix/suffix for a single input format, or attach to input
+ // format selector radio buttons.
+ if (isset($element['format']['guidelines'])) {
+ $element[$format]['#prefix'] = '<div class="wysiwyg wysiwyg-editor-'. $editor .' wysiwyg-field-'. $field['#id'] . $theme . $extra_class .'">';
+ $element[$format]['#suffix'] = '</div>';
+ }
+ else {
+ if (isset($element[$format]['#attributes']['class'])) {
+ $element[$format]['#attributes']['class'] .= ' ';
+ }
+ else {
+ $element[$format]['#attributes']['class'] = '';
+ }
+ $element[$format]['#attributes']['class'] .= 'wysiwyg wysiwyg-editor-'. $editor .' wysiwyg-field-'. $field['#id'] . $theme . $extra_class;
+ }
+ }
+ }
+ // If this element is 'format', do not recurse further.
+ continue;
+ }
+ // Recurse into children.
+ wysiwyg_process_form($element);
+ }
+ }
+ return $form;
+}
+
+/**
+ * Determine the profile to use for a given input format id.
*
- * Considerations:
- * - Will Drupal editor plugins need to hook into profile operations?
- * - Discuss moving profile rules into render.module.
+ * This function also performs sanity checks for the configured editor in a
+ * profile to ensure that we do not load a malformed editor.
*
- * @param string $op
- * An operation to perform, one of 'load', 'save', 'duplicate'.
- * @param string $profile
- * An editor profile object containing at least an id, title, array of plugins
- * and an array of settings.
+ * @param $format
+ * The internal id of an input format.
*
- * @todo '_profile' is an ambigious hook in Drupal. Needs a unique name.
+ * @return
+ * A wysiwyg profile.
+ *
+ * @see wysiwyg_load_editor(), wysiwyg_get_editor()
+ *
+ * @todo Replace wysiwyg_current_profile() with a input format to profile
+ * association.
*/
-function wysiwyg_profile() {
+function wysiwyg_get_profile($format) {
+ // Determine whether this input format has PHP filter enabled.
+ // Temporary, until input format to profile associations are in place.
+ $filters = filter_list_format($format);
+ foreach ($filters as $filter) {
+ if ($filter->module == 'php') {
+ return FALSE;
+ }
+ }
+ if ($profile = wysiwyg_load_profile(wysiwyg_current_profile())) {
+ if (wysiwyg_load_editor($profile)) {
+ return $profile;
+ }
+ }
+ return FALSE;
}
/**
- * Wysiwyg editor execution controller.
- *
- * Disables an editor for certain fields that were never intended to be edited
- * with an editor.
- * @see http://drupal.org/node/81297
+ * Load an editor library and initialize basic Wysiwyg settings.
+ *
+ * @param $profile
+ * A wysiwyg editor profile.
*
- * Considerations:
- * - Take D6 FAPI3 / widgets into account (see #138706 and #86535).
- * - Run registration either in hook_elements() or hook_form_alter().
- * form_alter() might also allow to load needed JS/CSS.
- * - Use an attribute or class name or both (editor code analysis needed). Or
- * alter field #type 'textarea' to 'html' (IIRC, suggested by moshe).
- * - Disable an editor for fields using the PHP input format.
- * - D6: Perhaps depend on the input format to *enable* a field.
- * - Allow to take the current path into account.
- * - Allow to force an editor for certain CCK fields (f.e. user input).
- * - Disable core's #resizable if an editor does not support it.
- * - Allow contrib modules to extend this definition.
- * - Allow to manually extend this list via wysiwyg settings page.
- * - Include an editor profile or user role to limit/enhance available plugins.
- * - Take other input formats (e.g. bbcode) into account.
+ * @return
+ * TRUE if the editor has been loaded, FALSE if not.
*
- * @todo Rename function to appropriate/chosen Drupal hook.
+ * @see wysiwyg_get_profile()
+ */
+function wysiwyg_load_editor($profile) {
+ static $settings_added;
+ static $loaded = array();
+
+ $name = $profile->settings['editor'];
+ // Library files must be loaded only once.
+ if (!isset($loaded[$name])) {
+ // Load editor.
+ $editor = wysiwyg_get_editor($name);
+ if ($editor) {
+ // Determine library files to load.
+ // @todo Allow to configure the library/execMode to use.
+ if (isset($profile->settings['library']) && isset($editor['libraries'][$profile->settings['library']])) {
+ $library = $profile->settings['library'];
+ $files = $editor['libraries'][$profile->settings['library']]['files'];
+ }
+ else {
+ // Fallback to the first by default (external libraries can change).
+ $library = key($editor['libraries']);
+ $files = array_shift($editor['libraries']);
+ $files = $files['files'];
+ }
+ foreach ($files as $file) {
+ drupal_add_js($editor['library path'] . '/' . $file);
+ }
+ // Load JavaScript integration files for this editor.
+ if (isset($editor['js files'])) {
+ $files = $editor['js files'];
+ }
+ foreach ($files as $file) {
+ drupal_add_js($editor['js path'] . '/' . $file, 'module', 'footer');
+ }
+
+ $status = wysiwyg_user_get_status($profile);
+ drupal_add_js(array('wysiwyg' => array(
+ 'configs' => array($editor['name'] => array()),
+ 'showToggle' => $profile->settings['show_toggle'],
+ 'status' => $status,
+ // If JS compression is enabled, at least TinyMCE is unable to determine
+ // its own base path and exec mode since it can't find the script name.
+ 'editorBasePath' => base_path() . $editor['library path'],
+ 'execMode' => $library,
+ )), 'setting');
+
+ $loaded[$name] = TRUE;
+ }
+ else {
+ $loaded[$name] = FALSE;
+ }
+ }
+
+ // Add basic Wysiwyg settings if any editor has been added.
+ if (!isset($settings_added) && $loaded[$name]) {
+ drupal_add_js(array('wysiwyg' => array(
+ 'configs' => array(),
+ 'disable' => t('Disable rich-text'),
+ 'enable' => t('Enable rich-text'),
+ )), 'setting');
+
+ // Initialize our namespaces in the *header* to do not force editor
+ // integration scripts to check and define Drupal.wysiwyg on its own.
+ drupal_add_js(wysiwyg_get_path('wysiwyg.init.js'));
+
+ // The 'none' editor is a special editor implementation, allowing us to
+ // attach and detach regular Drupal behaviors just like any other editor.
+ drupal_add_js(wysiwyg_get_path('editors/js/none.js'), 'module', 'footer');
+
+ // Add wysiwyg.js to the footer to ensure it's executed after the
+ // Drupal.settings array has been rendered and populated. Also, since editor
+ // library initialization functions must be loaded first by the browser,
+ // Drupal.wysiwygInit() must be executed AFTER editors registered
+ // their callbacks, and BEFORE Drupal.behaviors are applied, this must come
+ // last.
+ drupal_add_js(wysiwyg_get_path('wysiwyg.js'), 'module', 'footer');
+
+ // Add our stylesheet to stack editor buttons into one row.
+ // @todo This is TinyMCE 2.x specific at the moment.
+ drupal_add_css(wysiwyg_get_path('wysiwyg.css'));
+
+ $settings_added = TRUE;
+ }
+
+ return $loaded[$name];
+}
+
+/**
+ * Register a theme.
*/
-function wysiwyg_controller() {
+function wysiwyg_add_editor_settings($profile, $theme) {
+ static $themes = array();
+
+ if (!isset($themes[$theme])) {
+ $config = wysiwyg_get_editor_config($profile, $theme);
+ // Convert the config values into the form expected by Wysiwyg Editor.
+ // @todo Is this conversion TinyMCE specific?
+ foreach ($config as $key => $value) {
+ if (is_bool($value)) {
+ continue;
+ }
+ if (is_array($value)) {
+ $config[$key] = implode(',', $config[$key]);
+ }
+ }
+ drupal_add_js(array('wysiwyg' => array('configs' => array($profile->settings['editor'] => array($theme => $config)))), 'setting');
+ $themes[$theme] = TRUE;
+ }
}
/**
- * hook_wysiwyg_plugin(). Return an array of editor plugins.
+ * Add settings for external plugins.
+ *
+ * @param $profile
+ * A wysiwyg editor profile.
+ */
+function wysiwyg_add_plugin_settings($profile) {
+ static $plugins_added = array();
+
+ if (!isset($plugins_added[$profile->settings['editor']])) {
+ $plugins = array();
+ $editor = wysiwyg_get_editor($profile->settings['editor']);
+ // Collect editor plugins provided via hook_wysiwyg_plugin().
+ $info = module_invoke_all('wysiwyg_plugin', $editor['name'], $editor['installed version']);
+ // Only keep enabled plugins in this profile.
+ foreach ($info as $plugin => $meta) {
+ if (!isset($profile->settings['buttons'][$plugin])) {
+ unset($info[$plugin]);
+ }
+ }
+
+ if (isset($editor['plugin settings callback']) && function_exists($editor['plugin settings callback'])) {
+ $plugins = $editor['plugin settings callback']($editor, $profile, $info);
+ }
+
+ drupal_add_js(array('wysiwyg' => array('plugins' => array($profile->settings['editor'] => $plugins))), 'setting');
+
+ $plugins_added[$profile->settings['editor']] = TRUE;
+ }
+}
+
+/**
+ * Grab the themes available to Wysiwyg Editor.
*
- * Each wysiwyg editor as well as each contrib module implementing an editor
- * plugin has to return an associative array of available plugins. Each module
- * can add one or more plugins and editor buttons.
+ * Wysiwyg Editor themes control the functionality and buttons that are available to a
+ * user. Themes are only looked for within the default Wysiwyg Editor theme directory.
*
- * Notes for TinyMCE:
- * A module is able to override almost all TinyMCE initialization settings.
- * However, modules should only make use of that if a plugin really needs to,
- * because customized configuration settings may clash with overrides by another
- * module. TinyMCE automatically assigns the baseURL of your plugin to the plugin
- * object. If you need to load or access additional files from your plugin
- * directory, retrieve the path via this.baseURL. tinyMCE.baseURL returns the
- * path of TinyMCE and not your module. For example:
- * @code
- * initInstance: function(inst) {
- * tinyMCE.importCSS(inst.getDoc(), this.baseURL + '/myplugin.css');
- * },
- * @endcode
- *
- * @param string $editor
- * An (lowercase) editor name to return plugins for.
- * @return array
- * An associative array having internal plugin names as keys, an array of
- * plugin meta-information as values:
- * - type: 'external' (optional); if omitted, wysiwyg editors will likely
- * search for the plugin in their own plugins folder.
- * - title: A human readable title of the plugin.
- * - description: A (one-line) description of the plugin.
- * - path: The patch to the javascript plugin.
- * - callback: A Drupal menu callback returning the plugin UI. A plugin
- * should return a callback *or* a path.
- * - icon: An icon (usually 16x16 pixels) for the plugin button (optional).
- * - ... Any other custom editor settings (optional).
+ * @param $profile
+ * A wysiwyg editor profile; passed/altered by reference.
+ * @param $selected_theme
+ * An optional theme name that ought to be used.
*
- * @todo Move this template into hooks.php.
+ * @return
+ * An array of theme names, or a single, checked theme name if $selected_theme
+ * was given.
*/
-function hook_wysiwyg_plugin($editor) {
- switch ($editor) {
- case 'tinymce':
- return array(
- 'myplugin' => array(
- 'type' => 'external',
- 'title' => t('My plugin title'),
- 'description' => t('My plugin title'),
- // Regular callback URL for external TinyMCE plugins.
- 'path' => drupal_get_path('module', 'mymodule') .'/myplugin',
- // Wysiwyg wrapper plugin AJAX callback.
- 'callback' => url('myplugin/browse'),
- 'icon' => drupal_get_path('module', 'mymodule') .'/myplugin/myplugin.png',
- 'extended_valid_elements' => array('tag[attribute1|attribute2=default_value]'),
- // Might need to be set later on; after retrieving customized editor
- // layout.
- 'theme_advanced_buttons1' => array(t('Button title (optional)') => 'myplugin'),
- ),
- );
+function wysiwyg_get_editor_themes(&$profile, $selected_theme = NULL) {
+ static $themes = array();
+
+ if (!isset($themes[$profile->settings['editor']])) {
+ $editor = wysiwyg_get_editor($profile->settings['editor']);
+ if (isset($editor['themes callback']) && function_exists($editor['themes callback'])) {
+ $themes[$editor['name']] = $editor['themes callback']($editor, $profile);
+ }
+ // Fallback to 'default' otherwise.
+ else {
+ $themes[$editor['name']] = array('default');
+ }
}
+
+ // Check optional $selected_theme argument, if given.
+ if (isset($selected_theme)) {
+ // If the passed theme name does not exist, use the first available.
+ if (!isset($themes[$profile->settings['editor']][$selected_theme])) {
+ $selected_theme = $profile->settings['theme'] = $themes[$profile->settings['editor']][0];
+ }
+ }
+
+ return isset($selected_theme) ? $selected_theme : $themes[$profile->settings['editor']];
}
/**
- * Implementation of hook_wysiwyg_plugin().
+ * Return plugin metadata from the plugin registry.
*
- * Implements a generic wrapper plugin for Drupal (module-based) editor plugins.
+ * @param $editor_name
+ * The internal name of an editor to return plugins for.
*
- * Considerations:
- * - By comparing the javascript of available editor plugins, most of them are
- * based on img_assist.
- * - An editor plugin basically consists of a title, icon (button), description
- * (localized) and menu path returning the actual Drupal module. This
- * meta-information is available via hook_wysiwyg_plugin().
- * - Each editor implements its own plugin API, but the JS-PHP-JS communication
- * is always the same.
- * - Since Drupal 5, jQuery is always available and allows to perform AJAX/HTTP
- * requests at any time.
- * - Each editor plugin returns HTML via Javascript to the editor.
- * - Do we really require each Drupal editor plugin to write their own
- * javascript or are we able to supply Drupal editor plugins to all editors
- * through a wrapper module?
- * - We can transform a regular editor plugin template into a wrapper plugin or
- * we can use a Drupal menu path to serve a editor plugin template which
- * (optionally) already has additional plugin code injected.
+ * @return
+ * An array for each plugin.
+ */
+function wysiwyg_get_plugins($editor_name) {
+ $plugins = array();
+ if (!empty($editor_name)) {
+ $editor = wysiwyg_get_editor($editor_name);
+ // Add internal editor plugins.
+ if (isset($editor['plugin callback']) && function_exists($editor['plugin callback'])) {
+ $plugins = $editor['plugin callback']($editor);
+ }
+ // Load our own plugins.
+ include_once drupal_get_path('module', 'wysiwyg') .'/wysiwyg.plugins.inc';
+
+ // Add editor plugins provided via hook_wysiwyg_plugin().
+ $plugins = array_merge($plugins, module_invoke_all('wysiwyg_plugin', $editor['name'], $editor['installed version']));
+ }
+ return $plugins;
+}
+
+/**
+ * Return an array of initial Wysiwyg Editor config options from the current role.
+ */
+function wysiwyg_get_editor_config($profile, $theme) {
+ $editor = wysiwyg_get_editor($profile->settings['editor']);
+ $settings = array();
+ if (!empty($editor['settings callback']) && function_exists($editor['settings callback'])) {
+ $settings = $editor['settings callback']($editor, $profile->settings, $theme);
+ }
+ return $settings;
+}
+
+/**
+ * Return the name of the current user's default profile.
*/
-function wysiwyg_wysiwyg_plugin($editor) {
- switch ($editor) {
- case 'tinymce':
- // Define generic plugin properties.
- $path = drupal_get_path('module', 'wysiwyg') .'/wrapper/tinymce'
-
- // Load all Drupal editor plugins into an array.
- $plugins = module_invoke_all('wysiwyg_plugin', $editor);
-
- // Define all Drupal editor plugins by looping through the array,
- // omitting all non-'external' plugins; assigning type, title, icon,
- // custom editor settings and most important:
- // wrapper plugin path followed by callback path (if JS: use query string).
-
-
- return $plugins;
+function wysiwyg_current_profile() {
+ global $user;
+ static $profile_name;
+
+ if (!isset($profile_name)) {
+ $profile_name = db_result(db_query_range('SELECT p.name FROM {wysiwyg_profile} p INNER JOIN {wysiwyg_role} r ON r.name = p.name WHERE r.rid IN (%s) ORDER BY plugin_count DESC', implode(',', array_keys($user->roles)), 0, 1));
}
+ return $profile_name;
}
/**
- * Return an array of editor plugins.
+ * Load all profiles. Just load one profile if $name is passed in.
+ */
+function wysiwyg_load_profile($name = '') {
+ static $profiles;
+
+ // If $name is passed from wysiwyg_current_profile(), it may be FALSE,
+ // which means the user is not allowed to use a wysiwyg editor.
+ if ($name === FALSE) {
+ return FALSE;
+ }
+ if (!isset($profiles)) {
+ $profiles = array();
+ $roles = user_roles();
+ $result = db_query('SELECT * FROM {wysiwyg_profile}');
+ while ($profile = db_fetch_object($result)) {
+ $profile->settings = unserialize($profile->settings);
+ $result2 = db_query("SELECT rid FROM {wysiwyg_role} WHERE name = '%s'", $profile->name);
+ $profile_roles = array();
+ while ($role = db_fetch_object($result2)) {
+ $profile_roles[$role->rid] = $roles[$role->rid];
+ }
+ $profile->rids = $profile_roles;
+
+ $profiles[$profile->name] = $profile;
+ }
+ }
+
+ return ($name && isset($profiles[$name]) ? $profiles[$name] : ($name ? FALSE : $profiles));
+}
+
+/**
+ * Implementation of hook_user().
+ */
+function wysiwyg_user($type, &$edit, &$user, $category = NULL) {
+ if ($type == 'form' && $category == 'account' && user_access('access wysiwyg editor')) {
+ $profile = wysiwyg_user_get_profile($user);
+ if (isset($profile->settings['user_choose']) && $profile->settings['user_choose']) {
+ $form['wysiwyg'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Wysiwyg Editor settings'),
+ '#weight' => 10,
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ );
+ $form['wysiwyg']['wysiwyg_status'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Enable editor by default'),
+ '#default_value' => isset($user->wysiwyg_status) ? $user->wysiwyg_status : (isset($profile->settings['default']) ? $profile->settings['default'] : FALSE),
+ '#return_value' => 1,
+ '#description' => t('If enabled, rich-text editing is enabled by default in textarea fields.'),
+ );
+ return array('wysiwyg' => $form);
+ }
+ }
+ if ($type == 'validate') {
+ return array('wysiwyg_status' => $edit['wysiwyg_status']);
+ }
+}
+
+function wysiwyg_user_get_profile($account) {
+ $profile_name = db_result(db_query('SELECT s.name FROM {wysiwyg_profile} s INNER JOIN {wysiwyg_role} r ON r.name = s.name WHERE r.rid IN (%s)', implode(',', array_keys($account->roles))));
+ if ($profile_name) {
+ return wysiwyg_load_profile($profile_name);
+ }
+ else {
+ return FALSE;
+ }
+}
+
+function wysiwyg_user_get_status($profile) {
+ global $user;
+ $settings = $profile->settings;
+
+ if ($settings['user_choose'] && isset($user->wysiwyg_status)) {
+ $status = $user->wysiwyg_status;
+ }
+ else {
+ $status = isset($settings['default']) ? $settings['default'] : FALSE;
+ }
+
+ return $status;
+}
+
+/**
+ * @defgroup wysiwyg_api Wysiwyg API
+ * @{
*
- * @param string $op
- * A performed action:
- * - 'list': Plugins are about to be listed or registered.
- * - 'load': Plugins are about to be loaded.
- * @param string $editor
- * An (lowercase) editor name to retrieve plugins for.
+ * @todo Forked from Panels; abstract into a separate API module that allows
+ * contrib modules to define supported include/plugin types.
+ */
+
+/**
+ * Return library information for a given editor.
*
- * @see hook_wysiwyg_plugin()
+ * @param $name
+ * The internal name of an editor.
*
- * @todo Implement TinyMCE-specific code as hook into wysiwyg_tinymce.inc.
+ * @return
+ * The library information for the editor, or FALSE if $name is unknown or not
+ * installed properly.
*/
-function wysiwyg_get_plugins($op, $editor) {
- static $plugins;
-
- if (!isset($plugins)) {
- $plugins = module_invoke_all('wysiwyg_plugin', $editor);
+function wysiwyg_get_editor($name) {
+ $editors = wysiwyg_get_all_editors();
+ return isset($editors[$name]) && $editors[$name]['installed'] ? $editors[$name] : FALSE;
+}
+
+/**
+ * Compile a list holding all supported editors including installed editor version information.
+ */
+function wysiwyg_get_all_editors() {
+ static $editors;
+
+ if (isset($editors)) {
+ return $editors;
}
-
- switch ($editor) {
- case 'tinymce':
- if ($op == 'list') {
- // Do not alter cached array.
- $plugin_list = $plugins;
- foreach ($plugin_list as $name => $plugin) {
- if ($plugin['type'] == 'external') {
- $plugin_list[$name] = _wysiwyg_plugin_name('add', $name);
- }
- }
- return $plugin_list;
+
+ $editors = wysiwyg_load_includes('editors', 'editor');
+ foreach ($editors as $editor => $properties) {
+ // Fill in required properties.
+ $editors[$editor] += array(
+ 'title' => '',
+ 'vendor url' => '',
+ 'download url' => '',
+ 'editor path' => wysiwyg_get_path($properties['name']),
+ 'library path' => wysiwyg_get_path($properties['name']),
+ 'libraries' => array(),
+ 'version callback' => NULL,
+ 'themes callback' => NULL,
+ 'settings callback' => NULL,
+ 'plugin callback' => NULL,
+ 'plugin settings callback' => NULL,
+ 'versions' => array(),
+ 'js path' => $properties['path'] .'/js',
+ 'css path' => $properties['path'] .'/css',
+ );
+ // Check whether library is present.
+ if (!($editors[$editor]['installed'] = file_exists($properties['library path']))) {
+ continue;
+ }
+ // Detect library version.
+ if (function_exists($editors[$editor]['version callback'])) {
+ $editors[$editor]['installed version'] = $editors[$editor]['version callback']($properties);
+ }
+ if (empty($editors[$editor]['installed version'])) {
+ $editors[$editor]['error'] = t('The version of %editor could not be detected.', array('%editor' => $properties['title']));
+ $editors[$editor]['installed'] = FALSE;
+ continue;
+ }
+ // Determine to which supported version the installed version maps.
+ ksort($editors[$editor]['versions']);
+ $version = 0;
+ foreach ($editors[$editor]['versions'] as $supported_version => $version_properties) {
+ if (version_compare($editors[$editor]['installed version'], $supported_version, '>=')) {
+ $version = $supported_version;
}
- else if ($op == 'load') {
- static $plugins_added;
-
- if (!isset($plugins_added)) {
- $plugins_added = TRUE;
-
- $init_plugins = '';
- foreach ($plugins as $name => $plugin) {
- // Ensure there is no leading hiven in external plugin names.
- $name = _wysiwyg_plugin_name('remove', $name);
-
- $init_plugins .= "tinyMCE.loadPlugin('$name', '". base_path() . $plugin['path'] ."');\n";
- }
- if (!empty($init_plugins)) {
- drupal_add_js($init_plugins, 'inline');
- }
- }
+ }
+ if (!$version) {
+ $editors[$editor]['error'] = t('The installed version of %editor is not supported.', array('%editor' => $properties['title']));
+ $editors[$editor]['installed'] = FALSE;
+ continue;
+ }
+ // Apply library version specific definitions and overrides.
+ $editors[$editor] = array_merge($editors[$editor], $editors[$editor]['versions'][$version]);
+ unset($editors[$editor]['versions']);
+ $editors[$editor]['title'] = $editors[$editor]['title'] . ' ' . $editors[$editor]['installed version'];
+ }
+ return $editors;
+}
+
+/**
+ * Load include files for wysiwyg implemented by all modules.
+ *
+ * @param $type
+ * The type of includes to search for, can be 'editors'.
+ * @param $hook
+ * The hook name to invoke.
+ * @param $file
+ * An optional include file name without .inc extension to limit the search to.
+ *
+ * @see wysiwyg_get_directories(), _wysiwyg_process_include()
+ */
+function wysiwyg_load_includes($type = 'editors', $hook = 'editor', $file = NULL) {
+ // Determine implementations.
+ $directories = wysiwyg_get_directories($type);
+ $directories['wysiwyg_'] = wysiwyg_get_path($type);
+ $file_list = array();
+ foreach ($directories as $module => $path) {
+ $file_list[$module] = drupal_system_listing("$file" . '.inc$', $path, 'name', 0);
+ }
+
+ // Load implementations.
+ $info = array();
+ foreach (array_filter($file_list) as $module => $files) {
+ foreach ($files as $file) {
+ include_once './' . $file->filename;
+ $result = _wysiwyg_process_include('wysiwyg', $module . $file->name, dirname($file->filename), $hook);
+ if (is_array($result)) {
+ $info = array_merge($info, $result);
}
- break;
+ }
}
-}
+ return $info;
+}
+/**
+ * Helper function to build module/file paths.
+ *
+ * @param $file
+ * A file or directory in a module to return.
+ * @param $base_path
+ * Whether to prefix the resulting path with base_path().
+ * @param $module
+ * The module name to use as prefix.
+ *
+ * @return
+ * The path to the specified file in a module.
+ */
+function wysiwyg_get_path($file = '', $base_path = FALSE, $module = 'wysiwyg') {
+ $base_path = ($base_path ? base_path() : '');
+ return $base_path . drupal_get_path('module', $module) . '/' . $file;
+}
/**
- * Add or remove leading hiven to/of (external) plugin names.
+ * Return a list of directories by modules implementing wysiwyg_include_directory().
*
- * Externally loaded TinyMCE plugins need to be prefixed with a hiven. TinyMCE
- * will not try to add and load external plugins from the default plugins
- * folder.
- *
- * @param string $op
- * Operation to perform, 'add' or 'remove'.
- * @param string $editor
- * An editor name.
- * @param string $name
- * A plugin name.
+ * @param $plugintype
+ * The type of a plugin; can be 'editors'.
+ *
+ * @return
+ * An array containing module names suffixed with '_' and their defined
+ * directory.
*
- * @todo Implement TinyMCE-specific code as hook into wysiwyg_tinymce.inc.
+ * @see wysiwyg_load_includes(), _wysiwyg_process_include()
*/
-function _wysiwyg_plugin_name($op, $editor, $name) {
- switch ($editor) {
- case 'tinymce':
- if ($op == 'add') {
- if (strpos($name, '-') !== 0) {
- return '-'. $name;
- }
- return $name;
- }
- else {
- if (strpos($name, '-') === 0) {
- return substr($name, 1);
- }
- return $name;
- }
- break;
+function wysiwyg_get_directories($plugintype) {
+ $directories = array();
+ foreach (module_implements('wysiwyg_include_directory') as $module) {
+ $result = module_invoke($module, 'wysiwyg_include_directory', $plugintype);
+ if (isset($result) && is_string($result)) {
+ $directories[$module .'_'] = drupal_get_path('module', $module) .'/'. $result;
+ }
}
+ return $directories;
}
+/**
+ * Process a single hook implementation of a wysiwyg editor.
+ *
+ * @param $module
+ * The module that owns the hook.
+ * @param $identifier
+ * Either the module or 'wysiwyg_' . $file->name
+ * @param $hook
+ * The name of the hook being invoked.
+ */
+function _wysiwyg_process_include($module, $identifier, $path, $hook) {
+ $function = $identifier . '_' . $hook;
+ if (!function_exists($function)) {
+ return NULL;
+ }
+ $result = $function();
+ if (!isset($result) || !is_array($result)) {
+ return NULL;
+ }
+
+ // Fill in defaults.
+ foreach ($result as $editor => $properties) {
+ $result[$editor]['module'] = $module;
+ $result[$editor]['name'] = $editor;
+ $result[$editor]['path'] = $path;
+ }
+ return $result;
+}
+
+/**
+ * @} End of "defgroup wysiwyg_api".
+ */
+
diff --git a/wysiwyg_editor.plugins.inc b/wysiwyg.plugins.inc
index 3027884..5f46d77 100644
--- a/wysiwyg_editor.plugins.inc
+++ b/wysiwyg.plugins.inc
@@ -5,13 +5,13 @@
/**
* Implementation of hook_wysiwyg_plugin().
*/
-function wysiwyg_editor_wysiwyg_plugin($editor, $version) {
+function wysiwyg_wysiwyg_plugin($editor, $version) {
switch ($editor) {
case 'tinymce':
if ($version < 3) {
return array(
'wysiwyg' => array(
- 'path' => drupal_get_path('module', 'wysiwyg_editor') .'/plugins/break/editor_plugin.js',
+ 'path' => drupal_get_path('module', 'wysiwyg') .'/plugins/break/editor_plugin.js',
'buttons' => array('break' => t('Teaser break')),
'url' => 'http://drupal.org/project/wysiwyg',
),
diff --git a/wysiwyg_editor.info b/wysiwyg_editor.info
index 600f61b..bfb910d 100644
--- a/wysiwyg_editor.info
+++ b/wysiwyg_editor.info
@@ -1,5 +1,5 @@
; $Id$
-name = Wysiwyg Editor
-description = Allows users to edit contents with client-side editors.
+name = Wysiwyg Editor (UNINSTALL)
+description = Please uninstall this module after running update.php.
package = User interface
core = 6.x
diff --git a/wysiwyg_editor.install b/wysiwyg_editor.install
index aa3bd70..514bfb3 100644
--- a/wysiwyg_editor.install
+++ b/wysiwyg_editor.install
@@ -1,7 +1,6 @@
<?php
// $Id$
-
/**
* Implementation of hook_schema().
*/
@@ -28,15 +27,6 @@ function wysiwyg_editor_schema() {
}
/**
- * Implementation of hook_install().
- */
-function wysiwyg_editor_install() {
- drupal_install_schema('wysiwyg_editor');
- // Import data from old editor modules.
- wysiwyg_editor_migrate_tinymce();
-}
-
-/**
* Implementation of hook_uninstall()
*/
function wysiwyg_editor_uninstall() {
@@ -44,57 +34,6 @@ function wysiwyg_editor_uninstall() {
}
/**
- * Migrate from TinyMCE.
- */
-function wysiwyg_editor_migrate_tinymce() {
- if (db_table_exists('tinymce_settings')) {
- $schema = db_result(db_query("SELECT schema_version FROM {system} WHERE name = 'tinymce'"));
- if ($schema >= 1) {
- // Import TinyMCE settings.
- db_query('INSERT INTO {wysiwyg_editor_profile} (name, settings) SELECT name, settings FROM {tinymce_settings}');
- // Import TinyMCE profile role assignments.
- db_query('INSERT INTO {wysiwyg_editor_role} (name, rid) SELECT name, rid FROM {tinymce_role}');
-
- // Disable TinyMCE module.
- module_disable(array('tinymce'));
-
- // Update configuration.
- wysiwyg_editor_update_5001();
- }
- else {
- drupal_set_message(t('To migrate your existing TinyMCE settings to Wysiwyg Editor, please update TinyMCE module to the latest official release, and re-install Wysiwyg Editor module.'));
- }
- }
-}
-
-/**
- * Convert buttons and plugins into associative array and fix plugin count for old profiles.
- *
- * Note: This update is required for wysiwyg_editor_migrate_tinymce().
- */
-function wysiwyg_editor_update_5001() {
- $ret = array();
- $profiles = db_query("SELECT name, settings, plugin_count FROM {wysiwyg_editor_profile}");
- while ($profile = db_fetch_array($profiles)) {
- $settings = unserialize($profile['settings']);
- if (isset($settings['form_id'])) {
- $old_buttons = (isset($settings['buttons']) ? $settings['buttons'] : array());
- $settings['buttons'] = array();
- $plugin_count = 0;
- foreach ($old_buttons as $old_button => $enabled) {
- list($plugin, $button) = explode('-', $old_button, 2);
- $settings['buttons'][$plugin][$button] = 1;
- $plugin_count++;
- }
- // We can't use update_sql() here because of curly braces in serialized
- // array.
- db_query("UPDATE {wysiwyg_editor_profile} SET settings = '%s', plugin_count = %d WHERE name = '%s'", serialize($settings), $plugin_count, $profile['name']);
- }
- }
- return $ret;
-}
-
-/**
* Add editor key to wysiwyg profiles.
*/
function wysiwyg_editor_update_6002() {
@@ -112,3 +51,20 @@ function wysiwyg_editor_update_6002() {
return $ret;
}
+/**
+ * Enable Wysiwyg module.
+ */
+function wysiwyg_editor_update_6003() {
+ $ret = array();
+ if (!module_exists('wysiwyg')) {
+ // Load Wysiwyg module.
+ module_enable(array('wysiwyg'));
+ // Invoke module installation.
+ module_invoke('wysiwyg', 'install');
+ // Disable Wysiwyg Editor module.
+ module_disable(array('wysiwyg_editor'));
+ $ret[] = array('success' => TRUE, 'query' => t('Wysiwyg Editor module has been disabled and replaced with Wysiwyg module. Your Wysiwyg profiles should have been migrated.'));
+ }
+ return $ret;
+}
+
diff --git a/wysiwyg_editor.module b/wysiwyg_editor.module
index f4a2485..a1710df 100644
--- a/wysiwyg_editor.module
+++ b/wysiwyg_editor.module
@@ -1,741 +1,5 @@
<?php
// $Id$
-
-/**
- * @file
- * Integrate client-side editors with Drupal.
- *
- * Please note that this module is slowly moving to become wysiwyg.module. Most
- * functions are still based on the obsolete wysiwyg_editor name, which was
- * originally chosen, because it was not clear whether editors would just be
- * one component of a larger API.
- */
-
-/**
- * Implementation of hook_menu().
- */
-function wysiwyg_editor_menu() {
- $items = array();
- $items['admin/settings/wysiwyg/profile'] = array(
- 'title' => 'Wysiwyg Editor',
- 'page callback' => 'wysiwyg_editor_admin',
- 'description' => 'Configure client-side editors profiles.',
- 'access arguments' => array('administer site configuration'),
- 'file' => 'wysiwyg_editor.admin.inc',
- );
- return $items;
-}
-
-/**
- * Implementation of hook_theme().
- */
-function wysiwyg_editor_theme() {
- return array(
- 'wysiwyg_editor_admin_button_table' => array('arguments' => array('form')),
- );
-}
-
-/**
- * Implementation of hook_help().
- */
-function wysiwyg_editor_help($path, $arg) {
- switch ($path) {
- case 'admin/settings/wysiwyg/profile':
- case 'admin/help#wysiwyg_editor':
- $output = '<p>'. t('Profiles can be defined based on user roles. A Wysiwyg Editor profile can define which pages receive this Wysiwyg Editor capability, what buttons or themes are enabled for the editor, how the editor is displayed, and a few other editor functions. Lastly, only users with the %permission <a href="!url">user permission</a> are able to use Wysiwyg Editor.', array('%permission' => 'access wysiwyg editor', '!url' => url('admin/user/permissions'))) .'</p>';
- return $output;
- }
-}
-
-/**
- * Implementation of hook_perm().
- */
-function wysiwyg_editor_perm() {
- return array('access wysiwyg editor');
-}
-
-/**
- * Implementation of hook_elements().
- *
- * Before Drupal 7, there is no way to easily identify form fields that are
- * input format enabled. This is a workaround: We assign a form #after_build
- * processing callback that is executed on all forms after they have been
- * completely built, so that form elements already are in their effective order
- * and position.
- *
- * @see wysiwyg_process_form()
- *
- * @todo Remove #wysiwyg_style; the GUI for an editor should be solely handled
- * via profiles, when profiles are attached to an input format. It makes no
- * sense to display TinyMCE's simple GUI/theme for the user signature, when
- * the input format allows users to use advanced HTML and hence, editor
- * plugins. Fix this here, in wysiwyg_editor_process_element(), and lastly
- * in wysiwyg_editor_get_config().
- */
-function wysiwyg_editor_elements() {
- $type = array();
- if (user_access('access wysiwyg editor')) {
- // @todo Derive editor theme from input format.
- $type['textarea'] = array('#wysiwyg_style' => 'advanced');
- $type['form'] = array('#after_build' => array('wysiwyg_process_form'));
- }
- return $type;
-}
-
-/**
- * Implementation of hook_form_alter().
- */
-function wysiwyg_editor_form_alter(&$form, &$form_state) {
- // Disable 'teaser' textarea.
- if (isset($form['body_field'])) {
- unset($form['body_field']['teaser_js']);
- $form['body_field']['teaser_include'] = array();
- }
-}
-
-/**
- * Process a textarea for Wysiwyg Editor.
- *
- * This way, we can recurse into the form and search for certain, hard-coded
- * elements that have been added by filter_form(). If an input format selector
- * or input format guidelines element is found, we assume that the preceding
- * element is the corresponding textarea and use it's #id for attaching
- * client-side editors.
- *
- * @see wysiwyg_editor_elements(), filter_form()
- */
-function wysiwyg_process_form(&$form) {
- // Iterate over element children; resetting array keys to access last index.
- if ($children = array_values(element_children($form))) {
- foreach ($children as $index => $item) {
- $element = &$form[$item];
-
- // filter_form() always uses the key 'format'. We need a type-agnostic
- // match to prevent false positives. Also, there must have been at least
- // one element on this level.
- if ($item === 'format' && $index > 0) {
- // Make sure we either match a input format selector or input format
- // guidelines (displayed if user has access to one input format only).
- if ((isset($element['#type']) && $element['#type'] == 'fieldset') || isset($element['format']['guidelines'])) {
- // The element before this element is the target form field.
- $field = &$form[$children[$index - 1]];
-
- // Disable #resizable to avoid resizable behavior to hi-jack the UI,
- // but load the behavior, so the 'none' editor can attach/detach it.
- $extra_class = '';
- if (!empty($field['#resizable'])) {
- // Due to our CSS class parsing, we can add arbitrary parameters
- // for each input format.
- $extra_class = ' wysiwyg-resizable-1';
- $field['#resizable'] = FALSE;
- drupal_add_js('misc/textarea.js');
- }
-
- // Determine the available input formats. The last child element is a
- // link to "More information about formatting options". When only one
- // input format is displayed, we also have to remove formatting
- // guidelines, stored in the child 'format'.
- $formats = element_children($element);
- array_pop($formats);
- unset($formats['format']);
- foreach ($formats as $format) {
- // Default to 'none' editor (Drupal's default behaviors).
- $editor = 'none';
- $theme = '';
- // Fetch the profile associated to this input format.
- $profile = wysiwyg_get_profile($format);
- if ($profile) {
- $editor = $profile->settings['editor'];
- // Check editor theme (and reset it if not/no longer available).
- $theme = wysiwyg_editor_get_themes($profile, $field['#wysiwyg_style']);
-
- // Add profile settings for this input format.
- wysiwyg_editor_add_settings($profile, $theme);
- // Add plugin settings for this input format.
- wysiwyg_editor_add_plugin_settings($profile);
-
- $theme = ' wysiwyg-theme-'. $theme;
- }
-
- // Use a prefix/suffix for a single input format, or attach to input
- // format selector radio buttons.
- if (isset($element['format']['guidelines'])) {
- $element[$format]['#prefix'] = '<div class="wysiwyg wysiwyg-editor-'. $editor .' wysiwyg-field-'. $field['#id'] . $theme . $extra_class .'">';
- $element[$format]['#suffix'] = '</div>';
- }
- else {
- if (isset($element[$format]['#attributes']['class'])) {
- $element[$format]['#attributes']['class'] .= ' ';
- }
- else {
- $element[$format]['#attributes']['class'] = '';
- }
- $element[$format]['#attributes']['class'] .= 'wysiwyg wysiwyg-editor-'. $editor .' wysiwyg-field-'. $field['#id'] . $theme . $extra_class;
- }
- }
- }
- // If this element is 'format', do not recurse further.
- continue;
- }
- // Recurse into children.
- wysiwyg_process_form($element);
- }
- }
- return $form;
-}
-
-/**
- * Determine the profile to use for a given input format id.
- *
- * This function also performs sanity checks for the configured editor in a
- * profile to ensure that we do not load a malformed editor.
- *
- * @param $format
- * The internal id of an input format.
- *
- * @return
- * A wysiwyg profile.
- *
- * @see wysiwyg_editor_load_editor(), wysiwyg_get_editor()
- *
- * @todo Replace wysiwyg_editor_current_profile() with a input format to profile
- * association.
- */
-function wysiwyg_get_profile($format) {
- // Determine whether this input format has PHP filter enabled.
- // Temporary, until input format to profile associations are in place.
- $filters = filter_list_format($format);
- foreach ($filters as $filter) {
- if ($filter->module == 'php') {
- return FALSE;
- }
- }
- if ($profile = wysiwyg_editor_load_profile(wysiwyg_editor_current_profile())) {
- if (wysiwyg_editor_load_editor($profile)) {
- return $profile;
- }
- }
- return FALSE;
-}
-
-/**
- * Load an editor library and initialize basic Wysiwyg settings.
- *
- * @param $profile
- * A wysiwyg editor profile.
- *
- * @return
- * TRUE if the editor has been loaded, FALSE if not.
- *
- * @see wysiwyg_get_profile()
- */
-function wysiwyg_editor_load_editor($profile) {
- static $settings_added;
- static $loaded = array();
-
- $name = $profile->settings['editor'];
- // Library files must be loaded only once.
- if (!isset($loaded[$name])) {
- // Load editor.
- $editor = wysiwyg_get_editor($name);
- if ($editor) {
- // Determine library files to load.
- // @todo Allow to configure the library/execMode to use.
- if (isset($profile->settings['library']) && isset($editor['libraries'][$profile->settings['library']])) {
- $library = $profile->settings['library'];
- $files = $editor['libraries'][$profile->settings['library']]['files'];
- }
- else {
- // Fallback to the first by default (external libraries can change).
- $library = key($editor['libraries']);
- $files = array_shift($editor['libraries']);
- $files = $files['files'];
- }
- foreach ($files as $file) {
- drupal_add_js($editor['library path'] . '/' . $file);
- }
- // Load JavaScript integration files for this editor.
- if (isset($editor['js files'])) {
- $files = $editor['js files'];
- }
- foreach ($files as $file) {
- drupal_add_js($editor['js path'] . '/' . $file, 'module', 'footer');
- }
-
- $status = wysiwyg_editor_user_get_status($profile);
- drupal_add_js(array('wysiwyg' => array(
- 'configs' => array($editor['name'] => array()),
- 'showToggle' => $profile->settings['show_toggle'],
- 'status' => $status,
- // If JS compression is enabled, at least TinyMCE is unable to determine
- // its own base path and exec mode since it can't find the script name.
- 'editorBasePath' => base_path() . $editor['library path'],
- 'execMode' => $library,
- )), 'setting');
-
- $loaded[$name] = TRUE;
- }
- else {
- $loaded[$name] = FALSE;
- }
- }
-
- // Add basic Wysiwyg settings if any editor has been added.
- if (!isset($settings_added) && $loaded[$name]) {
- drupal_add_js(array('wysiwyg' => array(
- 'configs' => array(),
- 'disable' => t('Disable rich-text'),
- 'enable' => t('Enable rich-text'),
- )), 'setting');
-
- // Initialize our namespaces in the *header* to do not force editor
- // integration scripts to check and define Drupal.wysiwyg on its own.
- drupal_add_js(wysiwyg_get_path('wysiwyg.init.js'));
-
- // The 'none' editor is a special editor implementation, allowing us to
- // attach and detach regular Drupal behaviors just like any other editor.
- drupal_add_js(wysiwyg_get_path('editors/js/none.js'), 'module', 'footer');
-
- // Add wysiwyg_editor.js to the footer to ensure it's executed after the
- // Drupal.settings array has been rendered and populated. Also, since editor
- // library initialization functions must be loaded first by the browser,
- // Drupal.wysiwygInit() must be executed AFTER editors registered
- // their callbacks, and BEFORE Drupal.behaviors are applied, this must come
- // last.
- drupal_add_js(wysiwyg_get_path('wysiwyg_editor.js'), 'module', 'footer');
-
- // Add our stylesheet to stack editor buttons into one row.
- // @todo This is TinyMCE 2.x specific at the moment.
- drupal_add_css(wysiwyg_get_path('wysiwyg_editor.css'));
-
- $settings_added = TRUE;
- }
-
- return $loaded[$name];
-}
-
-/**
- * Register a theme.
- */
-function wysiwyg_editor_add_settings($profile, $theme) {
- static $themes = array();
-
- if (!isset($themes[$theme])) {
- $config = wysiwyg_editor_get_config($profile, $theme);
- // Convert the config values into the form expected by Wysiwyg Editor.
- // @todo Is this conversion TinyMCE specific?
- foreach ($config as $key => $value) {
- if (is_bool($value)) {
- continue;
- }
- if (is_array($value)) {
- $config[$key] = implode(',', $config[$key]);
- }
- }
- drupal_add_js(array('wysiwyg' => array('configs' => array($profile->settings['editor'] => array($theme => $config)))), 'setting');
- $themes[$theme] = TRUE;
- }
-}
-
-/**
- * Add settings for external plugins.
- *
- * @param $profile
- * A wysiwyg editor profile.
- */
-function wysiwyg_editor_add_plugin_settings($profile) {
- static $plugins_added = array();
-
- if (!isset($plugins_added[$profile->settings['editor']])) {
- $plugins = array();
- $editor = wysiwyg_get_editor($profile->settings['editor']);
- // Collect editor plugins provided via hook_wysiwyg_plugin().
- $info = module_invoke_all('wysiwyg_plugin', $editor['name'], $editor['installed version']);
- // Only keep enabled plugins in this profile.
- foreach ($info as $plugin => $meta) {
- if (!isset($profile->settings['buttons'][$plugin])) {
- unset($info[$plugin]);
- }
- }
-
- if (isset($editor['plugin settings callback']) && function_exists($editor['plugin settings callback'])) {
- $plugins = $editor['plugin settings callback']($editor, $profile, $info);
- }
-
- drupal_add_js(array('wysiwyg' => array('plugins' => array($profile->settings['editor'] => $plugins))), 'setting');
-
- $plugins_added[$profile->settings['editor']] = TRUE;
- }
-}
-
-/**
- * Grab the themes available to Wysiwyg Editor.
- *
- * Wysiwyg Editor themes control the functionality and buttons that are available to a
- * user. Themes are only looked for within the default Wysiwyg Editor theme directory.
- *
- * @param $profile
- * A wysiwyg editor profile; passed/altered by reference.
- * @param $selected_theme
- * An optional theme name that ought to be used.
- *
- * @return
- * An array of theme names, or a single, checked theme name if $selected_theme
- * was given.
- */
-function wysiwyg_editor_get_themes(&$profile, $selected_theme = NULL) {
- static $themes = array();
-
- if (!isset($themes[$profile->settings['editor']])) {
- $editor = wysiwyg_get_editor($profile->settings['editor']);
- if (isset($editor['themes callback']) && function_exists($editor['themes callback'])) {
- $themes[$editor['name']] = $editor['themes callback']($editor, $profile);
- }
- // Fallback to 'default' otherwise.
- else {
- $themes[$editor['name']] = array('default');
- }
- }
-
- // Check optional $selected_theme argument, if given.
- if (isset($selected_theme)) {
- // If the passed theme name does not exist, use the first available.
- if (!isset($themes[$profile->settings['editor']][$selected_theme])) {
- $selected_theme = $profile->settings['theme'] = $themes[$profile->settings['editor']][0];
- }
- }
-
- return isset($selected_theme) ? $selected_theme : $themes[$profile->settings['editor']];
-}
-
-/**
- * Return plugin metadata from the plugin registry.
- *
- * @param $editor_name
- * The internal name of an editor to return plugins for.
- *
- * @return
- * An array for each plugin.
- */
-function wysiwyg_editor_get_plugins($editor_name) {
- $plugins = array();
- if (!empty($editor_name)) {
- $editor = wysiwyg_get_editor($editor_name);
- // Add internal editor plugins.
- if (isset($editor['plugin callback']) && function_exists($editor['plugin callback'])) {
- $plugins = $editor['plugin callback']($editor);
- }
- // Load our own plugins.
- include_once drupal_get_path('module', 'wysiwyg_editor') .'/wysiwyg_editor.plugins.inc';
-
- // Add editor plugins provided via hook_wysiwyg_plugin().
- $plugins = array_merge($plugins, module_invoke_all('wysiwyg_plugin', $editor['name'], $editor['installed version']));
- }
- return $plugins;
-}
-
-/**
- * Return an array of initial Wysiwyg Editor config options from the current role.
- */
-function wysiwyg_editor_get_config($profile, $theme) {
- $editor = wysiwyg_get_editor($profile->settings['editor']);
- $settings = array();
- if (!empty($editor['settings callback']) && function_exists($editor['settings callback'])) {
- $settings = $editor['settings callback']($editor, $profile->settings, $theme);
- }
- return $settings;
-}
-
-/**
- * Return the name of the current user's default profile.
- */
-function wysiwyg_editor_current_profile() {
- global $user;
- static $profile_name;
-
- if (!isset($profile_name)) {
- $profile_name = db_result(db_query_range('SELECT p.name FROM {wysiwyg_editor_profile} p INNER JOIN {wysiwyg_editor_role} r ON r.name = p.name WHERE r.rid IN (%s) ORDER BY plugin_count DESC', implode(',', array_keys($user->roles)), 0, 1));
- }
- return $profile_name;
-}
-
-/**
- * Load all profiles. Just load one profile if $name is passed in.
- */
-function wysiwyg_editor_load_profile($name = '') {
- static $profiles;
-
- // If $name is passed from wysiwyg_editor_current_profile(), it may be FALSE,
- // which means the user is not allowed to use a wysiwyg editor.
- if ($name === FALSE) {
- return FALSE;
- }
- if (!isset($profiles)) {
- $profiles = array();
- $roles = user_roles();
- $result = db_query('SELECT * FROM {wysiwyg_editor_profile}');
- while ($profile = db_fetch_object($result)) {
- $profile->settings = unserialize($profile->settings);
- $result2 = db_query("SELECT rid FROM {wysiwyg_editor_role} WHERE name = '%s'", $profile->name);
- $profile_roles = array();
- while ($role = db_fetch_object($result2)) {
- $profile_roles[$role->rid] = $roles[$role->rid];
- }
- $profile->rids = $profile_roles;
-
- $profiles[$profile->name] = $profile;
- }
- }
-
- return ($name && isset($profiles[$name]) ? $profiles[$name] : ($name ? FALSE : $profiles));
-}
-
-/**
- * Implementation of hook_user().
- */
-function wysiwyg_editor_user($type, &$edit, &$user, $category = NULL) {
- if ($type == 'form' && $category == 'account' && user_access('access wysiwyg editor')) {
- $profile = wysiwyg_editor_user_get_profile($user);
- if (isset($profile->settings['user_choose']) && $profile->settings['user_choose']) {
- $form['wysiwyg'] = array(
- '#type' => 'fieldset',
- '#title' => t('Wysiwyg Editor settings'),
- '#weight' => 10,
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- );
- $form['wysiwyg']['wysiwyg_editor_status'] = array(
- '#type' => 'checkbox',
- '#title' => t('Enable editor by default'),
- '#default_value' => isset($user->wysiwyg_editor_status) ? $user->wysiwyg_editor_status : (isset($profile->settings['default']) ? $profile->settings['default'] : FALSE),
- '#return_value' => 1,
- '#description' => t('If enabled, rich-text editing is enabled by default in textarea fields.'),
- );
- return array('wysiwyg_editor' => $form);
- }
- }
- if ($type == 'validate') {
- return array('wysiwyg_editor_status' => $edit['wysiwyg_editor_status']);
- }
-}
-
-function wysiwyg_editor_user_get_profile($account) {
- $profile_name = db_result(db_query('SELECT s.name FROM {wysiwyg_editor_profile} s INNER JOIN {wysiwyg_editor_role} r ON r.name = s.name WHERE r.rid IN (%s)', implode(',', array_keys($account->roles))));
- if ($profile_name) {
- return wysiwyg_editor_load_profile($profile_name);
- }
- else {
- return FALSE;
- }
-}
-
-function wysiwyg_editor_user_get_status($profile) {
- global $user;
- $settings = $profile->settings;
-
- if ($settings['user_choose'] && isset($user->wysiwyg_editor_status)) {
- $status = $user->wysiwyg_editor_status;
- }
- else {
- $status = isset($settings['default']) ? $settings['default'] : FALSE;
- }
-
- return $status;
-}
-
-/**
- * @defgroup wysiwyg_api Wysiwyg API
- * @{
- *
- * @todo Forked from Panels; abstract into a separate API module that allows
- * contrib modules to define supported include/plugin types.
- */
-
-/**
- * Return library information for a given editor.
- *
- * @param $name
- * The internal name of an editor.
- *
- * @return
- * The library information for the editor, or FALSE if $name is unknown or not
- * installed properly.
- */
-function wysiwyg_get_editor($name) {
- $editors = wysiwyg_get_all_editors();
- return isset($editors[$name]) && $editors[$name]['installed'] ? $editors[$name] : FALSE;
-}
-
-/**
- * Compile a list holding all supported editors including installed editor version information.
- */
-function wysiwyg_get_all_editors() {
- static $editors;
-
- if (isset($editors)) {
- return $editors;
- }
-
- $editors = wysiwyg_load_includes('editors', 'editor');
- foreach ($editors as $editor => $properties) {
- // Fill in required properties.
- $editors[$editor] += array(
- 'title' => '',
- 'vendor url' => '',
- 'download url' => '',
- 'editor path' => wysiwyg_get_path($properties['name']),
- 'library path' => wysiwyg_get_path($properties['name']),
- 'libraries' => array(),
- 'version callback' => NULL,
- 'themes callback' => NULL,
- 'settings callback' => NULL,
- 'plugin callback' => NULL,
- 'plugin settings callback' => NULL,
- 'versions' => array(),
- 'js path' => $properties['path'] .'/js',
- 'css path' => $properties['path'] .'/css',
- );
- // Check whether library is present.
- if (!($editors[$editor]['installed'] = file_exists($properties['library path']))) {
- continue;
- }
- // Detect library version.
- if (function_exists($editors[$editor]['version callback'])) {
- $editors[$editor]['installed version'] = $editors[$editor]['version callback']($properties);
- }
- if (empty($editors[$editor]['installed version'])) {
- $editors[$editor]['error'] = t('The version of %editor could not be detected.', array('%editor' => $properties['title']));
- $editors[$editor]['installed'] = FALSE;
- continue;
- }
- // Determine to which supported version the installed version maps.
- ksort($editors[$editor]['versions']);
- $version = 0;
- foreach ($editors[$editor]['versions'] as $supported_version => $version_properties) {
- if (version_compare($editors[$editor]['installed version'], $supported_version, '>=')) {
- $version = $supported_version;
- }
- }
- if (!$version) {
- $editors[$editor]['error'] = t('The installed version of %editor is not supported.', array('%editor' => $properties['title']));
- $editors[$editor]['installed'] = FALSE;
- continue;
- }
- // Apply library version specific definitions and overrides.
- $editors[$editor] = array_merge($editors[$editor], $editors[$editor]['versions'][$version]);
- unset($editors[$editor]['versions']);
- $editors[$editor]['title'] = $editors[$editor]['title'] . ' ' . $editors[$editor]['installed version'];
- }
- return $editors;
-}
-
-/**
- * Load include files for wysiwyg implemented by all modules.
- *
- * @param $type
- * The type of includes to search for, can be 'editors'.
- * @param $hook
- * The hook name to invoke.
- * @param $file
- * An optional include file name without .inc extension to limit the search to.
- *
- * @see wysiwyg_get_directories(), _wysiwyg_process_include()
- */
-function wysiwyg_load_includes($type = 'editors', $hook = 'editor', $file = NULL) {
- // Determine implementations.
- $directories = wysiwyg_get_directories($type);
- $directories['wysiwyg_'] = wysiwyg_get_path($type);
- $file_list = array();
- foreach ($directories as $module => $path) {
- $file_list[$module] = drupal_system_listing("$file" . '.inc$', $path, 'name', 0);
- }
-
- // Load implementations.
- $info = array();
- foreach (array_filter($file_list) as $module => $files) {
- foreach ($files as $file) {
- include_once './' . $file->filename;
- $result = _wysiwyg_process_include('wysiwyg', $module . $file->name, dirname($file->filename), $hook);
- if (is_array($result)) {
- $info = array_merge($info, $result);
- }
- }
- }
- return $info;
-}
-
-/**
- * Helper function to build module/file paths.
- *
- * @param $file
- * A file or directory in a module to return.
- * @param $base_path
- * Whether to prefix the resulting path with base_path().
- * @param $module
- * The module name to use as prefix.
- *
- * @return
- * The path to the specified file in a module.
- */
-function wysiwyg_get_path($file = '', $base_path = FALSE, $module = 'wysiwyg_editor') {
- $base_path = ($base_path ? base_path() : '');
- return $base_path . drupal_get_path('module', $module) . '/' . $file;
-}
-
-/**
- * Return a list of directories by modules implementing wysiwyg_include_directory().
- *
- * @param $plugintype
- * The type of a plugin; can be 'editors'.
- *
- * @return
- * An array containing module names suffixed with '_' and their defined
- * directory.
- *
- * @see wysiwyg_load_includes(), _wysiwyg_process_include()
- */
-function wysiwyg_get_directories($plugintype) {
- $directories = array();
- foreach (module_implements('wysiwyg_include_directory') as $module) {
- $result = module_invoke($module, 'wysiwyg_include_directory', $plugintype);
- if (isset($result) && is_string($result)) {
- $directories[$module .'_'] = drupal_get_path('module', $module) .'/'. $result;
- }
- }
- return $directories;
-}
-
-/**
- * Process a single hook implementation of a wysiwyg editor.
- *
- * @param $module
- * The module that owns the hook.
- * @param $identifier
- * Either the module or 'wysiwyg_' . $file->name
- * @param $hook
- * The name of the hook being invoked.
- */
-function _wysiwyg_process_include($module, $identifier, $path, $hook) {
- $function = $identifier . '_' . $hook;
- if (!function_exists($function)) {
- return NULL;
- }
- $result = $function();
- if (!isset($result) || !is_array($result)) {
- return NULL;
- }
-
- // Fill in defaults.
- foreach ($result as $editor => $properties) {
- $result[$editor]['module'] = $module;
- $result[$editor]['name'] = $editor;
- $result[$editor]['path'] = $path;
- }
- return $result;
-}
-
-/**
- * @} End of "defgroup wysiwyg_api".
- */
-
+// Dummy file to protect users who did not remove the complete module folder.
+// Remove after publishing 0.4 release.