Commit a5b6ca17 authored by sun's avatar sun

#253600 by sun: Changed editor integration so that client-side editors attach...

#253600 by sun: Changed editor integration so that client-side editors attach to input formats instead of textareas and are invoked for input format enabled textareas only.
parent 83575292
......@@ -6,6 +6,9 @@ Wysiwyg x.x-x.x, xxxx-xx-xx
Wysiwyg 6.x-x.x, xxxx-xx-xx
---------------------------
#253600 by sun: Changed editor integration so that client-side editors attach to
input formats instead of textareas and are invoked for input format enabled
textareas only.
#282717 by sun: Added (basic) FCKeditor support.
#316507 by sun: Added Drupal.wysiwyg function stacks to execute editor library
specific actions upon initializing, attaching, detaching, and toggling an
......
// $Id$
Drupal.wysiwyg = Drupal.wysiwyg || { 'init': {}, 'attach': {}, 'detach': {}, 'toggle': {} };
Drupal.wysiwyg = Drupal.wysiwyg || { 'init': {}, 'attach': {}, 'detach': {} };
/**
* Attach FCKeditor to textareas, using the theme specified in CSS class names.
* Attach this editor to a target element.
*
* @param editorSettings
* An object containing editor settings for each enabled editor theme.
* See Drupal.wysiwyg.attach.none() for a full desciption of this hook.
*/
Drupal.wysiwyg.attach.fckeditor = function(context, editorSettings) {
for (var theme in editorSettings) {
$('textarea.wysiwyg-' + theme + ':not(.wysiwyg-processed)', context).each(function() {
// @todo Convert string into variable name w/o overwriting string?
// workaround: build object via editors[this.id] = new ...
var oFCK_1 = new FCKeditor(this.id);
// Clone, so original settings are not overwritten.
var config = Drupal.wysiwyg.clone(editorSettings[theme]);
// Configure settings for this theme.
oFCK_1.BasePath = config.BasePath;
for (var setting in config) {
oFCK_1.Config[setting] = config[setting];
}
// Attach Wysiwyg Editor control if default is on.
if (Drupal.settings.wysiwygEditor.status) {
oFCK_1.ReplaceTextarea();
}
$(this).addClass('wysiwyg-processed');
});
Drupal.wysiwyg.attach.fckeditor = function(context, params, settings) {
// @todo Convert string into variable name w/o overwriting string?
// workaround: build object via editors[this.id] = new ...
var FCKinstance = new FCKeditor(params.field);
// Configure settings for this theme.
FCKinstance.BasePath = settings[params.theme].BasePath;
for (var setting in settings[params.theme]) {
FCKinstance.Config[setting] = settings[params.theme][setting];
}
}
/**
* Detach all FCKeditor editors.
*
* @todo Context support required to remove only certain editors (think AHAH/AJAX).
*/
Drupal.wysiwyg.detach.fckeditor = function(context) {
if (tinyMCE.activeEditor) {
tinyMCE.triggerSave();
tinyMCE.activeEditor.remove();
// Attach editor control if default is on.
if (Drupal.settings.wysiwygEditor.status) {
FCKinstance.ReplaceTextarea();
}
}
/**
* Toggle editor and return new state.
*
* @param element
* The DOM element to toggle the editor for.
* @param theme
* The editor theme assigned to the element.
* Detach a single or all editors.
*
* @return
* A boolean value indicating whether the editor has been enabled.
* See Drupal.wysiwyg.detach.none() for a full desciption of this hook.
*/
Drupal.wysiwyg.toggle.fckeditor = function(element, theme) {
var instance = FCKeditorAPI.GetInstance(element.id);
if ($(element).css('display') != 'none' || instance == null) {
instance.SetHTML($(element).hide().val());
$('#' + element.id + '___Frame').show();
return true;
}
else {
$('#' + element.id).val(instance.GetXHTML()).show();
$('#' + element.id + '___Frame').hide();
return false;
Drupal.wysiwyg.detach.fckeditor = function(context, params) {
if (typeof params != 'undefined') {
var editor = FCKeditorAPI.GetInstance(params.field);
if (editor) {
$('#' + params.field).val(editor.GetXHTML()).show();
$('#' + params.field + '___Config').remove();
$('#' + params.field + '___Frame').remove();
delete FCKeditorAPI.__Instances[params.field];
}
}
// else {
// tinyMCE.triggerSave();
// tinyMCE.remove();
// }
}
// $Id$
Drupal.wysiwyg = Drupal.wysiwyg || { 'init': {}, 'attach': {}, 'detach': {} };
/**
* Attach this editor to a target element.
*
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
* @param params
* An object containing input format parameters. Default parameters are:
* - editor: The internal editor name.
* - theme: The name/key of the editor theme/profile to use.
* - field: The CSS id of the target element.
* @param settings
* An object containing editor settings for all enabled editor themes.
*/
Drupal.wysiwyg.attach.none = function(context, params, settings) {
if (params.resizable) {
$('#' + params.field).addClass('resizable');
Drupal.behaviors.textarea();
}
}
/**
* Detach a single or all editors.
*
* See Drupal.wysiwyg.attach.none() for a full desciption of arguments.
*
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
* @param params
* (optional) An object containing input format parameters. If defined,
* only the editor instance in params.field should be detached. Otherwise,
* all editors should be detached and saved, so they can be submitted in
* AJAX/AHAH applications.
*/
Drupal.wysiwyg.detach.none = function(context, params) {
if (typeof params != 'undefined') {
var $textarea = $('#' + params.field, context).removeClass('textarea-processed');
var $div = $textarea.parents('div.resizable-textarea');
$div.before($textarea);
$div.remove();
}
}
// $Id$
Drupal.wysiwyg = Drupal.wysiwyg || { 'init': {}, 'attach': {}, 'detach': {}, 'toggle': {} };
Drupal.wysiwyg = Drupal.wysiwyg || { 'init': {}, 'attach': {}, 'detach': {} };
/**
* Initialize TinyMCE instances.
* Initialize editor instances.
*
* This function needs to be called before the page is fully loaded, as
* calling tinyMCE.init() after the page is loaded breaks IE6.
......@@ -31,54 +31,34 @@ Drupal.wysiwyg.init.tinymce = function(editorSettings) {
}
/**
* Attach TinyMCE to textareas, using the theme specified in CSS class names.
* Attach this editor to a target element.
*
* @param editorSettings
* An object containing editor settings for each enabled editor theme.
* See Drupal.wysiwyg.attach.none() for a full desciption of this hook.
*/
Drupal.wysiwyg.attach.tinymce = function(context, editorSettings) {
for (var theme in editorSettings) {
// Clone, so original settings are not overwritten.
var config = Drupal.wysiwyg.clone(editorSettings[theme]);
// Configure settings for this theme.
for (var setting in config) {
tinyMCE.settings[setting] = config[setting];
}
$('textarea.wysiwyg-' + theme + ':not(.wysiwyg-processed)', context).each(function() {
// Attach Wysiwyg Editor control if default is on.
if (Drupal.settings.wysiwygEditor.status) {
tinyMCE.execCommand('mceAddControl', true, this.id);
}
$(this).addClass('wysiwyg-processed');
});
Drupal.wysiwyg.attach.tinymce = function(context, params, editorSettings) {
// Configure settings for this theme.
for (var setting in editorSettings[params.theme]) {
tinyMCE.settings[setting] = editorSettings[params.theme][setting];
}
// Attach editor control if default is on.
if (Drupal.settings.wysiwygEditor.status) {
tinyMCE.execCommand('mceAddControl', true, params.field);
}
}
/**
* Toggle editor and return new state.
*
* @param element
* The DOM element to toggle the editor for.
* @param theme
* The editor theme assigned to the element.
* Detach a single or all editors.
*
* @return
* A boolean value indicating whether the editor has been enabled.
* See Drupal.wysiwyg.detach.none() for a full desciption of this hook.
*/
Drupal.wysiwyg.toggle.tinymce = function(element, theme) {
if (tinyMCE.getEditorId(element.id) == null) {
// Clone, so original settings are not overwritten.
var config = Drupal.wysiwyg.clone(Drupal.settings.wysiwygEditor.configs.tinymce[theme]);
// Set configuration options for this theme.
for (var setting in config) {
tinyMCE.settings[setting] = config[setting];
}
tinyMCE.addMCEControl(element, element.id);
return true;
}
else {
tinyMCE.removeMCEControl(tinyMCE.getEditorId(element.id));
return false;
Drupal.wysiwyg.detach.tinymce = function(context, params) {
if (typeof params != 'undefined') {
tinyMCE.removeMCEControl(tinyMCE.getEditorId(params.field));
$('#' + params.field).removeAttr('style');
}
// else if (tinyMCE.activeEditor) {
// tinyMCE.triggerSave();
// tinyMCE.activeEditor.remove();
// }
}
// $Id$
Drupal.wysiwyg = Drupal.wysiwyg || { 'init': {}, 'attach': {}, 'detach': {}, 'toggle': {} };
Drupal.wysiwyg = Drupal.wysiwyg || { 'init': {}, 'attach': {}, 'detach': {} };
/**
* Initialize TinyMCE instances.
* Initialize editor instances.
*
* @todo Is the following note still valid for 3.x?
* This function needs to be called before the page is fully loaded, as
......@@ -33,54 +33,37 @@ Drupal.wysiwyg.init.tinymce = function(editorSettings) {
}
/**
* Attach TinyMCE to textareas, using the theme specified in CSS class names.
* Attach this editor to a target element.
*
* @param editorSettings
* An object containing editor settings for each enabled editor theme.
* See Drupal.wysiwyg.attach.none() for a full desciption of this hook.
*/
Drupal.wysiwyg.attach.tinymce = function(context, editorSettings) {
for (var theme in editorSettings) {
// Clone, so original settings are not overwritten.
var config = Drupal.wysiwyg.clone(editorSettings[theme]);
// Configure settings for this theme.
for (var setting in config) {
tinyMCE.settings[setting] = config[setting];
}
$('textarea.wysiwyg-' + theme + ':not(.wysiwyg-processed)', context).each(function() {
// Attach Wysiwyg Editor control if default is on.
if (Drupal.settings.wysiwygEditor.status) {
tinyMCE.execCommand('mceAddControl', true, this.id);
}
$(this).addClass('wysiwyg-processed');
});
Drupal.wysiwyg.attach.tinymce = function(context, params, editorSettings) {
// Configure settings for this theme.
for (var setting in editorSettings[params.theme]) {
tinyMCE.settings[setting] = editorSettings[params.theme][setting];
}
// Attach editor control if default is on.
if (Drupal.settings.wysiwygEditor.status) {
tinyMCE.execCommand('mceAddControl', true, params.field);
}
}
/**
* Detach all TinyMCE editors.
* Detach a single or all editors.
*
* @todo Context support required to remove only certain editors (think AHAH/AJAX).
* See Drupal.wysiwyg.detach.none() for a full desciption of this hook.
*/
Drupal.wysiwyg.detach.tinymce = function(context) {
if (tinyMCE.activeEditor) {
Drupal.wysiwyg.detach.tinymce = function(context, params) {
if (typeof params != 'undefined') {
var editor = tinyMCE.get(params.field);
if (editor) {
editor.save();
editor.remove();
}
}
else if (tinyMCE.activeEditor) {
tinyMCE.triggerSave();
tinyMCE.activeEditor.remove();
}
}
/**
* Toggle editor and return new state.
*
* @param element
* The DOM element to toggle the editor for.
* @param theme
* The editor theme assigned to the element.
*
* @return
* A boolean value indicating whether the editor has been enabled.
*/
Drupal.wysiwyg.toggle.tinymce = function(element, theme) {
tinyMCE.execCommand('mceToggleEditor', false, element.id);
return !(tinyMCE.get(element.id).isHidden());
}
......@@ -166,49 +166,6 @@ function wysiwyg_editor_profile_form($form_state, $profile) {
'#description' => t('The language for the Wysiwyg Editor interface. Language codes are based on the <a href="http://www.loc.gov/standards/iso639-2/englangn.html">ISO-639-2</a> format.'),
);
$form['visibility'] = array(
'#type' => 'fieldset',
'#title' => t('Visibility'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
// If the visibility is set to PHP mode but the user doesn't have this block
// permission, don't allow them to edit nor see this PHP code
$access = user_access('use PHP for block visibility');
if ($profile->settings['access'] == 2 && !$access) {
$form['visibility'] = array();
$form['visibility']['access'] = array(
'#type' => 'value',
'#value' => 2,
);
$form['visibility']['access_pages'] = array(
'#type' => 'value',
'#value' => $profile->settings['access_pages'],
);
}
else {
$options = array(t('Show on every page except the listed pages.'), t('Show on only the listed pages.'));
$description = t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are '%blog' for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>'));
if ($access) {
$options[] = t('Show if the following PHP code returns <code>TRUE</code> (PHP-mode, experts only).');
$description .= ' '. t('If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can break your Drupal site.', array('%php' => '<?php ?>'));
}
$form['visibility']['access'] = array(
'#type' => 'radios',
'#title' => t('Show Wysiwyg Editor on specific pages'),
'#default_value' => $profile->settings['access'],
'#options' => $options,
);
$form['visibility']['access_pages'] = array(
'#type' => 'textarea',
'#title' => t('Pages'),
'#default_value' => $profile->settings['access_pages'],
'#description' => $description,
'#wysiwyg' => FALSE,
);
}
$form['buttons'] = array(
'#type' => 'fieldset',
'#title' => t('Buttons and plugins'),
......
// $Id$
Drupal.wysiwyg = Drupal.wysiwyg || { 'init': {}, 'attach': {}, 'detach': {}, 'toggle': {} };
Drupal.wysiwyg = Drupal.wysiwyg || { 'init': {}, 'attach': {}, 'detach': {} };
/**
* Initialize all editor libraries.
* Initialize editor libraries.
*
* Some editors need to be initialized before the DOM is fully loaded. The
* init hook gives them a chance to do so.
*/
Drupal.wysiwygEditorInit = function() {
Drupal.wysiwygInit = function() {
jQuery.each(Drupal.wysiwyg.init, function(editor) {
this(Drupal.settings.wysiwygEditor.configs[editor]);
});
}
/**
* Attach editors to fields.
* Attach editors to input formats and target elements (f.e. textareas).
*
* This behavior searches for input format selectors and formatting guidelines
* that have been preprocessed by Wysiwyg API. All CSS classes of those elements
* with the prefix 'wysiwyg-' are parsed into input format parameters, defining
* the configured editor, editor theme, target element id, and variable other
* properties, which are passed to the attach/detach hooks of the corresponding
* editor.
*
* Furthermore, an "enable/disable rich-text" toggle link is added after the
* target element to allow users to alter its contents in plain text.
*
* This function can be called to process AJAX-loaded content.
* This is executed once, while editor attach/detach hooks can be invoked
* multiple times.
*
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
*/
Drupal.behaviors.attachWysiwyg = function(context) {
jQuery.each(Drupal.wysiwyg.attach, function(editor) {
// Show toggle link if set.
if (Drupal.settings.wysiwygEditor.showToggle) {
for (var theme in Drupal.settings.wysiwygEditor.configs[editor]) {
$('textarea.wysiwyg-' + theme + ':not(.wysiwyg-processed)', context).each(function() {
Drupal.wysiwygEditorAttachToggleLink(this, editor, theme);
});
$('.wysiwyg:not(.wysiwyg-processed)', context).each(function() {
// Parse the element's CSS classes into parameters.
// Format is wysiwyg-name-value.
var classes = this.className.split(' ');
var params = {};
for (var i in classes) {
if (classes[i].substr(0, 8) == 'wysiwyg-') {
var parts = classes[i].split('-');
var value = parts.slice(2).join('-');
params[parts[1]] = value;
}
}
this(context, Drupal.settings.wysiwygEditor.configs[editor]);
$this = $(this);
// Directly attach this editor, if the input format is enabled or there is
// only one input format at all.
if (($this.is(':input') && $this.is(':checked')) || $this.is('div')) {
Drupal.wysiwygEditorAttachToggleLink(context, params);
Drupal.wysiwygAttach(context, params);
}
// Attach onChange handlers to input format selector elements.
// @todo To support different editors on the same page, we need to store
// the last attached editor of each target element separately.
if ($this.is(':input')) {
$this.change(function() {
Drupal.wysiwygDetach(context, params);
Drupal.wysiwygAttach(context, params);
});
}
$this.addClass('wysiwyg-processed');
});
}
/**
* Append a toggle link to an element.
* Attach an editor to a target element.
*
* This tests whether the passed in editor implements the attach hook and
* invokes it if available. Editor profile settings are cloned first, so they
* cannot be overridden. After attaching the editor, the toggle link is shown
* again, except in case we are attaching no editor.
*
* @param element
* The DOM element to toggle the editor for.
* @param editor
* The editor name assigned to the element.
* @param theme
* The editor theme assigned to the element.
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
* @param params
* An object containing input format parameters.
*/
Drupal.wysiwygEditorAttachToggleLink = function(element, editor, theme) {
var text = document.createTextNode(Drupal.settings.wysiwygEditor.status ? Drupal.settings.wysiwygEditor.disable : Drupal.settings.wysiwygEditor.enable);
var a = document.createElement('a');
$(a)
.click(function() {
Drupal.wysiwygEditorToggle(element, editor, theme);
})
.attr('id', 'wysiwyg4' + element.id)
.css('cursor', 'pointer')
.append(text);
var div = document.createElement('div');
$(div).append(a);
$(element).after(div);
Drupal.wysiwygAttach = function(context, params) {
if (typeof Drupal.wysiwyg.attach[params.editor] == 'function') {
Drupal.wysiwyg.attach[params.editor](context, params, Drupal.wysiwyg.clone(Drupal.settings.wysiwygEditor.configs[params.editor]));
$('#wysiwyg-toggle-' + params.field).show();
}
if (params.editor == 'none') {
$('#wysiwyg-toggle-' + params.field).hide();
}
}
/**
* Enable/disable the editor and change toggle link text accordingly.
* Detach all editors from a target element.
*
* Toggle implementation functions are expected to return the new state of a
* toggled editor.
* Until there is a central registry of target elements storing the currently
* attached editor, we simply invoke the detach hook of all editors to ensure
* that no editor is attached to the target element.
*
* @param element
* The DOM element to toggle the editor for.
* @param editor
* The editor name assigned to the element.
* @param theme
* The editor theme assigned to the element.
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
* @param params
* An object containing input format parameters.
*/
Drupal.wysiwygEditorToggle = function(element, editor, theme) {
if (typeof Drupal.wysiwyg.toggle[editor] == 'function') {
var new_state = Drupal.wysiwyg.toggle[editor](element, theme);
}
if (new_state) {
$('#wysiwyg4' + element.id).html(Drupal.settings.wysiwygEditor.disable).blur();
}
else {
$('#wysiwyg4' + element.id).html(Drupal.settings.wysiwygEditor.enable).blur();
}
Drupal.wysiwygDetach = function(context, params) {
jQuery.each(Drupal.wysiwyg.detach, function(editor) {
this(context, params);
});
}
/**
* Append a editor toggle link to a target element.
*
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
* @param params
* An object containing input format parameters.
*/
Drupal.wysiwygEditorAttachToggleLink = function(context, params) {
var text = document.createTextNode(Drupal.settings.wysiwygEditor.status ? Drupal.settings.wysiwygEditor.disable : Drupal.settings.wysiwygEditor.enable);
var a = document.createElement('a');
$(a).toggle(
function() {
Drupal.wysiwygDetach(context, params);
$('#wysiwyg-toggle-' + params.field).html(Drupal.settings.wysiwygEditor.enable).blur();
// After disabling the editor, re-attach default behaviors.
Drupal.wysiwyg.attach.none(context, params);
},
function() {
// Before enabling the editor, detach default behaviors.
Drupal.wysiwyg.detach.none(context, params);
Drupal.wysiwygAttach(context, params);
$('#wysiwyg-toggle-' + params.field).html(Drupal.settings.wysiwygEditor.disable).blur();
})
.attr('id', 'wysiwyg-toggle-' + params.field)
.attr('href', 'javascript:void(0);')
.append(text);
var div = document.createElement('div');
$(div).append(a);
$('#' + params.field).after(div);
}
/**
* Clone a configuration object recursively; required for certain editors.
* Clone a configuration object recursively.
*
* @param obj
* The object to clone.
......@@ -103,7 +162,7 @@ Drupal.wysiwyg.clone = function(obj) {
}
/**
* Initialize editor libraries.
* Allow certain editor libraries to initialize before the DOM is loaded.
*/
Drupal.wysiwygEditorInit();
Drupal.wysiwygInit();
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment