Files
2024-07-15 12:33:27 +02:00

173 lines
5.5 KiB
JavaScript

/**
* @file
* dialog.js
*/
(function ($, Drupal, Bootstrap, Attributes) {
Bootstrap.Dialog = Bootstrap.Dialog || {};
/**
* A collection of Drupal dialog handlers.
*
* @type {Object<String, Drupal.bootstrap.Dialog.Handler>}
*/
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);