(function($) { CKEDITOR.disableAutoInline = true; // Exclude every id starting with 'cke_' in ajax_html_ids during AJAX requests. Drupal.wysiwyg.excludeIdSelectors.wysiwyg_ckeditor = ['[id^="cke_"]']; // Keeps track of private instance data. var instanceMap; /** * Initialize the editor library. * * This method is called once the first time a library is needed. If new * WYSIWYG fields are added later, update() will be called instead. * * @param settings * An object containing editor settings for each input format. * @param pluginInfo * An object containing global plugin configuration. */ Drupal.wysiwyg.editor.init.ckeditor = function(settings, pluginInfo) { instanceMap = {}; // Nothing to do here other than register new plugins etc. Drupal.wysiwyg.editor.update.ckeditor(settings, pluginInfo); }; /** * Update the editor library when new settings are available. * * This method is called instead of init() when at least one new WYSIWYG field * has been added to the document and the library has already been initialized. * * $param settings * An object containing editor settings for each input format. * $param pluginInfo * An object containing global plugin configuration. */ Drupal.wysiwyg.editor.update.ckeditor = function(settings, pluginInfo) { // Register native external plugins. // Array syntax required; 'native' is a predefined token in JavaScript. for (var pluginId in pluginInfo['native']) { if (pluginInfo['native'].hasOwnProperty(pluginId) && (!CKEDITOR.plugins.externals || !CKEDITOR.plugins.externals[pluginId])) { var plugin = pluginInfo['native'][pluginId]; CKEDITOR.plugins.addExternal(pluginId, plugin.path, plugin.fileName); } } // Build and register Drupal plugin wrappers. for (var pluginId in pluginInfo.drupal) { if (pluginInfo.drupal.hasOwnProperty(pluginId) && (!CKEDITOR.plugins.registered || !CKEDITOR.plugins.registered[pluginId])) { Drupal.wysiwyg.editor.instance.ckeditor.addPlugin(pluginId, pluginInfo.drupal[pluginId]); } } // Register Font styles (versions 3.2.1 and above). for (var format in settings) { if (settings[format].stylesSet && (!CKEDITOR.stylesSet || !CKEDITOR.stylesSet.registered[format])) { CKEDITOR.stylesSet.add(format, settings[format].stylesSet); } } }; /** * Attach this editor to a target element. */ Drupal.wysiwyg.editor.attach.ckeditor = function(context, params, settings) { // Apply editor instance settings. CKEDITOR.config.customConfig = ''; var $drupalToolbars = $('#toolbar, #admin-menu', Drupal.overlayChild ? window.parent.document : document); if (!settings.height) { settings.height = $('#' + params.field).height(); } settings.on = { instanceReady: function(ev) { var editor = ev.editor; // Get a list of block, list and table tags from CKEditor's XHTML DTD. // @see http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Output_Formatting. var dtd = CKEDITOR.dtd; var tags = CKEDITOR.tools.extend({}, dtd.$block, dtd.$listItem, dtd.$tableContent); // Set source formatting rules for each listed tag except
.
      // Linebreaks can be inserted before or after opening and closing tags.
      if (settings.simple_source_formatting) {
        // Mimic FCKeditor output, by breaking lines between tags.
        for (var tag in tags) {
          if (tag == 'pre') {
            continue;
          }
          this.dataProcessor.writer.setRules(tag, {
            indent: true,
            breakBeforeOpen: true,
            breakAfterOpen: false,
            breakBeforeClose: false,
            breakAfterClose: true
          });
        }
      }
      else {
        // CKEditor adds default formatting to 
, so we want to remove that // here too. tags.br = 1; // No indents or linebreaks; for (var tag in tags) { if (tag == 'pre') { continue; } this.dataProcessor.writer.setRules(tag, { indent: false, breakBeforeOpen: false, breakAfterOpen: false, breakBeforeClose: false, breakAfterClose: false }); } } }, pluginsLoaded: function(ev) { var wysiwygInstance = instanceMap[this.name]; var enabledPlugins = wysiwygInstance.pluginInfo.instances.drupal; // Override the conversion methods to let Drupal plugins modify the data. var editor = ev.editor; if (editor.dataProcessor && enabledPlugins) { editor.dataProcessor.toHtml = CKEDITOR.tools.override(editor.dataProcessor.toHtml, function(originalToHtml) { // Convert raw data for display in WYSIWYG mode. return function(data, fixForBody) { for (var plugin in enabledPlugins) { if (typeof Drupal.wysiwyg.plugins[plugin].attach == 'function') { data = Drupal.wysiwyg.plugins[plugin].attach(data, wysiwygInstance.pluginInfo.global.drupal[plugin], editor.name); data = wysiwygInstance.prepareContent(data); } } return originalToHtml.call(this, data, fixForBody); }; }); editor.dataProcessor.toDataFormat = CKEDITOR.tools.override(editor.dataProcessor.toDataFormat, function(originalToDataFormat) { // Convert WYSIWYG mode content to raw data. return function(data, fixForBody) { data = originalToDataFormat.call(this, data, fixForBody); for (var plugin in enabledPlugins) { if (typeof Drupal.wysiwyg.plugins[plugin].detach == 'function') { data = Drupal.wysiwyg.plugins[plugin].detach(data, wysiwygInstance.pluginInfo.global.drupal[plugin], editor.name); } } return data; }; }); } }, selectionChange: function (event) { var wysiwygInstance = instanceMap[this.name]; var enabledPlugins = wysiwygInstance.pluginInfo.instances.drupal; for (var name in enabledPlugins) { var plugin = Drupal.wysiwyg.plugins[name]; if ($.isFunction(plugin.isNode)) { var node = event.data.selection.getSelectedElement(); var state = plugin.isNode(node ? node.$ : null) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF; event.editor.getCommand(name).setState(state); } } }, focus: function(ev) { Drupal.wysiwyg.activeId = ev.editor.name; }, afterCommandExec: function(ev) { // Fix Drupal toolbar obscuring editor toolbar in fullscreen mode. if (ev.data.name != 'maximize') { return; } if (ev.data.command.state == CKEDITOR.TRISTATE_ON) { $drupalToolbars.hide(); } else { $drupalToolbars.show(); } }, destroy: function (event) { // Free our reference to the private instance to not risk memory leaks. delete instanceMap[this.name]; } }; instanceMap[params.field] = this; // Attach editor. var editorInstance = CKEDITOR.replace(params.field, settings); }; /** * Detach a single editor instance. */ Drupal.wysiwyg.editor.detach.ckeditor = function (context, params, trigger) { var method = (trigger == 'serialize') ? 'updateElement' : 'destroy'; var instance = CKEDITOR.instances[params.field]; if (!instance) { return; } instance[method](); }; Drupal.wysiwyg.editor.instance.ckeditor = { addPlugin: function (pluginName, pluginSettings) { CKEDITOR.plugins.add(pluginName, { // Wrap Drupal plugin in a proxy plugin. init: function(editor) { if (pluginSettings.css) { editor.on('mode', function(ev) { if (ev.editor.mode == 'wysiwyg') { // Inject CSS files directly into the editing area head tag. var iframe = $('#cke_contents_' + ev.editor.name + ' iframe, #' + ev.editor.id + '_contents iframe'); $('head', iframe.eq(0).contents()).append(''); } }); } if (typeof Drupal.wysiwyg.plugins[pluginName].invoke == 'function') { var pluginCommand = { exec: function (editor) { var data = { format: 'html', node: null, content: '' }; var selection = editor.getSelection(); if (selection) { data.node = selection.getSelectedElement(); if (data.node) { data.node = data.node.$; } if (selection.getType() == CKEDITOR.SELECTION_TEXT) { if (selection.getSelectedText) { data.content = selection.getSelectedText(); } else { // Pre v3.6.1. if (CKEDITOR.env.ie) { data.content = selection.getNative().createRange().text; } else { data.content = selection.getNative().toString(); } } } else if (data.node) { // content is supposed to contain the "outerHTML". data.content = data.node.parentNode.innerHTML; } } Drupal.wysiwyg.plugins[pluginName].invoke(data, pluginSettings, editor.name); } }; editor.addCommand(pluginName, pluginCommand); } editor.ui.addButton(pluginName, { label: pluginSettings.title, command: pluginName, icon: pluginSettings.icon }); // @todo Add button state handling. } }); }, prepareContent: function(content) { // @todo Don't know if we need this yet. return content; }, insert: function(content) { content = this.prepareContent(content); if (CKEDITOR.version.split('.')[0] === '3' && (CKEDITOR.env.webkit || CKEDITOR.env.chrome || CKEDITOR.env.opera || CKEDITOR.env.safari)) { // Works around a WebKit bug which removes wrapper elements. // @see https://drupal.org/node/1927968 var tmp = new CKEDITOR.dom.element('div'), children, skip = 0, item; tmp.setHtml(content); children = tmp.getChildren(); skip = 0; while (children.count() > skip) { item = children.getItem(skip); switch(item.type) { case 1: CKEDITOR.instances[this.field].insertElement(item); break; case 3: CKEDITOR.instances[this.field].insertText(item.getText()); skip++; break; case 8: CKEDITOR.instances[this.field].insertHtml(item.getOuterHtml()); skip++; break; } } } else { CKEDITOR.instances[this.field].insertHtml(content); } }, setContent: function (content) { CKEDITOR.instances[this.field].setData(content); }, getContent: function () { return CKEDITOR.instances[this.field].getData(); }, isFullscreen: function () { var cmd = CKEDITOR.instances[this.field].commands.maximize; return !!(cmd && cmd.state == CKEDITOR.TRISTATE_ON); } }; })(jQuery); ;/*})'"*/ ;/*})'"*/ (function($) { /** * 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.editor.attach.none = function(context, params, settings) { if (params.resizable) { var $wrapper = $('#' + params.field, context).parents('.form-textarea-wrapper:first'); $wrapper.addClass('resizable'); if (Drupal.behaviors.textarea) { Drupal.behaviors.textarea.attach(context); } } }; /** * Detach a single editor instance. * * The editor syncs its contents back to the original field before its instance * is removed. * * In here, 'this' is an instance of WysiwygInternalInstance. * See Drupal.wysiwyg.editor.instance.none for more details. * * @param context * A DOM element, supplied by Drupal.attachBehaviors(). * @param params * An object containing input format parameters. Only the editor instance in * params.field should be detached and saved, so its data can be submitted in * AJAX/AHAH applications. * @param trigger * A string describing why the editor is being detached. * Possible triggers are: * - unload: (default) Another or no editor is about to take its place. * - move: Currently expected to produce the same result as unload. * - serialize: The form is about to be serialized before an AJAX request or * a normal form submission. If possible, perform a quick detach and leave * the editor's GUI elements in place to avoid flashes or scrolling issues. * @see Drupal.detachBehaviors */ Drupal.wysiwyg.editor.detach.none = function (context, params, trigger) { if (trigger != 'serialize') { var $wrapper = $('#' + params.field, context).parents('.form-textarea-wrapper:first'); $wrapper.removeOnce('textarea').removeClass('.resizable-textarea').removeClass('resizable') .find('.grippie').remove(); } }; /** * Instance methods for plain text areas. */ Drupal.wysiwyg.editor.instance.none = { insert: function(content) { var editor = document.getElementById(this.field); // IE support. if (document.selection) { editor.focus(); var sel = document.selection.createRange(); sel.text = content; } // Mozilla/Firefox/Netscape 7+ support. else if (editor.selectionStart || editor.selectionStart == '0') { var startPos = editor.selectionStart; var endPos = editor.selectionEnd; editor.value = editor.value.substring(0, startPos) + content + editor.value.substring(endPos, editor.value.length); } // Fallback, just add to the end of the content. else { editor.value += content; } }, setContent: function (content) { $('#' + this.field).val(content); }, getContent: function () { return $('#' + this.field).val(); } }; })(jQuery); ;/*})'"*/ ;/*})'"*/ Drupal.wysiwyg.plugins.linebreaks = { invoke: function(data, settings, instanceId) { alert('This button does nothing, it belongs to the linebreaks plugin.'); }, attach: function(content, settings, instanceId) { content = this.linebreaks_attach(content); return content; }, detach: function(content, settings, instanceId) { content = this.linebreaks_detach(content); return content; }, // Clean up content for saving or turning off WYSIWYG. linebreaks_detach : function(content) { var blocklist1, blocklist2, blocklist3; // Protect pre|script tags. content = content.replace(/<(pre|script|li)[^>]*>[\s\S]+?<\/\1>/g, function(a) { a = a.replace(/
[\r\n]*/g, ''); return a.replace(/<\/?p( [^>]*)?>[\r\n]*/g, ''); }); // Pretty it up for the source editor. blocklist1 = 'blockquote|ul|ol|li|hr|table|thead|tbody|tr|th|td|div|h[1-6]|p'; content = content.replace(new RegExp('\\s*\\s*', 'mg'), '\n'); content = content.replace(new RegExp('\\s*<(('+blocklist1+')[^>]*)>', 'mg'), '\n<$1>'); // Mark

