diff --git a/core/modules/ckeditor/ckeditor.admin.inc b/core/modules/ckeditor/ckeditor.admin.inc index 0dff9f5..7e6bda7 100644 --- a/core/modules/ckeditor/ckeditor.admin.inc +++ b/core/modules/ckeditor/ckeditor.admin.inc @@ -57,7 +57,7 @@ $value = $button['image_alternative' . $rtl]; } elseif (isset($button['image'])) { - $value = theme('image', array('uri' => $button['image' . $rtl], 'title' => $button['label'])); + $value = '' . theme('image', array('uri' => $button['image' . $rtl], 'title' => $button['label'])) . ''; } else { $value = '?'; diff --git a/core/modules/ckeditor/ckeditor.module b/core/modules/ckeditor/ckeditor.module index c53fefa..5676cc6 100644 --- a/core/modules/ckeditor/ckeditor.module +++ b/core/modules/ckeditor/ckeditor.module @@ -20,9 +20,12 @@ 'title' => 'Drupal behavior to enable CKEditor on textareas.', 'version' => VERSION, 'js' => array( - $module_path . '/js/ckeditor.js' => array(), + $module_path . '/js/ckeditor.js' => array('group' => JS_DEFAULT), array('data' => $settings, 'type' => 'setting'), ), + 'css' => array( + $module_path . '/css/ckeditor.css' => array(), + ), 'dependencies' => array( array('system', 'drupal'), array('ckeditor', 'ckeditor'), diff --git a/core/modules/ckeditor/css/ckeditor.admin.css b/core/modules/ckeditor/css/ckeditor.admin.css index 272e3ea..41af514 100644 --- a/core/modules/ckeditor/css/ckeditor.admin.css +++ b/core/modules/ckeditor/css/ckeditor.admin.css @@ -85,8 +85,10 @@ text-indent: -9999px; width: 16px; } -ul.ckeditor-buttons li a:focus { +ul.ckeditor-buttons li a:focus, +ul.ckeditor-multiple-buttons li a:focus { z-index: 11; /* Ensure focused buttons show their outline on all sides. */ + outline: 1px dotted #333; } ul.ckeditor-buttons li:first-child a { border-top-left-radius: 2px; /* LTR */ diff --git a/core/modules/ckeditor/css/ckeditor.css b/core/modules/ckeditor/css/ckeditor.css new file mode 100644 index 0000000..08d5716 --- /dev/null +++ b/core/modules/ckeditor/css/ckeditor.css @@ -0,0 +1,19 @@ +.ckeditor-dialog-loading { + position: absolute; + top: 0; + width: 100%; + text-align: center; +} + +.ckeditor-dialog-loading-link { + border-radius: 0 0 5px 5px; + border: 1px solid #B6B6B6; + border-top: none; + background: white; + padding: 3px 10px; + box-shadow: 0 0 10px -3px #000; + display: inline-block; + font-size: 14px; + position: relative; + top: 0; +} diff --git a/core/modules/ckeditor/js/ckeditor.js b/core/modules/ckeditor/js/ckeditor.js index f5d4317..19c6689 100644 --- a/core/modules/ckeditor/js/ckeditor.js +++ b/core/modules/ckeditor/js/ckeditor.js @@ -100,4 +100,83 @@ }; +Drupal.ckeditor = { + /** + * Variable storing the current dialog's save callback. + */ + saveCallack: null, + + /** + * Open a dialog for a Drupal-based plugin. + * + * This dynamically loads jQuery UI (if necessary) using the Drupal AJAX + * framework, then opens a dialog at the specified Drupal path. + * + * @param editor + * The CKEditor instance that is opening the dialog. + * @param options + * An object of options that affect the behavior of the dialog. Possible + * options include: + * - callback: A function to be called upon saving the dialog. + */ + openDialog: function (editor, url, existingValues, saveCallback, modalSettings) { + // Locate a suitable place to display our loading indicator. + var $target = $(editor.container.$); + if (editor.elementMode === CKEDITOR.ELEMENT_MODE_REPLACE) { + $target = $target.find('.cke_contents'); + } + + // Remove any previous loading indicator. + $target.css('position', 'relative').find('.ckeditor-dialog-loading').remove(); + + // Generate a pseudo-AJAX object for ajax.js to use in making this request. + Drupal.settings.ajax = Drupal.settings.ajax || {}; + Drupal.settings.ajax['ckeditor-dialog'] = { + accepts: 'application/vnd.drupal-modal', + selector: '.ckeditor-dialog-loading-link a', + url: url, + event: 'click', + progress: { 'type': 'throbber' }, + submit: { + editor_object: existingValues + } + }; + + // Add a new AJAX link, click it, then display it while loading. + var $content = $('
' + Drupal.t('Loading...') + '
'); + $content.appendTo($target); + Drupal.attachBehaviors($content[0]); + $content.find('a').trigger('click'); + + // After a short delay, show the loading throbber. + window.setTimeout(function() { + $content.find('span').animate({ top: '0px' }); + }, 250); + + // Store the save callback to be executed when this dialog is closed. + Drupal.ckeditor.saveCallback = saveCallback; + } +}; + +// Respond to new dialogs that are opened by CKEditor, closing the AJAX loader. +$(window).on('dialog:beforecreate', function(e, dialog, $element, settings) { + $('.ckeditor-dialog-loading').animate({ top: '-40px' }, function() { + $(this).remove(); + }); +}); + +// Respond to dialogs that are saved, sending data back to CKEditor. +$(window).on('editor:dialogsave', function(e, values) { + if (Drupal.ckeditor.saveCallback) { + Drupal.ckeditor.saveCallback(values); + } +}); + +// Respond to dialogs that are closed, removing the current save handler. +$(window).on('dialog:afterclose', function(e, dialog, $element, values) { + if (Drupal.ckeditor.saveCallback) { + Drupal.ckeditor.saveCallback = null; + } +}); + })(Drupal, CKEDITOR, jQuery); diff --git a/core/modules/ckeditor/js/plugins/drupalimage/plugin.js b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js new file mode 100644 index 0000000..e8c0122 --- /dev/null +++ b/core/modules/ckeditor/js/plugins/drupalimage/plugin.js @@ -0,0 +1,126 @@ +/** + * @file + * Drupal Image plugin. + */ + +(function ($, Drupal, drupalSettings, CKEDITOR) { + +"use strict"; + +CKEDITOR.plugins.add('drupalimage', { + init: function (editor) { + var pluginName = 'drupalimage'; + + // Register the toolbar button. + editor.ui.addButton('DrupalImage', { + label: editor.lang.common.image, + command: 'image', + icon: drupalSettings.basePath + drupalSettings.ckeditor.modulePath + '/js/plugins/drupalimage/image.png' + }); + + // Register the image command. + editor.addCommand('image', { + allowedContent: 'img[alt,src,width,height,class,id,lang,longdesc,title]', + requiredContent: 'img[alt,src,width,height]', + exec: function (editor) { + var imageElement = getSelectedImage(editor); + var imageDOMElement = null; + var existingValues = {}; + if (imageElement && imageElement.$) { + imageDOMElement = imageElement.$; + + // Width and height are populated by actual dimensions. + existingValues.width = imageDOMElement ? imageDOMElement.width : ''; + existingValues.height = imageDOMElement ? imageDOMElement.height : ''; + // Populate all other attributes by their specified attribute values. + var attribute = null; + for (var key = 0; key < imageDOMElement.attributes.length; key++) { + attribute = imageDOMElement.attributes.item(key); + existingValues[attribute.nodeName.toLowerCase()] = attribute.nodeValue; + } + } + + var saveCallback = function(returnValues) { + // Create a new image element if needed. + if (!imageElement && returnValues['attributes']['src']) { + imageElement = editor.document.createElement('img'); + imageElement.setAttribute('alt', ''); + editor.insertElement(imageElement); + } + // Delete the image if the src was removed. + if (imageElement && !returnValues['attributes']['src']) { + imageElement.remove(); + } + // Update the image properties. + else { + for (var key in returnValues['attributes']) { + if (returnValues['attributes'].hasOwnProperty(key)) { + // Update the property if a value is specified. + if (returnValues['attributes'][key].length > 0) { + imageElement.setAttribute(key, returnValues['attributes'][key]); + } + // Delete the property if set to an empty string. + else { + imageElement.removeAttribute(key); + } + } + } + } + }; + var modalSettings = { + dialogClass: 'editor-image-dialog', + }; + Drupal.ckeditor.openDialog(editor, editor.config.drupalImage_dialogUrl, existingValues, saveCallback, modalSettings); + }, + modes: { wysiwyg : 1 }, + canUndo: true + }); + + // Double clicking an image opens its properties. + editor.on('doubleclick', function(event) { + var element = event.data.element; + if (element.is('img') && !element.data('cke-realelement') && !element.isReadOnly()) { + editor.getCommand('image').exec(); + } + }); + + // If the "menu" plugin is loaded, register the menu items. + if (editor.addMenuItems) { + editor.addMenuItems({ + image: { + label: editor.lang.image.menu, + command : 'image', + group: 'image' + } + }); + } + + // If the "contextmenu" plugin is loaded, register the listeners. + if (editor.contextMenu) { + editor.contextMenu.addListener(function (element, selection) { + if (getSelectedImage(editor, element)) { + return { image: CKEDITOR.TRISTATE_OFF }; + } + }); + } + } +}); + +/** + * Finds an img tag anywhere in the current editor selection. + */ +function getSelectedImage (editor, element) { + if (!element) { + var sel = editor.getSelection(); + var selectedText = sel.getSelectedText().replace(/^\s\s*/, '').replace(/\s\s*$/, ''); + var isElement = sel.getType() === CKEDITOR.SELECTION_ELEMENT; + var isEmptySelection = sel.getType() === CKEDITOR.SELECTION_TEXT && selectedText.length === 0; + element = (isElement || isEmptySelection) && sel.getSelectedElement(); + } + + if (element && element.is('img') && !element.data('cke-realelement') && !element.isReadOnly()) { + return element; + } +} + +})(jQuery, Drupal, drupalSettings, CKEDITOR); diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginBase.php b/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginBase.php index 4050be1..445d9c4 100644 --- a/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginBase.php +++ b/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginBase.php @@ -39,4 +39,17 @@ return FALSE; } + /** + * Implements \Drupal\ckeditor\Plugin\CKEditorPluginInterface::getDependencies(). + */ + function getDependencies(Editor $editor) { + return array(); + } + + /** + * Implements \Drupal\ckeditor\Plugin\CKEditorPluginInterface::getLibraries(). + */ + function getLibraries(Editor $editor) { + return array(); + } } diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginInterface.php b/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginInterface.php index 601cafb..58c83ac 100644 --- a/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginInterface.php +++ b/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginInterface.php @@ -41,6 +41,31 @@ public function isInternal(); /** + * Returns a list of plugins this plugin requires. + * + * @param \Drupal\editor\Plugin\Core\Entity\Editor $editor + * A configured text editor object. + * @return array + * An unindexed array of plugin names this plugin requires. Each plugin is + * is identified by its annotated ID. + */ + public function getDependencies(Editor $editor); + + /** + * Returns a list of libraries this plugin requires. + * + * These libraries will be attached to the text_format element on which the + * editor is being loaded. + * + * @param \Drupal\editor\Plugin\Core\Entity\Editor $editor + * A configured text editor object. + * @return array + * An array of libraries suitable for usage in a render API #attached + * property. + */ + public function getLibraries(Editor $editor); + + /** * Returns the Drupal root-relative file path to the plugin JavaScript file. * * Note: this does not use a Drupal library because this uses CKEditor's API, diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginManager.php b/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginManager.php index cbb75f6..ffcac7a 100644 --- a/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginManager.php +++ b/core/modules/ckeditor/lib/Drupal/ckeditor/CKEditorPluginManager.php @@ -65,6 +65,7 @@ $plugins = array_keys($this->getDefinitions()); $toolbar_buttons = array_unique(NestedArray::mergeDeepArray($editor->settings['toolbar']['buttons'])); $enabled_plugins = array(); + $additional_plugins = array(); foreach ($plugins as $plugin_id) { $plugin = $this->createInstance($plugin_id); @@ -74,19 +75,29 @@ } $enabled = FALSE; + // Enable this plugin if it provides a button that has been enabled. if ($plugin instanceof CKEditorPluginButtonsInterface) { $plugin_buttons = array_keys($plugin->getButtons()); $enabled = (count(array_intersect($toolbar_buttons, $plugin_buttons)) > 0); } + // Otherwise enable this plugin if it declares itself as enabled. if (!$enabled && $plugin instanceof CKEditorPluginContextualInterface) { $enabled = $plugin->isEnabled($editor); } if ($enabled) { $enabled_plugins[$plugin_id] = ($plugin->isInternal()) ? NULL : $plugin->getFile(); + // Check if this plugin has dependencies that also need to be enabled. + $additional_plugins = array_merge($additional_plugins, array_diff($plugin->getDependencies($editor), $additional_plugins)); } } + // Add the list of dependent plugins. + foreach ($additional_plugins as $plugin_id) { + $plugin = $this->createInstance($plugin_id); + $enabled_plugins[$plugin_id] = ($plugin->isInternal()) ? NULL : $plugin->getFile(); + } + // Always return plugins in the same order. asort($enabled_plugins); diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/CKEditorPlugin/DrupalImage.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/CKEditorPlugin/DrupalImage.php new file mode 100644 index 0000000..82d0da3 --- /dev/null +++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/CKEditorPlugin/DrupalImage.php @@ -0,0 +1,63 @@ + url('editor/dialog/image/' . $editor->format), + ); + } + + /** + * Implements \Drupal\ckeditor\Plugin\CKEditorPluginButtonsInterface::getButtons(). + */ + public function getButtons() { + return array( + 'DrupalImage' => array( + 'label' => t('Image'), + 'image' => drupal_get_path('module', 'ckeditor') . '/js/plugins/drupalimage/image.png', + ), + ); + } + +} diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/CKEditorPlugin/Internal.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/CKEditorPlugin/Internal.php index 4516762..1a4697c 100644 --- a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/CKEditorPlugin/Internal.php +++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/CKEditorPlugin/Internal.php @@ -47,7 +47,6 @@ $config = array( 'customConfig' => '', // Don't load CKEditor's config.js file. 'pasteFromWordPromptCleanup' => TRUE, - 'removeDialogTabs' => 'image:Link;image:advanced;link:advanced', 'resize_dir' => 'vertical', 'keystrokes' => array( // 0x11000 is CKEDITOR.CTRL, see http://docs.ckeditor.com/#!/api/CKEDITOR-property-CTRL. @@ -193,11 +192,6 @@ 'Format' => array( 'label' => t('HTML block format'), 'image_alternative' => '' . t('Format') . '', - ), - // "image" plugin. - 'Image' => array( - 'label' => t('Image'), - 'image_alternative' => $button('image'), ), // "table" plugin. 'Table' => array( diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorPluginManagerTest.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorPluginManagerTest.php index 8cee06e..a0bd76e 100644 --- a/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorPluginManagerTest.php +++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorPluginManagerTest.php @@ -69,7 +69,7 @@ // Case 1: no CKEditor plugins. $definitions = array_keys($this->manager->getDefinitions()); sort($definitions); - $this->assertIdentical(array('internal', 'stylescombo'), $definitions, 'No CKEditor plugins found besides the built-in ones.'); + $this->assertIdentical(array('drupalimage', 'internal', 'stylescombo'), $definitions, 'No CKEditor plugins found besides the built-in ones.'); $this->assertIdentical(array(), $this->manager->getEnabledPlugins($editor), 'Only built-in plugins are enabled.'); $this->assertIdentical(array('internal' => NULL), $this->manager->getEnabledPlugins($editor, TRUE), 'Only the "internal" plugin is enabled.'); @@ -82,7 +82,7 @@ // Case 2: CKEditor plugins are available. $plugin_ids = array_keys($this->manager->getDefinitions()); sort($plugin_ids); - $this->assertIdentical(array('internal', 'llama', 'llama_button', 'llama_contextual', 'llama_contextual_and_button', 'stylescombo'), $plugin_ids, 'Additional CKEditor plugins found.'); + $this->assertIdentical(array('drupalimage', 'internal', 'llama', 'llama_button', 'llama_contextual', 'llama_contextual_and_button', 'stylescombo'), $plugin_ids, 'Additional CKEditor plugins found.'); $this->assertIdentical(array(), $this->manager->getEnabledPlugins($editor), 'Only the internal plugins are enabled.'); $this->assertIdentical(array('internal' => NULL), $this->manager->getEnabledPlugins($editor, TRUE), 'Only the "internal" plugin is enabled.'); diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorTest.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorTest.php index 846b93a..73abb70 100644 --- a/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorTest.php +++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Tests/CKEditorTest.php @@ -79,6 +79,7 @@ 'toolbar' => $this->getDefaultToolbarConfig(), 'contentsCss' => $this->getDefaultContentsCssConfig(), 'extraPlugins' => '', + 'removePlugins' => 'image', 'language' => 'en', 'stylesSet' => FALSE, 'drupalExternalPlugins' => array(), @@ -98,6 +99,7 @@ $expected_config['toolbar'][] = '/'; $expected_config['format_tags'] = 'p;h4;h5;h6'; $expected_config['extraPlugins'] = 'llama_contextual,llama_contextual_and_button'; + $expected_config['removePlugins'] = 'image'; $expected_config['drupalExternalPlugins']['llama_contextual'] = file_create_url('core/modules/ckeditor/tests/modules/js/llama_contextual.js'); $expected_config['drupalExternalPlugins']['llama_contextual_and_button'] = file_create_url('core/modules/ckeditor/tests/modules/js/llama_contextual_and_button.js'); $expected_config['contentsCss'][] = file_create_url('core/modules/ckeditor/tests/modules/ckeditor_test.css'); @@ -224,7 +226,7 @@ return array( 'customConfig' => '', 'pasteFromWordPromptCleanup' => TRUE, - 'removeDialogTabs' => 'image:Link;image:advanced;link:advanced', + 'removeDialogTabs' => 'link:advanced', 'resize_dir' => 'vertical', 'keystrokes' => array(array(0x110000 + 75, 'link'), array(0x110000 + 76, NULL)), ); diff --git a/core/modules/ckeditor/tests/modules/lib/Drupal/ckeditor_test/Plugin/CKEditorPlugin/Llama.php b/core/modules/ckeditor/tests/modules/lib/Drupal/ckeditor_test/Plugin/CKEditorPlugin/Llama.php index 78e20e9..35a8db6 100644 --- a/core/modules/ckeditor/tests/modules/lib/Drupal/ckeditor_test/Plugin/CKEditorPlugin/Llama.php +++ b/core/modules/ckeditor/tests/modules/lib/Drupal/ckeditor_test/Plugin/CKEditorPlugin/Llama.php @@ -34,6 +34,20 @@ class Llama extends PluginBase implements CKEditorPluginInterface { /** + * Implements \Drupal\ckeditor\Plugin\CKEditorPluginInterface::getDependencies(). + */ + function getDependencies(Editor $editor) { + return array(); + } + + /** + * Implements \Drupal\ckeditor\Plugin\CKEditorPluginInterface::getLibraries(). + */ + function getLibraries(Editor $editor) { + return array(); + } + + /** * Implements \Drupal\ckeditor\Plugin\CKEditorPluginInterface::isInternal(). */ function isInternal() { @@ -48,7 +62,7 @@ } /** - * Implements \Drupal\ckeditor\Plugin\CKEditorPluginInterface::getButtons(). + * Implements \Drupal\ckeditor\Plugin\CKEditorPluginInterface::getConfig(). */ public function getConfig(Editor $editor) { return array(); diff --git a/core/modules/editor/css/editor.dialog.css b/core/modules/editor/css/editor.dialog.css new file mode 100644 index 0000000..4f71f1a --- /dev/null +++ b/core/modules/editor/css/editor.dialog.css @@ -0,0 +1,8 @@ +/** + * @file + * Styles for text editors. + */ +.editor-image-dialog { + width: 80%; + max-width: 500px; +} diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module index 0f317b9..a439b15 100644 --- a/core/modules/editor/editor.module +++ b/core/modules/editor/editor.module @@ -79,6 +79,20 @@ ), ); + $libraries['drupal.editor.dialog'] = array( + 'title' => 'Text Editor Dialog', + 'version' => VERSION, + 'js' => array( + $path . '/js/editor.dialog.js' => array(), + ), + 'dependencies' => array( + array('system', 'jquery'), + array('system', 'drupal.dialog'), + array('system', 'drupal.ajax'), + array('system', 'drupalSettings'), + ), + ); + $libraries['edit.formattedTextEditor.editor'] = array( 'title' => 'Formatted text editor', 'version' => VERSION, diff --git a/core/modules/editor/editor.routing.yml b/core/modules/editor/editor.routing.yml index 0bb56cf..05cddcc 100644 --- a/core/modules/editor/editor.routing.yml +++ b/core/modules/editor/editor.routing.yml @@ -5,3 +5,9 @@ requirements: _permission: 'access in-place editing' _access_edit_entity_field: 'TRUE' +editor_image_dialog: + pattern: '/editor/dialog/image/{filter_format}' + defaults: + _form: '\Drupal\editor\Form\EditorImageDialog' + requirements: + _filter_access: 'TRUE' diff --git a/core/modules/editor/js/editor.dialog.js b/core/modules/editor/js/editor.dialog.js new file mode 100644 index 0000000..301d391 --- /dev/null +++ b/core/modules/editor/js/editor.dialog.js @@ -0,0 +1,20 @@ +/** + * @todo D8: remove this when http://drupal.org/node/1870764 lands + */ + +(function ($, Drupal) { + +"use strict"; + +/** + * Command to save the contents of an editor-provided modal. + * + * This command does not close the open modal. It should be followed by a call + * to Drupal.ajax.prototype.commands.closeDialog. + */ +Drupal.ajax.prototype.commands.editorDialogSave = function (ajax, response, status) { + console.log(response.values); + $(window).trigger('editor:dialogsave', [response.values]); +}; + +})(jQuery, Drupal); diff --git a/core/modules/editor/lib/Drupal/editor/Ajax/EditorDialogSave.php b/core/modules/editor/lib/Drupal/editor/Ajax/EditorDialogSave.php new file mode 100644 index 0000000..047336f --- /dev/null +++ b/core/modules/editor/lib/Drupal/editor/Ajax/EditorDialogSave.php @@ -0,0 +1,46 @@ +values = $values; + } + + /** + * Implements \Drupal\Core\Ajax\CommandInterface::render(). + */ + public function render() { + return array( + 'command' => 'editorDialogSave', + 'values' => $this->values, + ); + } + +} diff --git a/core/modules/editor/lib/Drupal/editor/EditorController.php b/core/modules/editor/lib/Drupal/editor/EditorController.php index 2968454..c48b894 100644 --- a/core/modules/editor/lib/Drupal/editor/EditorController.php +++ b/core/modules/editor/lib/Drupal/editor/EditorController.php @@ -9,8 +9,11 @@ use Symfony\Component\DependencyInjection\ContainerAware; use Drupal\Core\Ajax\AjaxResponse; +use Drupal\Core\Ajax\OpenModalDialogCommand; +use Drupal\Core\Ajax\CloseModalDialogCommand; use Drupal\Core\Entity\EntityInterface; use Drupal\editor\Ajax\GetUntransformedTextCommand; +use Drupal\filter\Plugin\Core\Entity\FilterFormat; /** * Returns responses for Editor module routes. @@ -44,4 +47,12 @@ return $response; } + public function imageDialog(FilterFormat $filter_format = NULL) { + $response = new AjaxResponse(); + + $response->addCommand(new OpenModalDialogCommand(t('Insert image'), 'test')); + + return $response; + } + } diff --git a/core/modules/editor/lib/Drupal/editor/Form/EditorImageDialog.php b/core/modules/editor/lib/Drupal/editor/Form/EditorImageDialog.php new file mode 100644 index 0000000..3ff73ab --- /dev/null +++ b/core/modules/editor/lib/Drupal/editor/Form/EditorImageDialog.php @@ -0,0 +1,138 @@ + t('URL'), + '#type' => 'textfield', + '#default_value' => isset($input['src']) ? $input['src'] : '', + '#maxlength' => 2048, + '#required' => TRUE, + ); + + $form['attributes']['alt'] = array( + '#title' => t('Alternative text'), + '#type' => 'textfield', + '#default_value' => isset($input['alt']) ? $input['alt'] : '', + '#maxlength' => 2048, + ); + $form['dimensions'] = array( + '#type' => 'item', + '#title' => t('Image size'), + '#field_prefix' => '
', + '#field_suffix' => '
', + ); + $form['dimensions']['width'] = array( + '#title' => t('Width'), + '#title_display' => 'invisible', + '#type' => 'number', + '#default_value' => isset($input['width']) ? $input['width'] : '', + '#size' => 8, + '#maxlength' => 8, + '#min' => 1, + '#max' => 99999, + '#placeholder' => 'width', + '#field_suffix' => ' x ', + '#parents' => array('attributes', 'width'), + ); + $form['dimensions']['height'] = array( + '#title' => t('Height'), + '#title_display' => 'invisible', + '#type' => 'number', + '#default_value' => isset($input['height']) ? $input['height'] : '', + '#size' => 8, + '#maxlength' => 8, + '#min' => 1, + '#max' => 99999, + '#placeholder' => 'height', + '#field_suffix' => 'pixels', + '#parents' => array('attributes', 'height'), + ); + + $form['actions'] = array( + '#type' => 'actions', + ); + $form['actions']['save_modal'] = array( + '#type' => 'submit', + '#value' => t('Save'), + // No regular submit-handler. This form only works via JavaScript. + '#submit' => array(), + '#ajax' => array( + 'callback' => array($this, 'submitForm'), + ), + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) { + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + $response = new AjaxResponse(); + + if (form_get_errors()) { + $output = drupal_render($form); + $output = '
' . theme('status_messages') . $output . '
'; + $response->addCommand(new HtmlCommand('#drupal-modal', $output)); + } + else { + $response->addCommand(new EditorDialogSave($form_state['values'])); + $response->addCommand(new CloseModalDialogCommand()); + } + + return $response; + } + +}