diff --git a/js/modal.jquery.ui.bridge.js b/js/modal.jquery.ui.bridge.js index d7f08e28a672fe81b3a62fd2b37f12a002d03ab4..53a5484f7b9a7f088c561acbc5939225bd8b188c 100644 --- a/js/modal.jquery.ui.bridge.js +++ b/js/modal.jquery.ui.bridge.js @@ -38,58 +38,69 @@ /** * Proxy $.fn.dialog to $.fn.modal. */ - Bootstrap.createPlugin('dialog', function (options) { + 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(function () { - // This part gets a little tricky. Core can potentially already - // semi-process this "dialog" if was created using an Ajax command - // (i.e. prepareDialogButtons in drupal.ajax.js). Because of this, - // we cannot simply dump the existing dialog content into a newly - // created modal because that would destroy any existing event - // bindings. Instead, we have to create this in steps and "move" - // (append) the existing content as needed. - var $this = $(this); - - // Create a new modal to get a complete template. - var $modal = $(Drupal.theme('bootstrapModal', {attributes: Attributes.create(this).remove('style')})); - - // Store a reference to the content inside the existing dialog. - // 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 $existing = $this.contents(); - - // Destroy any existing Bootstrap Modal data that may have been saved. - $this.removeData('bs.modal'); - - // Set the attributes of the dialog to that of the newly created modal. - $this.attr(Attributes.create($modal).toPlainObject()); - - // Append the newly created modal markup. - $this.append($modal.html()); - - // Move the existing HTML into the modal markup that was just appended. - $this.find('.modal-body').append($existing); - }); - - // Indicate that the modal is a jQuery UI dialog bridge. - options = { + this.each($.fn.dialog.ensureModalStructure); + + // Proxy to the Bootstrap Modal plugin, indicating that this is a + // jQuery UI dialog bridge. + return $.fn.modal.apply(this, [{ dialogOptions: options, jQueryUiBridge: true - }; - - // Proxy just the options to the Bootstrap Modal plugin. - return $.fn.modal.apply(this, [options]); + }]); } // 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; + } + + // 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); + }; + + Bootstrap.createPlugin('dialog', Dialog); /** * Extend the Bootstrap Modal plugin constructor class. diff --git a/js/modal.js b/js/modal.js index 151bc193e316c5e0a9786eee8233d9deddabbfc9..58be56f084e5872dab01a5e328cfef90647cf334 100644 --- a/js/modal.js +++ b/js/modal.js @@ -155,6 +155,7 @@ } options = Bootstrap.normalizeObject($.extend({}, Modal.DEFAULTS, data && data.options, $this.data(), options)); + delete options['bs.modal']; if (!data) { $this.data('bs.modal', (data = new Modal(this, options))); @@ -180,12 +181,10 @@ Bootstrap.unsupported('method', method); } } + // No method, set options and open if necessary. else { - // If no method set the options. data.option(options); - - // Handle native modal showing. - if (!options.jQueryUiBridge && options.show && !data.isShown) { + if (options.show && !data.isShown) { data.show(relatedTarget); } }