diff --git a/editors/js/tinymce-2.js b/editors/js/tinymce-2.js deleted file mode 100644 index 61a60ad..0000000 --- a/editors/js/tinymce-2.js +++ /dev/null @@ -1,203 +0,0 @@ -(function($) { - -/** - * 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. - * - * @param editorSettings - * An object containing editor settings for each input format. - */ -Drupal.wysiwyg.editor.init.tinymce = function(settings) { - // Initialize editor configurations. - for (var format in settings) { - tinyMCE.init(settings[format]); - if (Drupal.settings.wysiwyg.plugins[format]) { - // Load native external plugins. - // Array syntax required; 'native' is a predefined token in JavaScript. - for (var plugin in Drupal.settings.wysiwyg.plugins[format]['native']) { - tinyMCE.loadPlugin(plugin, Drupal.settings.wysiwyg.plugins[format]['native'][plugin]); - } - // Load Drupal plugins. - for (var plugin in Drupal.settings.wysiwyg.plugins[format].drupal) { - Drupal.wysiwyg.editor.instance.tinymce.addPlugin(plugin, Drupal.settings.wysiwyg.plugins[format].drupal[plugin], Drupal.settings.wysiwyg.plugins.drupal[plugin]); - } - } - } -}; - -/** - * Attach this editor to a target element. - * - * See Drupal.wysiwyg.editor.attach.none() for a full desciption of this hook. - */ -Drupal.wysiwyg.editor.attach.tinymce = function(context, params, settings) { - // Configure editor settings for this input format. - for (var setting in settings) { - tinyMCE.settings[setting] = settings[setting]; - } - - // 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. - $field = $('#' + params.field); - $field.val($field.val().replace(/(<.+?\s+class=['"][\w\s]*?)\bmceItem\b([\w\s]*?['"].*?>)/ig, '$1$2')); - - // Attach editor. - tinyMCE.execCommand('mceAddControl', true, params.field); -}; - -/** - * Detach a single or all editors. - * - * See Drupal.wysiwyg.editor.detach.none() for a full desciption of this hook. - */ -Drupal.wysiwyg.editor.detach.tinymce = function (context, params, trigger) { - if (typeof params != 'undefined') { - tinyMCE.removeMCEControl(tinyMCE.getEditorId(params.field)); - $('#' + params.field).removeAttr('style'); - } -// else if (tinyMCE.activeEditor) { -// tinyMCE.triggerSave(); -// tinyMCE.activeEditor.remove(); -// } -}; - -Drupal.wysiwyg.editor.instance.tinymce = { - addPlugin: function(plugin, settings, pluginSettings) { - if (typeof Drupal.wysiwyg.plugins[plugin] != 'object') { - return; - } - tinyMCE.addPlugin(plugin, { - - // Register an editor command for this plugin, invoked by the plugin's button. - execCommand: function(editor_id, element, command, user_interface, value) { - switch (command) { - case plugin: - if (typeof Drupal.wysiwyg.plugins[plugin].invoke == 'function') { - var ed = tinyMCE.getInstanceById(editor_id); - var data = { format: 'html', node: ed.getFocusElement(), content: ed.getFocusElement() }; - Drupal.wysiwyg.plugins[plugin].invoke(data, pluginSettings, ed.formTargetElementId); - return true; - } - } - // Pass to next handler in chain. - return false; - }, - - // Register the plugin button. - getControlHTML: function(control_name) { - switch (control_name) { - case plugin: - return tinyMCE.getButtonHTML(control_name, settings.iconTitle, settings.icon, plugin); - } - return ''; - }, - - // Load custom CSS for editor contents on startup. - initInstance: function(ed) { - if (settings.css) { - tinyMCE.importCSS(ed.getDoc(), settings.css); - } - }, - - cleanup: function(type, content) { - switch (type) { - case 'insert_to_editor': - // Attach: Replace plain text with HTML representations. - if (typeof Drupal.wysiwyg.plugins[plugin].attach == 'function') { - content = Drupal.wysiwyg.plugins[plugin].attach(content, pluginSettings, tinyMCE.selectedInstance.editorId); - content = Drupal.wysiwyg.editor.instance.tinymce.prepareContent(content); - } - break; - - case 'get_from_editor': - // Detach: Replace HTML representations with plain text. - if (typeof Drupal.wysiwyg.plugins[plugin].detach == 'function') { - content = Drupal.wysiwyg.plugins[plugin].detach(content, pluginSettings, tinyMCE.selectedInstance.editorId); - } - break; - } - // Pass through to next handler in chain - return content; - }, - - // isNode: Return whether the plugin button should be enabled for the - // current selection. - handleNodeChange: function(editor_id, node, undo_index, undo_levels, visual_aid, any_selection) { - if (node === null) { - return; - } - if (typeof Drupal.wysiwyg.plugins[plugin].isNode == 'function') { - if (Drupal.wysiwyg.plugins[plugin].isNode(node)) { - tinyMCE.switchClass(editor_id + '_' + plugin, 'mceButtonSelected'); - return true; - } - } - tinyMCE.switchClass(editor_id + '_' + plugin, 'mceButtonNormal'); - return true; - }, - - /** - * Return information about the plugin as a name/value array. - */ - getInfo: function() { - return { - longname: settings.title - }; - } - }); - }, - - openDialog: function(dialog, params) { - var editor = tinyMCE.getInstanceById(this.field); - tinyMCE.openWindow({ - file: dialog.url + '/' + this.field, - width: dialog.width, - height: dialog.height, - inline: 1 - }, params); - }, - - closeDialog: function(dialog) { - var editor = tinyMCE.getInstanceById(this.field); - tinyMCEPopup.close(); - }, - - 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: { 'name': 'mce_drupal' } - }; - var $content = $('
' + content + '
'); // No .outerHTML() in jQuery :( - jQuery.each(specialProperties, function(element, properties) { - $content.find(element).each(function() { - for (var property in properties) { - if (property == 'class') { - $(this).addClass(properties[property]); - } - else { - $(this).attr(property, properties[property]); - } - } - }); - }); - return $content.html(); - }, - - insert: function(content) { - content = this.prepareContent(content); - var editor = tinyMCE.getInstanceById(this.field); - editor.execCommand('mceInsertContent', false, content); - editor.repaint(); - } -}; - -})(jQuery); diff --git a/editors/js/tinymce-4.js b/editors/js/tinymce-4.js index 45e95b6..2c9df70 100644 --- a/editors/js/tinymce-4.js +++ b/editors/js/tinymce-4.js @@ -49,8 +49,6 @@ Drupal.wysiwyg.editor.init.tinymce = function(settings) { * See Drupal.wysiwyg.editor.attach.none() for a full desciption 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); // Remove TinyMCE's internal mceItem class, which was incorrectly added to // submitted content by Wysiwyg <2.1. TinyMCE only temporarily adds the class @@ -63,7 +61,6 @@ Drupal.wysiwyg.editor.attach.tinymce = function(context, params, settings) { $field.val($field.val().replace(/(<.+?\s+class=['"][\w\s]*?)\bmceItem\b([\w\s]*?['"].*?>)/ig, '$1$2')); // Attach editor. - // ed.render(); settings.selector = '#' + params.field; tinymce.init(settings); }; diff --git a/editors/tinymce.inc b/editors/tinymce.inc index be54892..016ab63 100644 --- a/editors/tinymce.inc +++ b/editors/tinymce.inc @@ -64,6 +64,9 @@ function wysiwyg_tinymce_editor() { ), ), '4' => array( + 'removed plugins' => array('advhr', 'advimage', 'advlink', 'inlinepopups', 'style', 'emotions', 'xhtmlxtras'), + 'removed buttons' => array('link', 'unlink', 'anchor', 'image', 'justifyleft', 'justifycenter', 'justifyright', 'justifyfull', 'forecolor', 'backcolor', 'sup', 'sub', 'code', 'charmap', 'cleanup'), + 'plugin remap callback' => '_wysiwyg_tinymce_3_to_4_plugin_remap', 'js files' => array('tinymce-4.js'), 'library path' => wysiwyg_get_path('tinymce') . '/js/tinymce', 'libraries' => array( @@ -167,14 +170,21 @@ function wysiwyg_tinymce_settings_form(&$form, &$form_state) { 'remove_linebreaks' => TRUE, // Also available, but buggy in TinyMCE 2.x: blockquote,code,dt,dd,samp. 'theme_advanced_blockformats' => 'p,address,pre,h2,h3,h4,h5,h6,div', - 'theme_advanced_styles' => '', 'theme_advanced_statusbar_location' => 'bottom', - 'theme_advanced_resizing' => TRUE, 'theme_advanced_styles' => '', + 'theme_advanced_resizing' => TRUE, 'theme_advanced_toolbar_align' => 'left', 'theme_advanced_toolbar_location' => 'top', ); } + else { + $default_settings += array( + // The advanced tab used to be the advimage plugin. + 'image_advtab' => isset($settings['buttons']['advimage']['advimage']), + 'paste_as_text' => FALSE, + 'paste_data_images' => FALSE, + ); + } $settings += $default_settings; @@ -284,6 +294,33 @@ function wysiwyg_tinymce_settings_form(&$form, &$form_state) { ); } + if (version_compare($version, '4', '>')) { + $form['image'] = array( + '#type' => 'fieldset', + '#title' => t('Image plugin'), + '#description' => t('Settings for the image plugin.'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + '#group' => 'advanced', + ); + $form['image']['image_advtab'] = array( + '#type' => 'checkbox', + '#title' => t('Advanced tab'), + '#default_value' => $settings['image_advtab'], + '#return_value' => 1, + '#description' => t('Enable the advanced tab in the image dialog.'), + ); + } + + $form['paste'] = array( + '#type' => 'fieldset', + '#title' => t('Paste plugin'), + '#description' => t('Settings for the paste plugin.'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + '#group' => 'advanced', + ); + if (version_compare($version, '3.4b1', '<')) { $form['output']['apply_source_formatting'] = array( '#type' => 'checkbox', @@ -302,14 +339,6 @@ function wysiwyg_tinymce_settings_form(&$form, &$form_state) { '#description' => t('If enabled, the editor will re-format the HTML source code. Disabling this option could avoid conflicts with other input filters.'), ); - $form['paste'] = array( - '#type' => 'fieldset', - '#title' => t('Paste plugin'), - '#description' => t('Settings for the paste plugin.'), - '#collapsible' => TRUE, - '#collapsed' => TRUE, - '#group' => 'advanced', - ); $form['paste']['paste_auto_cleanup_on_paste'] = array( '#type' => 'checkbox', '#title' => t('Process contents on paste'), @@ -319,7 +348,22 @@ function wysiwyg_tinymce_settings_form(&$form, &$form_state) { '#element_validate' => array('wysiwyg_tinymce_settings_form_validate_blockformats'), ); } - + elseif (version_compare($version, '4', '>=')) { + $form['paste']['paste_as_text'] = array( + '#type' => 'checkbox', + '#title' => t('Paste as text'), + '#default_value' => !empty($settings['paste_as_text']), + '#return_value' => 1, + '#description' => t('If enabled, the default state of the "Paste as text" edit menu option is enabled.') . ' ' . t('Uses the @setting setting internally.', array('@setting' => 'paste_as_text', '@url' => url('http://www.tinymce.com/wiki.php/Configuration:paste_as_text'))), + ); + $form['paste']['paste_data_images'] = array( + '#type' => 'checkbox', + '#title' => t('Paste inline images'), + '#default_value' => !empty($settings['paste_data_images']), + '#return_value' => 1, + '#description' => t('If enabled, users will be allowed to paste data:url (inline) images, embedding the actual images data with the text contents. This is normally not something people want, since say embedding a 600kb image will take a long time to upload, store the image in the database, block page loads, and prevent caching the image across multiple pages. Firefox is known to allow embedding images through pasting or drag and drop.') . ' ' . t('Uses the @setting setting internally.', array('@setting' => 'paste_data_images', '@url' => url('http://www.tinymce.com/wiki.php/Configuration:paste_data_images'))), + ); + } } /** @@ -413,7 +457,10 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) { 'apply_source_formatting', 'convert_fonts_to_spans', 'language', + 'image_advtab', + 'paste_as_text', 'paste_auto_cleanup_on_paste', + 'paste_data_images', 'preformatted', 'remove_linebreaks', 'theme_advanced_blockformats', @@ -475,8 +522,16 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) { $settings['extended_valid_elements'] = array(); $plugins = wysiwyg_get_plugins($editor['name']); + $removed_buttons = (!empty($editor['removed buttons']) ? $editor['removed buttons'] : array()); foreach ($config['buttons'] as $plugin => $buttons) { foreach ($buttons as $button => $enabled) { + // If buttons are listed as missing, assume the profile is for an older + // version of TinyMCE. + if (in_array($button, $removed_buttons)) { + $converted = $editor['plugin remap callback']($plugin, $button); + $plugin = $converted[0]; + $button = $converted[1]; + } // Iterate separately over buttons and extensions properties. foreach (array('buttons', 'extensions') as $type) { // Skip unavailable plugins. @@ -528,6 +583,10 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) { } if (version_compare($version, '4', '>=')) { + // The image_advtab used to be the advimage plugin. + if (empty($settings['image_advtab']) && isset($config['buttons']['advimage']['advimage'])) { + $settings['image_advtab'] = TRUE; + } $settings += array( 'resize' => isset($config['resizing']) ? $config['resizing'] : 1, ); @@ -537,6 +596,11 @@ function wysiwyg_tinymce_settings($editor, $config, $theme) { $settings['toolbar'][] = $settings['buttons'][$i]; } } + // TinyMCE 3 allowed the callback to be the name of a funciton. Convert it + // to a reference to keep compatibility with IMCE Wysiwyg bridge module. + if (is_string($settings['file_browser_callback'])) { + $settings['file_browser_callback'] = wysiwyg_wrap_js_callback($settings['file_browser_callback']); + } } // Add theme-specific settings. @@ -888,12 +952,12 @@ function wysiwyg_tinymce_plugins($editor) { } if (version_compare($editor['installed version'], '4', '>=')) { - $removedPlugins = array('advhr', 'advimage', 'advlink', 'inlinepopups', 'style', 'emotions', 'xhtmlxtras'); - foreach ($removedPlugins as $plugin) { + $removed_plugins = $editor['removed plugins']; + foreach ($removed_plugins as $plugin) { unset($plugins[$plugin]); } - $removedDefaultButtons = array('link', 'unlink', 'anchor', 'image', 'justifyleft', 'justifycenter', 'justifyright', 'justifyfull', 'forecolor', 'backcolor', 'sup', 'sub', 'code', 'charmap', 'cleanup'); - foreach ($removedDefaultButtons as $button) { + $removed_default_buttons = $editor['removed buttons']; + foreach ($removed_default_buttons as $button) { unset($plugins['default']['buttons'][$button]); } @@ -977,3 +1041,36 @@ function wysiwyg_tinymce_plugins($editor) { return $plugins; } +/** + * Callback for converting plugins and buttons between TinyMCE 3 and 4. + */ +function _wysiwyg_tinymce_3_to_4_plugin_remap($plugin, $button) { + switch ($button) { + case 'link': + case 'unlink': + return array('link', $button); + case 'justifyleft': + return array('default', 'alignleft'); + case 'justifyright': + return array('default', 'alignright'); + case 'justifycenter': + return array('default', 'aligncenter'); + case 'justinfyfull': + return array('default', 'aligncenter'); + case 'anchor': + case 'image': + case 'code': + case 'charmap': + case 'cleanup': + case 'hr': + return array($button, $button); + case 'sup': + return array('default', 'superscript'); + case 'sub': + return array('default', 'subscript'); + case 'selectall': + return array('default', 'selectall'); + default: + return array($plugin, $button); + } +}