first commit

This commit is contained in:
2024-07-15 12:33:27 +02:00
commit ce50ae282b
22084 changed files with 2623791 additions and 0 deletions

View File

@@ -0,0 +1,603 @@
/**
* @file
* Bootstrap Modals.
*
* @param {jQuery} $
* @param {Drupal} Drupal
* @param {Drupal.bootstrap} Bootstrap
* @param {Attributes} Attributes
*/
(function ($, Drupal, Bootstrap, Attributes) {
'use strict';
/**
* Document jQuery object.
*
* @type {jQuery}
*/
var $document = $(document);
/**
* Finds the first available and visible focusable input element.
*
* This is abstracted from the main code below so sub-themes can override
* this method to return their own element if desired.
*
* @param {Modal} modal
* The Bootstrap modal instance.
*
* @return {jQuery}
* A jQuery object containing the element that should be focused. Note: if
* this object contains multiple elements, only the first visible one will
* be used.
*/
Bootstrap.modalFindFocusableElement = function (modal) {
return modal.$dialogBody.find(':input,:button,.btn').not('.visually-hidden,.sr-only');
};
$document.on('shown.bs.modal', function (e) {
var $modal = $(e.target);
var modal = $modal.data('bs.modal');
// Check if there are any CKEditor 5 instances
var $ckeditor = $modal.find('[data-ckeditor5-id]');
if ($ckeditor.length) {
// Move the overlay wrapper inside the modal so it can be interacted with
$('.ck-body-wrapper').appendTo($modal);
}
// Focus the first input element found.
if (modal && modal.options.focusInput) {
var $focusable = Bootstrap.modalFindFocusableElement(modal);
if ($focusable && $focusable[0]) {
var $input = $focusable.filter(':visible:first').focus();
// Select text if input is text.
if (modal.options.selectText && $input.is(':text')) {
$input[0].setSelectionRange(0, $input[0].value.length)
}
}
else if (modal.$close.is(':visible')) {
modal.$close.focus();
}
}
});
/**
* Only process this once.
*/
Bootstrap.once('modal', function (settings) {
/**
* Replace the Bootstrap Modal jQuery plugin definition.
*
* This adds a little bit of functionality so it works better with Drupal.
*/
Bootstrap.replacePlugin('modal', function () {
var BootstrapModal = this;
// Override the Modal constructor.
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.$dialog.find('.modal-body');
this.$backdrop = null;
this.isShown = null;
this.originalBodyPad = null;
this.scrollbarWidth = 0;
this.ignoreBackdropClick = false;
this.options = this.mapDialogOptions(options);
};
// Extend defaults to take into account for theme settings.
Bootstrap.Modal.DEFAULTS = $.extend({}, BootstrapModal.DEFAULTS, {
animation: !!settings.modal_animation,
backdrop: settings.modal_backdrop === 'static' ? 'static' : !!settings.modal_backdrop,
focusInput: !!settings.modal_focus_input,
selectText: !!settings.modal_select_text,
keyboard: !!settings.modal_keyboard,
remote: null,
show: !!settings.modal_show,
size: settings.modal_size
});
// Copy over the original prototype methods.
Bootstrap.Modal.prototype = BootstrapModal.prototype;
/**
* Handler for $.fn.modal('destroy').
*/
Bootstrap.Modal.prototype.destroy = function () {
this.hide();
Drupal.detachBehaviors(this.$element[0]);
this.$element.removeData('bs.modal').remove();
};
/**
* Initialize the modal.
*/
Bootstrap.Modal.prototype.init = function () {
if (this.options.remote) {
this.$content.load(this.options.remote, $.proxy(function () {
this.$element.trigger('loaded.bs.modal');
}, this));
}
};
/**
* Map dialog options.
*
* Note: this is primarily for use in modal.jquery.ui.bridge.js.
*
* @param {Object} options
* The passed options.
*/
Bootstrap.Modal.prototype.mapDialogOptions = function (options) {
return options || {};
}
// Modal jQuery Plugin Definition.
var Plugin = function () {
// Extract the arguments.
var args = Array.prototype.slice.call(arguments);
var method = args[0];
var options = args[1] || {};
var relatedTarget = args[2] || null;
// Move arguments down if no method was passed.
if ($.isPlainObject(method)) {
relatedTarget = options || null;
options = method;
method = null;
}
var ret = void 0;
this.each(function () {
var $this = $(this);
var data = $this.data('bs.modal');
var initialize = false;
// Immediately return if there's no instance to invoke a valid method.
var showMethods = ['open', 'show', 'toggle'];
if (!data && method && showMethods.indexOf(method) === -1) {
return;
}
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 Bootstrap.Modal(this, options)));
initialize = true;
}
// Initialize the modal.
if (initialize || (!method && !args.length)) {
data.init();
}
// Explicit method passed.
if (method) {
if (typeof data[method] === 'function') {
try {
ret = data[method].apply(data, args.slice(1));
}
catch (e) {
Drupal.throwError(e);
}
}
else {
Bootstrap.unsupported('method', method);
}
}
// No method, set options and open if necessary.
else {
data.option(options);
if (options.show && !data.isShown) {
data.show(relatedTarget);
}
}
});
// 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;
};
// Replace the plugin constructor with the new Modal constructor.
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
// out having to redo all this boilerplate.
$document
.off('click.bs.modal.data-api')
.on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
var $this = $(this);
var href = $this.attr('href');
var target = $this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, '')); // strip for ie7
var $target = $document.find(target);
var options = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data());
if ($this.is('a')) e.preventDefault();
$target.one('show.bs.modal', function (showEvent) {
// Only register focus restorer if modal will actually get shown.
if (showEvent.isDefaultPrevented()) return;
$target.one('hidden.bs.modal', function () {
$this.is(':visible') && $this.trigger('focus');
});
});
$target.modal(options, this);
});
return Plugin;
});
/**
* Extend Drupal theming functions.
*/
$.extend(Drupal.theme, /** @lend Drupal.theme */ {
/**
* Theme function for a Bootstrap Modal.
*
* @param {Object} [variables]
* An object containing key/value pairs of variables.
*
* @return {string}
* The HTML for the modal.
*/
bootstrapModal: function (variables) {
var output = '';
var settings = drupalSettings.bootstrap || {};
var defaults = {
attributes: {
class: ['modal'],
tabindex: -1,
role: 'dialog'
},
body: '',
closeButton: true,
description: {
attributes: {
class: ['help-block']
},
content: null,
position: 'before'
},
footer: '',
id: 'drupal-modal',
size: settings.modal_size ? settings.modal_size : '',
title: {
attributes: {
class: ['modal-title']
},
content: Drupal.t('Loading...'),
html: false,
tag: 'h4'
}
};
variables = $.extend(true, {}, defaults, variables);
var attributes = Attributes.create(defaults.attributes).merge(variables.attributes);
attributes.set('id', attributes.get('id', variables.id));
if (settings.modal_animation) {
attributes.addClass('fade');
}
// Build the modal wrapper.
output += '<div' + attributes + '>';
// Build the modal-dialog wrapper.
output += Drupal.theme('bootstrapModalDialog', _.omit(variables, 'attributes'));
// Close the modal wrapper.
output += '</div>';
// Return the constructed modal.
return output;
},
/**
* Theme function for a Bootstrap Modal dialog markup.
*
* @param {Object} [variables]
* An object containing key/value pairs of variables.
*
* @return {string}
* The HTML for the modal close button.
*/
bootstrapModalDialog: function (variables) {
var output = '';
var defaults = {
attributes: {
class: ['modal-dialog'],
role: 'document'
},
id: 'drupal-modal'
};
variables = $.extend(true, {}, defaults, variables);
var attributes = Attributes.create(defaults.attributes).merge(variables.attributes);
attributes.set('id', attributes.get('id', variables.id + '--dialog'));
if (variables.size) {
attributes.addClass(variables.size);
}
output += '<div' + attributes + '>';
// Build the modal-content wrapper.
output += Drupal.theme('bootstrapModalContent', _.omit(variables, 'attributes'));
// Close the modal-dialog wrapper.
output += '</div>';
return output;
},
/**
* Theme function for a Bootstrap Modal content markup.
*
* @param {Object} [variables]
* An object containing key/value pairs of variables.
*
* @return {string}
* The HTML for the modal close button.
*/
bootstrapModalContent: function (variables) {
var output = '';
var defaults = {
attributes: {
class: ['modal-content']
},
id: 'drupal-modal'
};
variables = $.extend(true, {}, defaults, variables);
var attributes = Attributes.create(defaults.attributes).merge(variables.attributes);
attributes.set('id', attributes.get('id', variables.id + '--content'));
// Build the modal-content wrapper.
output += '<div' + attributes + '>';
variables = _.omit(variables, 'attributes');
// Build the header wrapper and title.
output += Drupal.theme('bootstrapModalHeader', variables);
// Build the body.
output += Drupal.theme('bootstrapModalBody', variables);
// Build the footer.
output += Drupal.theme('bootstrapModalFooter', variables);
// Close the modal-content wrapper.
output += '</div>';
return output;
},
/**
* Theme function for a Bootstrap Modal body markup.
*
* @param {Object} [variables]
* An object containing key/value pairs of variables.
*
* @return {string}
* The HTML for the modal close button.
*/
bootstrapModalBody: function (variables) {
var output = '';
var defaults = {
attributes: {
class: ['modal-body']
},
body: '',
description: {
attributes: {
class: ['help-block']
},
content: null,
position: 'before'
},
id: 'drupal-modal'
};
variables = $.extend(true, {}, defaults, variables);
var attributes = Attributes.create(defaults.attributes).merge(variables.attributes);
attributes.set('id', attributes.get('id', variables.id + '--body'));
output += '<div' + attributes + '>';
if (typeof variables.description === 'string') {
variables.description = $.extend({}, defaults.description, { content: variables.description });
}
var description = variables.description;
description.attributes = Attributes.create(defaults.description.attributes).merge(description.attributes);
if (description.content && description.position === 'invisible') {
description.attributes.addClass('sr-only');
}
if (description.content && description.position === 'before') {
output += '<p' + description.attributes + '>' + description.content + '</p>';
}
output += variables.body;
if (description.content && (description.position === 'after' || description.position === 'invisible')) {
output += '<p' + description.attributes + '>' + description.content + '</p>';
}
output += '</div>';
return output;
},
/**
* Theme function for a Bootstrap Modal close button.
*
* @param {Object} [variables]
* An object containing key/value pairs of variables.
*
* @return {string}
* The HTML for the modal close button.
*/
bootstrapModalClose: function (variables) {
var defaults = {
attributes: {
'aria-label': Drupal.t('Close'),
class: ['close'],
'data-dismiss': 'modal',
type: 'button'
}
};
variables = $.extend(true, {}, defaults, variables);
var attributes = Attributes.create(defaults.attributes).merge(variables.attributes);
return '<button' + attributes + '><span aria-hidden="true">&times;</span></button>';
},
/**
* Theme function for a Bootstrap Modal footer.
*
* @param {Object} [variables]
* An object containing key/value pairs of variables.
* @param {boolean} [force]
* Flag to force rendering the footer, regardless if there's content.
*
* @return {string}
* The HTML for the modal footer.
*/
bootstrapModalFooter: function (variables, force) {
var output = '';
var defaults = {
attributes: {
class: ['modal-footer']
},
footer: '',
id: 'drupal-modal'
};
variables = $.extend(true, {}, defaults, variables);
if (force || variables.footer) {
var attributes = Attributes.create(defaults.attributes).merge(variables.attributes);
attributes.set('id', attributes.get('id', variables.id + '--footer'));
output += '<div' + attributes + '>';
output += variables.footer;
output += '</div>';
}
return output;
},
/**
* Theme function for a Bootstrap Modal header.
*
* @param {Object} [variables]
* An object containing key/value pairs of variables.
*
* @return {string}
* The HTML for the modal header.
*/
bootstrapModalHeader: function (variables) {
var output = '';
var defaults = {
attributes: {
class: ['modal-header']
},
closeButton: true,
id: 'drupal-modal',
title: {
attributes: {
class: ['modal-title']
},
content: Drupal.t('Loading...'),
html: false,
tag: 'h4'
}
};
variables = $.extend(true, {}, defaults, variables);
if (typeof variables.title === 'string') {
variables.title = $.extend({}, defaults.title, { content: variables.title });
}
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'));
output += '<div' + attributes + '>';
if (variables.closeButton) {
output += Drupal.theme('bootstrapModalClose', _.omit(variables, 'attributes'));
}
output += title;
output += '</div>';
}
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 += '</' + Drupal.checkPlain(variables.tag) + '>';
return output;
}
})
});
})(window.jQuery, window.Drupal, window.Drupal.bootstrap, window.Attributes);