From 72457673f82223e7e94dd870936140a95c8bab23 Mon Sep 17 00:00:00 2001 From: Mark Carver Date: Fri, 14 Jun 2019 03:43:24 -0500 Subject: [PATCH] Issue #3061758 by markcarver: Allow custom Drupal dialog type handlers to be registered Signed-off-by: Mark Carver --- bootstrap.libraries.yml | 7 ++ js/dialog.js | 156 +++++++++++++++++++++++++++ js/drupal.bootstrap.js | 44 ++++++-- js/misc/dialog.ajax.js | 31 +++++- js/modal.jquery.ui.bridge.js | 175 ++++++++++++++++--------------- js/modal.js | 86 ++++++++++++--- src/Plugin/Alter/LibraryInfo.php | 2 + 7 files changed, 394 insertions(+), 107 deletions(-) create mode 100644 js/dialog.js diff --git a/bootstrap.libraries.yml b/bootstrap.libraries.yml index 9640b63..1b7822e 100644 --- a/bootstrap.libraries.yml +++ b/bootstrap.libraries.yml @@ -23,6 +23,13 @@ drupal.bootstrap: - core/drupalSettings - bootstrap/framework +dialog: + js: + js/dialog.js: {} + dependencies: + - bootstrap/theme + - bootstrap/modal + # Create a library placeholder for livereload. # This is altered dynamically based on the set URL. # @see \Drupal\bootstrap\Plugin\Alter\LibraryInfo::alter diff --git a/js/dialog.js b/js/dialog.js new file mode 100644 index 0000000..517f049 --- /dev/null +++ b/js/dialog.js @@ -0,0 +1,156 @@ +/** + * @file + * dialog.js + */ +(function ($, Drupal, Bootstrap, Attributes) { + + Bootstrap.Dialog = Bootstrap.Dialog || {}; + + /** + * A collection of Drupal dialog handlers. + * + * @type {Object} + */ + Bootstrap.Dialog.handlers = {}; + + /** + * @class Drupal.bootstrap.Dialog.Handler + * + * @param type + * @param data + */ + Bootstrap.Dialog.Handler = function (type, data) { + this.ctor = $.fn.modal; + this.extend = null; + this.plugin = 'modal'; + this.prefix = 'modal'; + this.themeHooks = { + modal: 'bootstrapModal', + dialog: 'bootstrapModalDialog', + header: 'bootstrapModalHeader', + title: 'bootstrapModalTitle', + close: 'bootstrapModalClose', + content: 'bootstrapModalContent', + body: 'bootstrapModalBody', + footer: 'bootstrapModalFooter', + }; + this.type = type; + this.selectors = { + dialog: '.modal-dialog', + header: '.modal-header', + title: '.modal-title', + close: '.close', + content: '.modal-content', + body: '.modal-body', + footer: '.modal-footer', + buttons: '.modal-buttons' + }; + + // Extend the object with subclassed data. + $.extend(this, data); + + // Extend the jQuery plugin. + if (this.extend) { + Bootstrap.extend(this.plugin, this.extend); + } + }; + + /** + * Retrieves a Drupal dialog type handler. + * + * @param {String|HTMLElement|jQuery} type + * The dialog type to retrieve. + * + * @return {Drupal.bootstrap.Dialog.Handler} + * A Bootstrap.Dialog.Handler instance. + */ + Bootstrap.Dialog.Handler.get = function (type) { + if (type instanceof $) { + type = type[0]; + } + if (type instanceof HTMLElement) { + type = type.dialogType; + } + if (!type) { + type = 'modal'; + } + if (!Bootstrap.Dialog.handlers[type]) { + Bootstrap.Dialog.handlers[type] = new Bootstrap.Dialog.Handler(); + } + return Bootstrap.Dialog.handlers[type]; + }; + + /** + * Registers a Drupal dialog type handler. + * + * @param {String} type + * The dialog type to + * @param {Object} [data] + * Optional. Additional data to use to create the dialog handler. By + * default, this assumes values relative to the Bootstrap Modal plugin. + */ + Bootstrap.Dialog.Handler.register = function (type, data) { + Bootstrap.Dialog.handlers[type] = new Bootstrap.Dialog.Handler(type, data); + }; + + Bootstrap.Dialog.Handler.prototype.invoke = function (context) { + var args = Array.prototype.slice.call(arguments); + return this.ctor.apply(context, args.slice(1)); + }; + + Bootstrap.Dialog.Handler.prototype.theme = function (hook) { + var args = Array.prototype.slice.call(arguments); + return $(Drupal.theme.apply(Drupal.theme, [this.themeHooks[hook]].concat(args.slice(1)))); + }; + + /** + * Ensures a DOM element has the appropriate structure for a modal. + * + * Note: this can get a little tricky. Core potentially already + * semi-processes a "dialog" if was created using an Ajax command + * (i.e. prepareDialogButtons in drupal.ajax.js). Because of this, the + * contents (HTML) of the existing element cannot simply be dumped into a + * newly created modal. This would destroy any existing event bindings. + * Instead, the contents must be "moved" (appended) to the new modal and + * then "moved" again back to the to the existing container as needed. + * + * @param {HTMLElement|jQuery} element + * The element to ensure is a modal structure. + * @param {Object} options + * THe dialog options to use to construct the modal. + */ + Bootstrap.Dialog.Handler.prototype.ensureModalStructure = function (element, options) { + var $element = $(element); + + // Immediately return if the modal was already converted into a proper modal. + if ($element.is('[data-drupal-theme="' + this.themeHooks.modal + '"]')) { + return; + } + + options = $.extend(true, {}, options, { + attributes: Attributes.create(element).remove('style').set('data-drupal-theme', this.themeHooks.modal), + }); + + // Create a new modal. + var $modal = this.theme('modal', options); + + // Store a reference to the content inside the existing element container. + // This references the actual DOM node elements which will allow + // jQuery to "move" then when appending below. Using $.fn.children() + // does not return any text nodes present and $.fn.html() only returns + // a string representation of the content, which effectively destroys + // any prior event bindings or processing. + var $body = $element.find(this.selectors.body); + var $existing = $body[0] ? $body.contents() : $element.contents(); + + // Set the attributes of the dialog to that of the newly created modal. + $element.attr(Attributes.create($modal).toPlainObject()); + + // Append the newly created modal markup. + $element.append($modal.html()); + + // Move the existing HTML into the modal markup that was just appended. + $element.find(this.selectors.body).append($existing); + }; + +})(jQuery, Drupal, Drupal.bootstrap, Attributes); diff --git a/js/drupal.bootstrap.js b/js/drupal.bootstrap.js index 1157a91..0d0c101 100644 --- a/js/drupal.bootstrap.js +++ b/js/drupal.bootstrap.js @@ -6,11 +6,17 @@ /** * All Drupal Bootstrap JavaScript APIs are contained in this namespace. * - * @namespace + * @param {underscore} _ + * @param {jQuery} $ + * @param {Drupal} Drupal + * @param {drupalSettings} drupalSettings */ (function (_, $, Drupal, drupalSettings) { 'use strict'; + /** + * @typedef Drupal.bootstrap + */ var Bootstrap = { processedOnce: {}, settings: drupalSettings.bootstrap || {} @@ -311,6 +317,36 @@ } }; + /** + * Creates a handler that relays to another event name. + * + * @param {HTMLElement|jQuery} target + * A target element. + * @param {String} name + * The name of the event to trigger. + * @param {Boolean} [stopPropagation=true] + * Flag indicating whether to stop the propagation of the event, defaults + * to true. + * + * @return {Function} + * An even handler callback function. + */ + Bootstrap.relayEvent = function (target, name, stopPropagation) { + return function (e) { + if (stopPropagation === void 0 || stopPropagation) { + e.stopPropagation(); + } + var $target = $(target); + var parts = name.split('.').filter(Boolean); + var type = parts.shift(); + e.target = $target[0]; + e.currentTarget = $target[0]; + e.namespace = parts.join('.'); + e.type = type; + $target.trigger(e); + }; + }; + /** * Replaces a Bootstrap jQuery plugin definition. * @@ -558,11 +594,7 @@ } }; - /** - * Add Bootstrap to the global Drupal object. - * - * @type {Bootstrap} - */ + // Add Bootstrap to the global Drupal object. Drupal.bootstrap = Drupal.bootstrap || Bootstrap; })(window._, window.jQuery, window.Drupal, window.drupalSettings); diff --git a/js/misc/dialog.ajax.js b/js/misc/dialog.ajax.js index 5677705..c0fceed 100644 --- a/js/misc/dialog.ajax.js +++ b/js/misc/dialog.ajax.js @@ -7,6 +7,35 @@ Drupal.behaviors.dialog.ajaxCurrentButton = null; Drupal.behaviors.dialog.ajaxOriginalButton = null; + // Intercept the success event to add the dialog type to commands. + var success = Drupal.Ajax.prototype.success; + Drupal.Ajax.prototype.success = function (response, status) { + if (this.dialogType) { + for (var i = 0, l = response.length; i < l; i++) { + if (response[i].dialogOptions) { + response[i].dialogType = response[i].dialogOptions.dialogType = this.dialogType; + response[i].$trigger = response[i].dialogOptions.$trigger = $(this.element); + } + } + } + return success.apply(this, [response, status]); + }; + + var beforeSerialize = Drupal.Ajax.prototype.beforeSerialize; + Drupal.Ajax.prototype.beforeSerialize = function (element, options) { + // Add the dialog type currently in use. + if (this.dialogType) { + options.data['ajax_page_state[dialogType]'] = this.dialogType; + + // Add the dialog element ID if it can be found (useful for closing it). + var id = $(this.element).parents('.js-drupal-dialog:first').attr('id'); + if (id) { + options.data['ajax_page_state[dialogId]'] = id; + } + } + return beforeSerialize.apply(this, arguments); + }; + /** * Synchronizes a faux button with its original counterpart. * @@ -39,7 +68,7 @@ Drupal.behaviors.dialog.prepareDialogButtons = function prepareDialogButtons($dialog) { var _this = this; var buttons = []; - var $buttons = $dialog.find('.form-actions').find('button, input[type=submit], a.button'); + var $buttons = $dialog.find('.form-actions').find('button, input[type=submit], a.button, .btn'); $buttons.each(function () { var $originalButton = $(this) // Prevent original button from being tabbed to. diff --git a/js/modal.jquery.ui.bridge.js b/js/modal.jquery.ui.bridge.js index 53a5484..a316dd9 100644 --- a/js/modal.jquery.ui.bridge.js +++ b/js/modal.jquery.ui.bridge.js @@ -1,6 +1,12 @@ /** * @file * Bootstrap Modals. + * + * @param {jQuery} $ + * @param {Drupal} Drupal + * @param {Drupal.bootstrap} Bootstrap + * @param {Attributes} Attributes + * @param {drupalSettings} drupalSettings */ (function ($, Drupal, Bootstrap, Attributes, drupalSettings) { 'use strict'; @@ -20,92 +26,51 @@ drupalSettings.dialog.buttonPrimaryClass = 'btn-primary'; }); - var relayEvent = function ($element, name, stopPropagation) { - return function (e) { - if (stopPropagation === void 0 || stopPropagation) { - e.stopPropagation(); - } - var parts = name.split('.').filter(Boolean); - var type = parts.shift(); - e.target = $element[0]; - e.currentTarget = $element[0]; - e.namespace = parts.join('.'); - e.type = type; - $element.trigger(e); - }; - }; + // Create the "dialog" plugin bridge. + Bootstrap.Dialog.Bridge = function (options) { + var args = Array.prototype.slice.call(arguments); + var $element = $(this); + var type = options && options.dialogType || $element[0].dialogType || 'modal'; + + $element[0].dialogType = type; + + var handler = Bootstrap.Dialog.Handler.get(type); - /** - * Proxy $.fn.dialog to $.fn.modal. - */ - var Dialog = function (options) { // When only options are passed, jQuery UI dialog treats this like a // initialization method. Destroy any existing Bootstrap modal and // recreate it using the contents of the dialog HTML. - if (arguments.length === 1 && typeof options === 'object') { - this.each($.fn.dialog.ensureModalStructure); + if (args.length === 1 && typeof options === 'object') { + this.each(function () { + handler.ensureModalStructure(this, options); + }); // Proxy to the Bootstrap Modal plugin, indicating that this is a // jQuery UI dialog bridge. - return $.fn.modal.apply(this, [{ + return handler.invoke(this, { dialogOptions: options, jQueryUiBridge: true - }]); + }); } // Otherwise, proxy all arguments to the Bootstrap Modal plugin. - return $.fn.modal.apply(this, arguments); - }; - - /** - * Ensures a DOM element has the appropriate structure for a modal. - * - * Note: this can get a little tricky. Core potentially already - * semi-processes a "dialog" if was created using an Ajax command - * (i.e. prepareDialogButtons in drupal.ajax.js). Because of this, the - * contents (HTML) of the existing element cannot simply be dumped into a - * newly created modal. This would destroy any existing event bindings. - * Instead, the contents must be "moved" (appended) to the new modal and - * then "moved" again back to the to the existing container as needed. - */ - Dialog.ensureModalStructure = function () { - var $element = $(this); - - // Immediately return if the modal was already converted into a proper modal. - if ($element.is('[data-drupal-theme="bootstrapModal"]')) { - return; + var ret; + try { + ret = handler.invoke.apply(handler, [this].concat(args)); + } + catch (e) { + Bootstrap.warn(e); } - // Create a new modal. - var $modal = $(Drupal.theme('bootstrapModal', { - attributes: Attributes.create(this).remove('style').set('data-drupal-theme', 'bootstrapModal'), - })); - - // Store a reference to the content inside the existing element container. - // This references the actual DOM node elements which will allow - // jQuery to "move" then when appending below. Using $.fn.children() - // does not return any text nodes present and $.fn.html() only returns - // a string representation of the content, which effectively destroys - // any prior event bindings or processing. - var $body = $element.find('.modal-body'); - var $existing = $body[0] ? $body.contents() : $element.contents(); - - // Set the attributes of the dialog to that of the newly created modal. - $element.attr(Attributes.create($modal).toPlainObject()); - - // Append the newly created modal markup. - $element.append($modal.html()); - - // Move the existing HTML into the modal markup that was just appended. - $element.find('.modal-body').append($existing); + // If just one element and there was a result returned for the option passed, + // then return the result. Otherwise, just return the jQuery object. + return this.length === 1 && ret !== void 0 ? ret : this; }; - Bootstrap.createPlugin('dialog', Dialog); + // Assign the jQuery "dialog" plugin to use to the bridge. + Bootstrap.createPlugin('dialog', Bootstrap.Dialog.Bridge); - /** - * Extend the Bootstrap Modal plugin constructor class. - */ - Bootstrap.extendPlugin('modal', function () { + // Create the "modal" plugin bridge. + Bootstrap.Modal.Bridge = function () { var Modal = this; return { @@ -140,7 +105,8 @@ * Creates any necessary buttons from dialog options. */ createButtons: function () { - this.$footer.find('.modal-buttons').remove(); + var handler = Bootstrap.Dialog.Handler.get(this.$element); + this.$footer.find(handler.selectors.buttons).remove(); // jQuery UI supports both objects and arrays. Unfortunately // developers have misunderstood and abused this by simply placing @@ -199,20 +165,51 @@ * Initializes the Bootstrap Modal. */ init: function () { + var handler = Bootstrap.Dialog.Handler.get(this.$element); + if (!this.$dialog) { + this.$dialog = this.$element.find(handler.selectors.dialog); + } + this.$dialog.addClass('js-drupal-dialog'); + + if (!this.$header) { + this.$header = this.$dialog.find(handler.selectors.header); + } + if (!this.$title) { + this.$title = this.$dialog.find(handler.selectors.title); + } + if (!this.$close) { + this.$close = this.$header.find(handler.selectors.close); + } + if (!this.$footer) { + this.$footer = this.$dialog.find(handler.selectors.footer); + } + if (!this.$content) { + this.$content = this.$dialog.find(handler.selectors.content); + } + if (!this.$dialogBody) { + this.$dialogBody = this.$dialog.find(handler.selectors.body); + } + // Relay necessary events. if (this.options.jQueryUiBridge) { - this.$element.on('hide.bs.modal', relayEvent(this.$element, 'dialogbeforeclose', false)); - this.$element.on('hidden.bs.modal', relayEvent(this.$element, 'dialogclose', false)); - this.$element.on('show.bs.modal', relayEvent(this.$element, 'dialogcreate', false)); - this.$element.on('shown.bs.modal', relayEvent(this.$element, 'dialogopen', false)); + this.$element.on('hide.bs.modal', Bootstrap.relayEvent(this.$element, 'dialogbeforeclose', false)); + this.$element.on('hidden.bs.modal', Bootstrap.relayEvent(this.$element, 'dialogclose', false)); + this.$element.on('show.bs.modal', Bootstrap.relayEvent(this.$element, 'dialogcreate', false)); + this.$element.on('shown.bs.modal', Bootstrap.relayEvent(this.$element, 'dialogopen', false)); } // Create a footer if one doesn't exist. // This is necessary in case dialog.ajax.js decides to add buttons. if (!this.$footer[0]) { - this.$footer = $(Drupal.theme('bootstrapModalFooter', {}, true)).insertAfter(this.$dialogBody); + this.$footer = handler.theme('footer', {}, true).insertAfter(this.$dialogBody); } + // Map the initial options. + $.extend(true, this.options, this.mapDialogOptions(this.options)); + + // Update buttons. + this.createButtons(); + // Now call the parent init method. this.super(); @@ -248,6 +245,9 @@ * The options to map. */ mapDialogOptions: function (options) { + // Retrieve the dialog handler for this type. + var handler = Bootstrap.Dialog.Handler.get(this.$element); + var mappedOptions = {}; var dialogOptions = options.dialogOptions || {}; @@ -385,10 +385,10 @@ case 'draggable': this.$content .draggable({ - handle: '.modal-header', - drag: relayEvent(this.$element, 'dialogdrag'), - start: relayEvent(this.$element, 'dialogdragstart'), - end: relayEvent(this.$element, 'dialogdragend') + handle: handler.selectors.header, + drag: Bootstrap.relayEvent(this.$element, 'dialogdrag'), + start: Bootstrap.relayEvent(this.$element, 'dialogdragstart'), + end: Bootstrap.relayEvent(this.$element, 'dialogdragend') }) .draggable(dialogOptions.draggable ? 'enable' : 'disable'); break; @@ -425,9 +425,9 @@ case 'resizable': this.$content .resizable({ - resize: relayEvent(this.$element, 'dialogresize'), - start: relayEvent(this.$element, 'dialogresizestart'), - end: relayEvent(this.$element, 'dialogresizeend') + resize: Bootstrap.relayEvent(this.$element, 'dialogresize'), + start: Bootstrap.relayEvent(this.$element, 'dialogresizestart'), + end: Bootstrap.relayEvent(this.$element, 'dialogresizeend') }) .resizable(dialogOptions.resizable ? 'enable' : 'disable'); break; @@ -443,7 +443,7 @@ break; case 'title': - this.$dialog.find('.modal-title').text(dialogOptions.title); + this.$title.text(dialogOptions.title); break; } @@ -505,7 +505,14 @@ } } }; - }); + }; + + // Extend the Bootstrap Modal plugin constructor class. + Bootstrap.extendPlugin('modal', Bootstrap.Modal.Bridge); + + // Register default core dialog type handlers. + Bootstrap.Dialog.Handler.register('dialog'); + Bootstrap.Dialog.Handler.register('modal'); /** * Extend Drupal theming functions. diff --git a/js/modal.js b/js/modal.js index 58be56f..ac39137 100644 --- a/js/modal.js +++ b/js/modal.js @@ -1,6 +1,11 @@ /** * @file * Bootstrap Modals. + * + * @param {jQuery} $ + * @param {Drupal} Drupal + * @param {Drupal.bootstrap} Bootstrap + * @param {Attributes} Attributes */ (function ($, Drupal, Bootstrap, Attributes) { 'use strict'; @@ -65,15 +70,16 @@ var BootstrapModal = this; // Override the Modal constructor. - var Modal = function (element, options) { + Bootstrap.Modal = function (element, options) { this.$body = $(document.body); this.$element = $(element); this.$dialog = this.$element.find('.modal-dialog'); this.$header = this.$dialog.find('.modal-header'); + this.$title = this.$dialog.find('.modal-title'); this.$close = this.$header.find('.close'); this.$footer = this.$dialog.find('.modal-footer'); this.$content = this.$dialog.find('.modal-content'); - this.$dialogBody = this.$content.find('.modal-body'); + this.$dialogBody = this.$dialog.find('.modal-body'); this.$backdrop = null; this.isShown = null; this.originalBodyPad = null; @@ -83,7 +89,7 @@ }; // Extend defaults to take into account for theme settings. - Modal.DEFAULTS = $.extend({}, BootstrapModal.DEFAULTS, { + Bootstrap.Modal.DEFAULTS = $.extend({}, BootstrapModal.DEFAULTS, { animation: !!settings.modal_animation, backdrop: settings.modal_backdrop === 'static' ? 'static' : !!settings.modal_backdrop, focusInput: !!settings.modal_focus_input, @@ -95,12 +101,12 @@ }); // Copy over the original prototype methods. - Modal.prototype = BootstrapModal.prototype; + Bootstrap.Modal.prototype = BootstrapModal.prototype; /** * Handler for $.fn.modal('destroy'). */ - Modal.prototype.destroy = function () { + Bootstrap.Modal.prototype.destroy = function () { this.hide(); Drupal.detachBehaviors(this.$element[0]); this.$element.removeData('bs.modal').remove(); @@ -109,7 +115,7 @@ /** * Initialize the modal. */ - Modal.prototype.init = function () { + Bootstrap.Modal.prototype.init = function () { if (this.options.remote) { this.$content.load(this.options.remote, $.proxy(function () { this.$element.trigger('loaded.bs.modal'); @@ -125,7 +131,7 @@ * @param {Object} options * The passed options. */ - Modal.prototype.mapDialogOptions = function (options) { + Bootstrap.Modal.prototype.mapDialogOptions = function (options) { return options || {}; } @@ -154,11 +160,11 @@ return; } - options = Bootstrap.normalizeObject($.extend({}, Modal.DEFAULTS, data && data.options, $this.data(), options)); + options = Bootstrap.normalizeObject($.extend({}, Bootstrap.Modal.DEFAULTS, data && data.options, $this.data(), options)); delete options['bs.modal']; if (!data) { - $this.data('bs.modal', (data = new Modal(this, options))); + $this.data('bs.modal', (data = new Bootstrap.Modal(this, options))); initialize = true; } @@ -196,7 +202,7 @@ }; // Replace the plugin constructor with the new Modal constructor. - Plugin.Constructor = Modal; + Plugin.Constructor = Bootstrap.Modal; // Replace the data API so that it calls $.fn.modal rather than Plugin. // This allows sub-themes to replace the jQuery Plugin if they like with @@ -514,28 +520,76 @@ }; variables = $.extend(true, {}, defaults, variables); - var title = variables.title; + if (typeof variables.title === 'string') { + variables.title = $.extend({}, defaults, { content: variables.title }); + } + + variables.title.attributes = Attributes.create(defaults.title.attributes).merge(variables.title.attributes); + + var title = Drupal.theme('bootstrapModalTitle', variables.title); if (title) { var attributes = Attributes.create(defaults.attributes).merge(variables.attributes); attributes.set('id', attributes.get('id', variables.id + '--header')); - if (typeof title === 'string') { - title = $.extend({}, defaults.title, { content: title }); - } - output += ''; if (variables.closeButton) { output += Drupal.theme('bootstrapModalClose', _.omit(variables, 'attributes')); } - output += '<' + Drupal.checkPlain(title.tag) + Attributes.create(defaults.title.attributes).merge(title.attributes) + '>' + (title.html ? title.content : Drupal.checkPlain(title.content)) + ''; + output += title; output += ''; } + return output; + }, + + /** + * Theme function for a Bootstrap Modal title. + * + * @param {Object} [variables] + * An object containing key/value pairs of variables. + * + * @return {string} + * The HTML for the modal title. + */ + bootstrapModalTitle: function (variables) { + var output = ''; + + var defaults = { + attributes: { + class: ['modal-title'] + }, + closeButton: true, + id: 'drupal-modal', + content: Drupal.t('Loading...'), + html: false, + tag: 'h4' + }; + + if (typeof variables === 'string') { + variables = $.extend({}, defaults, { content: title }); + } + + variables = $.extend(true, {}, defaults, variables); + + var attributes = Attributes.create(defaults.attributes).merge(variables.attributes); + attributes.set('id', attributes.get('id', variables.id + '--title')); + + output += '<' + Drupal.checkPlain(variables.tag) + Attributes.create(defaults.attributes).merge(variables.attributes) + '>'; + + if (variables.closeButton) { + output += Drupal.theme('bootstrapModalClose', _.omit(variables, 'attributes')); + } + + output += (variables.html ? variables.content : Drupal.checkPlain(variables.content)); + + output += ''; + return output; } + }) }); diff --git a/src/Plugin/Alter/LibraryInfo.php b/src/Plugin/Alter/LibraryInfo.php index 09dbe8a..5aa12a6 100644 --- a/src/Plugin/Alter/LibraryInfo.php +++ b/src/Plugin/Alter/LibraryInfo.php @@ -55,11 +55,13 @@ class LibraryInfo extends PluginBase implements AlterInterface { unset($libraries['drupal.dialog']['js']['misc/dialog/dialog.jquery-ui.js']); // Add the Modal jQuery UI Bridge. + $libraries['drupal.dialog']['dependencies'][] = 'bootstrap/dialog'; $libraries['drupal.dialog']['dependencies'][] = 'bootstrap/modal.jquery.ui.bridge'; } // Otherwise, just append the modal. else { $libraries['drupal.dialog']['dependencies'][] = 'bootstrap/modal'; + $libraries['drupal.dialog']['dependencies'][] = 'bootstrap/dialog'; } } } -- 2.20.1 (Apple Git-117)