(function($) { /** * Initialize editor instances. * * @see Drupal.wysiwyg.editor.init.ckeditor() */ Drupal.wysiwyg.editor.init.tinymce = function(settings, pluginInfo) { // Fix Drupal toolbar obscuring editor toolbar in fullscreen mode. tinyMCE.onAddEditor.add(function (mgr, ed) { if (ed.id == 'mce_fullscreen') { Drupal.wysiwyg.utilities.onFullscreenEnter(); } }); tinyMCE.onRemoveEditor.add(function (mgr, ed) { if (ed.id == 'mce_fullscreen') { Drupal.wysiwyg.utilities.onFullscreenExit(); } else { // Free our reference to the private instance to not risk memory leaks. delete ed._drupalWysiwygInstance; } }); // Register new plugins. Drupal.wysiwyg.editor.update.tinymce(settings, pluginInfo); }; /** * Update the editor library when new settings are available. * * @see Drupal.wysiwyg.editor.update.ckeditor() */ Drupal.wysiwyg.editor.update.tinymce = function(settings, pluginInfo) { // Load native external plugins. // Array syntax required; 'native' is a predefined token in JavaScript. for (var plugin in pluginInfo['native']) { if (!(plugin in tinymce.PluginManager.lookup || plugin in tinymce.PluginManager.urls)) { tinymce.PluginManager.load(plugin, pluginInfo['native'][plugin]); } } // Load Drupal plugins. for (var plugin in pluginInfo.drupal) { if (!(plugin in tinymce.PluginManager.lookup)) { Drupal.wysiwyg.editor.instance.tinymce.addPlugin(plugin, pluginInfo.drupal[plugin]); } } }; /** * Attach this editor to a target element. * * See Drupal.wysiwyg.editor.attach.none() for a full description of this hook. */ Drupal.wysiwyg.editor.attach.tinymce = function(context, params, settings) { // Configure editor settings for this input format. var ed = new tinymce.Editor(params.field, settings); ed._drupalWysiwygInstance = this; // Reset active instance id on any event. ed.onEvent.add(function(ed, e) { Drupal.wysiwyg.activeId = ed.id; }); // Indicate that the DOM has been loaded (in case of Ajax). tinymce.dom.Event.domLoaded = true; // Make toolbar buttons wrappable (required for IE). ed.onPostRender.add(function (ed) { var $toolbar = $('
'); $('#' + ed.editorContainer + ' table.mceToolbar > tbody > tr > td').each(function () { $('').addClass(this.className).append($(this).children()).appendTo($toolbar); }); $('#' + ed.editorContainer + ' table.mceLayout td.mceToolbar').append($toolbar); $('#' + ed.editorContainer + ' table.mceToolbar').remove(); ed.onChange.add(function (ed) { ed._drupalWysiwygInstance.contentsChanged(); }); }); // Remove TinyMCE's internal mceItem class, which was incorrectly added to // submitted content by Wysiwyg <2.1. TinyMCE only temporarily adds the class // for placeholder elements. If preemptively set, the class prevents (native) // editor plugins from gaining an active state, so we have to manually remove // it prior to attaching the editor. This is done on the client-side instead // of the server-side, as Wysiwyg has no way to figure out where content is // stored, and the class only affects editing. var $field = $('#' + params.field); $field.val($field.val().replace(/(<.+?\s+class=['"][\w\s]*?)\bmceItem\b([\w\s]*?['"].*?>)/ig, '$1$2')); // Attach editor. ed.render(); if (tinymce.minorVersion == '5.7') { // Work around a TinyMCE bug hiding new instances when switching to them. // @see http://www.tinymce.com/develop/bugtracker_view.php?id=5510 setTimeout(function () { tinymce.DOM.show(ed.editorContainer); }, 1); } }; /** * Detach a single editor instance. * * See Drupal.wysiwyg.editor.detach.none() for a full description of this hook. */ Drupal.wysiwyg.editor.detach.tinymce = function (context, params, trigger) { var instance = tinyMCE.get(params.field); if (!instance) { return; } instance.save(); if (trigger !== 'serialize') { // The onRemove event fires before this returns. instance.remove(); } }; Drupal.wysiwyg.editor.instance.tinymce = { addPlugin: function(plugin, pluginSettings) { if (typeof Drupal.wysiwyg.plugins[plugin] != 'object') { return; } tinymce.create('tinymce.plugins.drupal_' + plugin, { /** * Initialize the plugin, executed after the plugin has been created. * * @param ed * The tinymce.Editor instance the plugin is initialized in. * @param url * The absolute URL of the plugin location. */ init: function(ed, url) { // Register an editor command for this plugin, invoked by the plugin's button. ed.addCommand('drupal_' + plugin, function() { if (typeof Drupal.wysiwyg.plugins[plugin].invoke == 'function') { var data = { format: 'html', node: ed.selection.getNode(), content: ed.selection.getContent() }; // TinyMCE creates a completely new instance for fullscreen mode. var instanceId = ed.id == 'mce_fullscreen' ? ed.getParam('fullscreen_editor_id') : ed.id; Drupal.wysiwyg.plugins[plugin].invoke(data, pluginSettings, instanceId); } }); // Register the plugin button. ed.addButton('drupal_' + plugin, { title : pluginSettings.title, cmd : 'drupal_' + plugin, image : pluginSettings.icon }); // Load custom CSS for editor contents on startup. ed.onInit.add(function() { if (pluginSettings.css) { ed.dom.loadCSS(pluginSettings.css); } }); // Attach: Replace plain text with HTML representations. ed.onBeforeSetContent.add(function(ed, data) { var editorId = (ed.id == 'mce_fullscreen' ? ed.getParam('fullscreen_editor_id') : ed.id); if (typeof Drupal.wysiwyg.plugins[plugin].attach == 'function') { data.content = Drupal.wysiwyg.plugins[plugin].attach(data.content, pluginSettings, editorId); // Get the instance from the id to work around fullscreen mode. data.content = tinymce.get(editorId)._drupalWysiwygInstance.prepareContent(data.content); } }); // Detach: Replace HTML representations with plain text. ed.onGetContent.add(function(ed, data) { var editorId = (ed.id == 'mce_fullscreen' ? ed.getParam('fullscreen_editor_id') : ed.id); if (typeof Drupal.wysiwyg.plugins[plugin].detach == 'function') { data.content = Drupal.wysiwyg.plugins[plugin].detach(data.content, pluginSettings, editorId); } }); // isNode: Return whether the plugin button should be enabled for the // current selection. ed.onNodeChange.add(function(ed, command, node) { if (typeof Drupal.wysiwyg.plugins[plugin].isNode == 'function') { command.setActive('drupal_' + plugin, Drupal.wysiwyg.plugins[plugin].isNode(node)); } }); }, /** * Return information about the plugin as a name/value array. */ getInfo: function() { return { longname: pluginSettings.title }; } }); // Register plugin. tinymce.PluginManager.add('drupal_' + plugin, tinymce.plugins['drupal_' + plugin]); }, openDialog: function(dialog, params) { var instanceId = this.getInstanceId(); var editor = tinyMCE.get(instanceId); editor.windowManager.open({ file: dialog.url + '/' + instanceId, width: dialog.width, height: dialog.height, inline: 1 }, params); }, closeDialog: function(dialog) { var editor = tinyMCE.get(this.getInstanceId()); editor.windowManager.close(dialog); }, prepareContent: function(content) { // Certain content elements need to have additional DOM properties applied // to prevent this editor from highlighting an internal button in addition // to the button of a Drupal plugin. var specialProperties = { img: { 'class': 'mceItem' } }; var $content = $('