/** * @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; } var attributes = Attributes.create(element).remove('style').set('data-drupal-theme', this.themeHooks.modal); // Merge in trigger data attributes. if (options.$trigger && options.$trigger[0]) { /** @var {HTMLElement} trigger */ var trigger = options.$trigger[0]; var data = {}; for (var i = 0, l = trigger.attributes.length; i < l; i++) { var name = trigger.attributes[i].name; if (name && name.substring(0, 5) === 'data-') { data[name] = trigger.getAttribute(name); } } attributes.merge(data); } options = $.extend(true, {}, options, { attributes: attributes, }); // 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);