if it has any attributes. content = content.replace(new RegExp('(

]+>.*?)

', 'mg'), '$1'); // Separate
containing

. content = content.replace(new RegExp(']*)>\\s*

', 'mgi'), '\n'); // Remove

and
. // content = content.replace(new RegExp('\\s*

', 'mgi'), ''); // content = content.replace(new RegExp('\\s*

\\s*', 'mgi'), '\n\n'); // content = content.replace(new RegExp('\\n\\s*\\n', 'mgi'), '\n\n'); // content = content.replace(new RegExp('\\s*
\\s*', 'gi'), '\n'); // Fix some block element newline issues. content = content.replace(new RegExp('\\s*\\s*', 'mg'), '
\n'); content = content.replace(new RegExp('\\s*\\[caption([^\\[]+)\\[/caption\\]\\s*', 'gi'), '\n\n[caption$1[/caption]\n\n'); content = content.replace(new RegExp('caption\\]\\n\\n+\\[caption', 'g'), 'caption]\n\n[caption'); // Block elements which look nicer with two newlines before and after. blocklist2 = 'blockquote|ul|ol|table|h[1-6]|pre'; content = content.replace(new RegExp('\\s*<(('+blocklist2+') ?[^>]*)\\s*>', 'mg'), '\n<$1>'); content = content.replace(new RegExp('\\s*\\s*', 'mg'), '\n'); content = content.replace(new RegExp('\\s*<(hr ?[^>]*)\\s*>', 'mg'), '\n<$1>'); // Block elements which look nicer with one newline before and after. blocklist3 = 'li|thead|tr|th|td'; content = content.replace(new RegExp('\\s*<(('+blocklist3+') ?[^>]*)\\s*>', 'mg'), '\n<$1>'); content = content.replace(new RegExp('\\s*\\s*', 'mg'), '\n'); // content = content.replace(new RegExp(']*)>', 'g'), '\t'); // Handle and tags. if (content.indexOf('/g, function(a){ return a.replace(/[\r\n]+/g, ''); }); } if (content.indexOf('/g, function(a){ return a.replace(/[\r\n]+/g, ''); }); } // Unmark special paragraph closing tags. content = content.replace(new RegExp('', 'g'), '

\n'); content = content.replace(new RegExp('\\s*(

]+>.*

)', 'mg'), '\n$1'); // Trim whitespace. content = content.replace(new RegExp('^\\s*', ''), ''); content = content.replace(new RegExp('[\\s\\u00a0]*$', ''), ''); // Put back linebreaks in
 and