core/misc/dialog.ajax.js | 50 ++++- core/misc/dialog.js | 38 +++- core/misc/dialog.theme.css | 103 ++++++++++ core/misc/loading-small.gif | 25 +++ core/misc/loading.gif | 43 ++++ core/modules/ckeditor/ckeditor.admin.inc | 2 +- core/modules/ckeditor/ckeditor.module | 3 + core/modules/ckeditor/css/ckeditor-iframe.css | 7 + core/modules/ckeditor/css/ckeditor.admin.css | 4 +- core/modules/ckeditor/css/ckeditor.css | 25 +++ core/modules/ckeditor/js/ckeditor.js | 92 +++++++++ .../ckeditor/js/plugins/drupalimage/image.png | 7 + .../ckeditor/js/plugins/drupalimage/plugin.js | 136 +++++++++++++ .../ckeditor/js/plugins/drupallink/link.png | 3 + .../ckeditor/js/plugins/drupallink/plugin.js | 207 ++++++++++++++++++++ .../ckeditor/js/plugins/drupallink/unlink.png | 7 + .../lib/Drupal/ckeditor/CKEditorPluginBase.php | 15 +- .../Drupal/ckeditor/CKEditorPluginInterface.php | 25 +++ .../lib/Drupal/ckeditor/CKEditorPluginManager.php | 11 ++ .../ckeditor/Plugin/CKEditorPlugin/DrupalImage.php | 65 ++++++ .../ckeditor/Plugin/CKEditorPlugin/DrupalLink.php | 70 +++++++ .../ckeditor/Plugin/CKEditorPlugin/Internal.php | 25 --- .../lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php | 19 +- .../ckeditor/Tests/CKEditorPluginManagerTest.php | 4 +- .../lib/Drupal/ckeditor/Tests/CKEditorTest.php | 5 +- .../ckeditor_test/Plugin/CKEditorPlugin/Llama.php | 16 +- core/modules/editor/css/editor.css | 15 ++ core/modules/editor/editor.module | 17 ++ core/modules/editor/editor.routing.yml | 12 ++ core/modules/editor/js/editor.dialog.js | 21 ++ .../lib/Drupal/editor/Ajax/EditorDialogSave.php | 47 +++++ .../editor/lib/Drupal/editor/EditorController.php | 5 + .../lib/Drupal/editor/Form/EditorImageDialog.php | 136 +++++++++++++ .../lib/Drupal/editor/Form/EditorLinkDialog.php | 103 ++++++++++ core/modules/system/system.module | 4 + .../standard/config/editor.editor.basic_html.yml | 6 +- .../standard/config/editor.editor.full_html.yml | 6 +- core/themes/bartik/css/style.css | 2 +- core/themes/seven/jquery.ui.theme.css | 49 ----- 39 files changed, 1336 insertions(+), 94 deletions(-) diff --git a/core/misc/dialog.ajax.js b/core/misc/dialog.ajax.js index 8b1f80f..5758b40 100644 --- a/core/misc/dialog.ajax.js +++ b/core/misc/dialog.ajax.js @@ -8,13 +8,55 @@ "use strict"; Drupal.behaviors.dialog = { - attach: function () { + attach: function (context, settings) { // Provide a known 'drupal-modal' DOM element for Drupal-based modal // dialogs. Non-modal dialogs are responsible for creating their own // elements, since there can be multiple non-modal dialogs at a time. if (!$('#drupal-modal').length) { $('
').hide().appendTo('body'); } + + // If a new form is being attached inside a dialog, remove and replace + // the dialog buttons with those from the new form. + var $dialog = $(context).closest('.ui-dialog-content'); + if ($dialog && $dialog.dialog('option', 'drupalAutoButtons')) { + var buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog); + $dialog.dialog('option', 'buttons', buttons); + } + }, + detach: function (context, settings) { + $(context).find('form').off('submit.dialogSubmit'); + }, + + /** + * Scan a dialog for any primary buttons and move them to the button area. + * + * @param $dialog + * An jQuery object containing the element that is the dialog target. + * @return + * An array of buttons that need to be added to the button area. + */ + prepareDialogButtons: function ($dialog) { + var buttons = []; + var $buttons = $dialog.find('.form-actions input[type=submit], button'); + $buttons.each(function () { + var $originalButton = $(this).hide(); + buttons.push({ + 'text': $originalButton.html() || $originalButton.attr('value'), + 'class': $originalButton.attr('class'), + 'click': function (e) { + $originalButton.trigger('mousedown'); + e.preventDefault(); + } + }); + }); + if ($buttons.length) { + $dialog.find('form').on('submit.dialogSubmit', function (e) { + $buttons.first().trigger('mousedown'); + e.preventDefault(); + }); + } + return buttons; } }; @@ -40,6 +82,12 @@ response.method = 'html'; ajax.commands.insert(ajax, response, status); + // Move the buttons to the jQuery UI dialog buttons area. + if (!response.dialogOptions.buttons) { + response.dialogOptions.drupalAutoButtons = true; + response.dialogOptions.buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog); + } + // Open the dialog itself. response.dialogOptions = response.dialogOptions || {}; var dialog = Drupal.dialog($dialog, response.dialogOptions); diff --git a/core/misc/dialog.js b/core/misc/dialog.js index 62cbeb1..2d186e2 100644 --- a/core/misc/dialog.js +++ b/core/misc/dialog.js @@ -19,10 +19,14 @@ drupalSettings.dialog = { Drupal.dialog = function (element, options) { function openDialog (settings) { - settings = $.extend({}, drupalSettings.dialog, options, settings); + settings = $.extend({ autoResize: true }, drupalSettings.dialog, options, settings); // Trigger a global event to allow scripts to bind events to the dialog. $(window).trigger('dialog:beforecreate', [dialog, $element, settings]); $element.dialog(settings); + if (settings.autoResize !== 'false' && settings.autoResize !== false) { + $(window).on('resize.dialogResize scroll.dialogResize', autoResize); + resetPosition(); + } dialog.open = true; $(window).trigger('dialog:aftercreate', [dialog, $element, settings]); } @@ -32,11 +36,43 @@ Drupal.dialog = function (element, options) { $element.dialog('close'); dialog.returnValue = value; dialog.open = false; + $(window).off('.dialogResize'); $(window).trigger('dialog:afterclose', [dialog, $element]); } + /** + * Resets the current options for positioning. + * + * This is used as a window resize and scroll callback to reposition the + * jQuery UI dialog. Although not a built-in jQuery UI option, this can + * be disabled by setting autoResize: false in the options array when creating + * a new Drupal.dialog(). + */ + function resetPosition () { + var positionOptions = ['width', 'height', 'minWidth', 'minHeight', 'maxHeight', 'maxWidth', 'position']; + var windowHeight = $(window).height(); + var adjustedOptions = $.extend({ position: { my: "center", at: "center", of: window }}, options); + var optionValue, adjustedValue; + for (var n = 0; n < positionOptions.length; n++) { + if (adjustedOptions[positionOptions[n]]) { + optionValue = adjustedOptions[positionOptions[n]]; + // jQuery UI does not support percentages on heights, convert to pixels. + if (positionOptions[n].match(/height/i) && typeof optionValue === 'string' && optionValue.match(/%$/)) { + adjustedValue = parseInt(0.01 * parseInt(optionValue, 10) * windowHeight, 10); + // Don't force the dialog to be bigger vertically than needed. + if (positionOptions[n] === 'height' && $element.parent().outerHeight() < adjustedValue) { + adjustedValue = 'auto'; + } + adjustedOptions[positionOptions[n]] = adjustedValue; + } + } + } + $element.dialog('option', adjustedOptions); + } + var undef; var $element = $(element); + var autoResize = Drupal.debounce(resetPosition, 50); var dialog = { open: false, returnValue: undef, diff --git a/core/misc/dialog.theme.css b/core/misc/dialog.theme.css new file mode 100644 index 0000000..360e6ae --- /dev/null +++ b/core/misc/dialog.theme.css @@ -0,0 +1,103 @@ +/** + * Presentational styles for Drupal dialogs. + */ + +.ui-dialog { + position: absolute; + z-index: 1260; + overflow: visible; + color: #000; + background: #fff; + border: solid 1px #ccc; + padding: 0; +} +.ui-dialog .ui-dialog-titlebar { + font-weight: bold; + background: #f3f4ee; + border-style: solid; + border-radius: 0; + border-width: 0 0 1px 0; + border-color: #ccc; +} +.ui-dialog .ui-dialog-titlebar-close { + border: 0; + background: none; +} +.ui-dialog .ui-dialog-buttonpane { + margin-top: 0; + background: #f3f4ee; + padding: .3em 1em; + border-width: 1px 0 0 0; + border-color: #ccc; +} +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { + margin: 0; + padding: 0; +} +.ui-dialog .ui-dialog-buttonpane .ui-button-text-only .ui-button-text { + padding: 0; +} + +.ui-dialog .ui-dialog-buttonpane button { + background: #fefefe; + background-image: -webkit-linear-gradient(top, #fefefe, #e0e0e0); + background-image: -moz-linear-gradient(top, #fefefe, #e0e0e0); + background-image: -o-linear-gradient(top, #fefefe, #e0e0e0); + background-image: linear-gradient(to bottom, #fefefe, #e0e0e0); + border: 1px solid #c8c8c8; + border-radius: 3px; + text-decoration: none; + padding: 6px 17px 6px 17px; +} +.ui-dialog .ui-dialog-buttonpane button:hover, +.ui-dialog .ui-dialog-buttonpane button:focus { + background: #fefefe; + background-image: -webkit-linear-gradient(top, #fefefe, #eaeaea); + background-image: -moz-linear-gradient(top, #fefefe, #eaeaea); + background-image: -o-linear-gradient(top, #fefefe, #eaeaea); + background-image: linear-gradient(to bottom, #fefefe, #eaeaea); + -webkit-box-shadow: 1px 1px 3px rgba(50, 50, 50, 0.1); + box-shadow: 1px 1px 3px rgba(50, 50, 50, 0.1); + color: #2e2e2e; + text-decoration: none; +} +.ui-dialog .ui-dialog-buttonpane button:active { + border: 1px solid #c8c8c8; + background: #fefefe; + background-image: -webkit-linear-gradient(top, #eaeaea, #fefefe); + background-image: -moz-linear-gradient(top, #eaeaea, #fefefe); + background-image: -o-linear-gradient(top, #eaeaea, #fefefe); + background-image: linear-gradient(to bottom, #eaeaea, #fefefe); + -webkit-box-shadow: 1px 1px 3px rgba(50, 50, 50, 0.1); + box-shadow: 1px 1px 3px rgba(50, 50, 50, 0.1); + color: #2e2e2e; + text-decoration: none; + text-shadow: none; +} + +/* Form action buttons are moved in dialogs. Remove empty space. */ +.ui-dialog .ui-dialog-content .form-actions { + padding: 0; + margin: 0; +} +.ui-dialog .ajax-progress-throbber { + /* Can't do center:50% middle: 50%, so approximate it for a typical window size. */ + left: 49%; + position: fixed; + top: 48.5%; + z-index: 1000; + background-color: #232323; + background-image: url("loading-small.gif"); + background-position: center center; + background-repeat: no-repeat; + border-radius: 7px; + height: 24px; + opacity: 0.9; + padding: 4px; + width: 24px; +} +.ui-dialog .ajax-progress-throbber .throbber, +.ui-dialog .ajax-progress-throbber .message { + display: none; +} + diff --git a/core/misc/loading-small.gif b/core/misc/loading-small.gif new file mode 100644 index 0000000..5cbf6e7 --- /dev/null +++ b/core/misc/loading-small.gif @@ -0,0 +1,25 @@ +GIF89a Ž{{{ssskkkcccZZZRRRJJJBBB:::111)))!!! !NETSCAPE2.0 ! + , &6MeK,kG8@qh/MGH:%#Gc4D2a8@@p2HfzH,%x" +WrIix%pqX1*=##+="I#3g~" ">w kX (_S(As}RTx (oBB4xZ %q ! + , 'GQe04k<\nU6d 'U!`D % XeU(2H `%)2(* PEš b%K`1K:$2$P{({"#)1%%% +#k +{" ?&*E vl [8w+! ! + , Ԡ'WUea