diff --git a/administrator/components/com_content/tmpl/articles/default.php b/administrator/components/com_content/tmpl/articles/default.php
index 1cb2e2cbe0d4b..dd8b9eba43527 100644
--- a/administrator/components/com_content/tmpl/articles/default.php
+++ b/administrator/components/com_content/tmpl/articles/default.php
@@ -26,6 +26,9 @@
HTMLHelper::_('behavior.multiselect');
+// Just for the tests :(
+HTMLHelper::_('jquery.framework');
+
$app = Factory::getApplication();
$user = Factory::getUser();
$userId = $user->get('id');
diff --git a/administrator/components/com_fields/tmpl/fields/default.php b/administrator/components/com_fields/tmpl/fields/default.php
index fefd4b33848a4..b5dc679539f30 100644
--- a/administrator/components/com_fields/tmpl/fields/default.php
+++ b/administrator/components/com_fields/tmpl/fields/default.php
@@ -20,6 +20,9 @@
HTMLHelper::_('behavior.multiselect');
+// Just for the tests :(
+HTMLHelper::_('jquery.framework');
+
$app = Factory::getApplication();
$user = Factory::getUser();
$userId = $user->get('id');
diff --git a/administrator/components/com_joomlaupdate/tmpl/update/default.php b/administrator/components/com_joomlaupdate/tmpl/update/default.php
index 474a52ed3f334..f1aaf9b569eb7 100644
--- a/administrator/components/com_joomlaupdate/tmpl/update/default.php
+++ b/administrator/components/com_joomlaupdate/tmpl/update/default.php
@@ -16,6 +16,7 @@
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('core')
+ ->useScript('jquery')
->useScript('com_joomlaupdate.encryption')
->useScript('com_joomlaupdate.update')
->useScript('com_joomlaupdate.admin-update');
diff --git a/administrator/components/com_joomlaupdate/tmpl/upload/captive.php b/administrator/components/com_joomlaupdate/tmpl/upload/captive.php
index 9ee1118249fbb..bc7b120d29d23 100644
--- a/administrator/components/com_joomlaupdate/tmpl/upload/captive.php
+++ b/administrator/components/com_joomlaupdate/tmpl/upload/captive.php
@@ -20,6 +20,7 @@
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = $this->document->getWebAssetManager();
$wa->useScript('core')
+ ->useScript('jquery')
->useScript('form.validate')
->useScript('keepalive')
->useScript('field.passwordview');
diff --git a/administrator/components/com_mails/tmpl/templates/default.php b/administrator/components/com_mails/tmpl/templates/default.php
index 79b5a09079555..93a901cbc87e3 100644
--- a/administrator/components/com_mails/tmpl/templates/default.php
+++ b/administrator/components/com_mails/tmpl/templates/default.php
@@ -14,6 +14,8 @@
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
+HTMLHelper::_('bootstrap.dropdown');
+
$listOrder = $this->escape($this->state->get('list.ordering'));
$listDirn = $this->escape($this->state->get('list.direction'));
?>
diff --git a/administrator/components/com_templates/tmpl/template/default.php b/administrator/components/com_templates/tmpl/template/default.php
index 816b566f857d0..adb24ed855799 100644
--- a/administrator/components/com_templates/tmpl/template/default.php
+++ b/administrator/components/com_templates/tmpl/template/default.php
@@ -376,7 +376,7 @@
);
?>
type != 'home') : ?>
@@ -391,7 +391,7 @@
);
?>
@@ -406,7 +406,7 @@
'body' => $this->loadTemplate('modal_delete_body')
);
?>
-
+
$this->loadTemplate('modal_file_body')
);
?>
-
+
'folderModal',
@@ -437,7 +437,7 @@
'body' => $this->loadTemplate('modal_folder_body')
);
?>
-
+
type == 'image') : ?>
diff --git a/build/build-modules-js/build-bootstrap-js.es6.js b/build/build-modules-js/build-bootstrap-js.es6.js
new file mode 100644
index 0000000000000..fae0380489f06
--- /dev/null
+++ b/build/build-modules-js/build-bootstrap-js.es6.js
@@ -0,0 +1,155 @@
+const {
+ readdir, readFile, rename, writeFile, rm,
+} = require('fs').promises;
+const { resolve } = require('path');
+const { minify } = require('terser');
+const rimraf = require('rimraf');
+const rollup = require('rollup');
+const { nodeResolve } = require('@rollup/plugin-node-resolve');
+const replace = require('@rollup/plugin-replace');
+const { babel } = require('@rollup/plugin-babel');
+
+const tasks = [];
+const inputFolder = 'build/media_source/vendor/bootstrap/js';
+const outputFolder = 'media/vendor/bootstrap/js';
+
+const createMinified = async (file) => {
+ const initial = await readFile(resolve(outputFolder, file), { encoding: 'utf8' });
+ const mini = await minify(initial);
+ await rename(resolve(outputFolder, file), resolve(outputFolder, `${file.split('-')[0]}.es6.js`));
+ await writeFile(resolve(outputFolder, `${file.split('-')[0]}.es6.min.js`), mini.code, { encoding: 'utf8' });
+};
+
+const build = async () => {
+ // eslint-disable-next-line no-console
+ console.log('Building ES6 Components...');
+
+ const bundle = await rollup.rollup({
+ input: resolve(inputFolder, 'index.es6.js'),
+ plugins: [
+ nodeResolve(),
+ replace({
+ 'process.env.NODE_ENV': '\'production\'',
+ }),
+ ],
+ external: [
+ './base-component.js',
+ './dom/data.js',
+ './event-handler.js',
+ './dom/manipulator.js',
+ './selector-engine.js',
+ './util/index.js',
+ ],
+ manualChunks: {
+ alert: ['build/media_source/vendor/bootstrap/js/alert.es6.js'],
+ button: ['build/media_source/vendor/bootstrap/js/button.es6.js'],
+ carousel: ['build/media_source/vendor/bootstrap/js/carousel.es6.js'],
+ collapse: ['build/media_source/vendor/bootstrap/js/collapse.es6.js'],
+ dropdown: ['build/media_source/vendor/bootstrap/js/dropdown.es6.js'],
+ modal: ['build/media_source/vendor/bootstrap/js/modal.es6.js'],
+ popover: ['build/media_source/vendor/bootstrap/js/popover.es6.js'],
+ scrollspy: ['build/media_source/vendor/bootstrap/js/scrollspy.es6.js'],
+ tab: ['build/media_source/vendor/bootstrap/js/tab.es6.js'],
+ toast: ['build/media_source/vendor/bootstrap/js/toast.es6.js'],
+ popper: ['@popperjs/core'],
+ dom: [
+ 'node_modules/bootstrap/js/src/base-component.js',
+ 'node_modules/bootstrap/js/src/dom/data.js',
+ 'node_modules/bootstrap/js/src/dom/event-handler.js',
+ 'node_modules/bootstrap/js/src/dom/manipulator.js',
+ 'node_modules/bootstrap/js/src/dom/selector-engine.js',
+ 'node_modules/bootstrap/js/src/util/index.js',
+ ],
+ },
+ });
+
+ await bundle.write({
+ format: 'es',
+ sourcemap: false,
+ dir: outputFolder,
+ });
+};
+
+const buildLegacy = async () => {
+ // eslint-disable-next-line no-console
+ console.log('Building Legacy...');
+
+ const bundle = await rollup.rollup({
+ input: resolve(inputFolder, 'index.es6.js'),
+ plugins: [
+ nodeResolve(),
+ replace({
+ 'process.env.NODE_ENV': '\'production\'',
+ }),
+ babel({
+ exclude: 'node_modules/core-js/**',
+ babelHelpers: 'bundled',
+ babelrc: false,
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ corejs: '3.8',
+ useBuiltIns: 'usage',
+ targets: {
+ chrome: '58',
+ ie: '11',
+ },
+ loose: true,
+ bugfixes: true,
+ modules: false,
+ },
+ ],
+ ],
+ }),
+ ],
+ external: [],
+ });
+
+ await bundle.write({
+ format: 'iife',
+ sourcemap: false,
+ name: 'Bootstrap',
+ file: resolve(outputFolder, 'bootstrap.es5.js'),
+ });
+};
+
+(async () => {
+ rimraf.sync(resolve(outputFolder));
+
+ try {
+ await build(resolve(inputFolder, 'index.es6.js'));
+ await rm(resolve(outputFolder, 'index.es6.js'));
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.error(error);
+ process.exit(1);
+ }
+
+ (await readdir(outputFolder)).forEach((file) => {
+ if (!(file.startsWith('dom-') || file.startsWith('popper-'))) {
+ tasks.push(createMinified(file));
+ }
+ });
+
+ await Promise.all(tasks).catch((er) => {
+ // eslint-disable-next-line no-console
+ console.log(er);
+ process.exit(1);
+ });
+ // eslint-disable-next-line no-console
+ console.log('ES6 components ready ✅');
+
+ try {
+ await buildLegacy(inputFolder, 'index.es6.js');
+ const es5File = await readFile(resolve(outputFolder, 'bootstrap.es5.js'), { encoding: 'utf8' });
+ const mini = await minify(es5File);
+ await writeFile(resolve(outputFolder, 'bootstrap.es5.min.js'), mini.code, { encoding: 'utf8' });
+ // eslint-disable-next-line no-console
+ console.log('Legacy done! ✅');
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.error(error);
+ process.exit(1);
+ }
+})();
diff --git a/build/build-modules-js/compilejs.es6.js b/build/build-modules-js/compilejs.es6.js
index e4cf2c3bd6581..d79c201236c01 100644
--- a/build/build-modules-js/compilejs.es6.js
+++ b/build/build-modules-js/compilejs.es6.js
@@ -1,4 +1,5 @@
const Fs = require('fs');
+const { sep } = require('path');
const Recurs = require('recursive-readdir');
const HandleFile = require('./javascript/handle-file.es6.js');
@@ -45,6 +46,9 @@ module.exports.compileJS = (options, path) => {
(files) => {
files.forEach(
(file) => {
+ if (file.includes(`build${sep}media_source${sep}vendor${sep}bootstrap${sep}js`)) {
+ return;
+ }
HandleFile.run(file);
},
(error) => {
diff --git a/build/build-modules-js/settings.json b/build/build-modules-js/settings.json
index c12c0e4de3d16..51e58b3cdcd6e 100644
--- a/build/build-modules-js/settings.json
+++ b/build/build-modules-js/settings.json
@@ -39,13 +39,6 @@
},
"bootstrap": {
"name": "bootstrap",
- "js": {
- "dist/js/bootstrap.js": "js/bootstrap.js",
- "dist/js/bootstrap.min.js": "js/bootstrap.min.js",
- "dist/js/bootstrap.bundle.js": "js/bootstrap.bundle.js",
- "dist/js/bootstrap.bundle.min.js": "js/bootstrap.bundle.min.js",
- "dist/js/bootstrap.bundle.min.js.map": "js/bootstrap.bundle.min.js.map"
- },
"css": {
"dist/css/bootstrap.css": "css/bootstrap.css",
"dist/css/bootstrap.min.css": "css/bootstrap.min.css",
@@ -76,22 +69,6 @@
"dependencies": [
"bootstrap.css"
]
- },
- {
- "name": "bootstrap.js",
- "type": "script",
- "uri": "bootstrap.min.js",
- "dependencies": [
- "jquery"
- ]
- },
- {
- "name": "bootstrap.js.bundle",
- "type": "script",
- "uri": "bootstrap.bundle.min.js",
- "dependencies": [
- "jquery"
- ]
}
],
"dependencies": [],
diff --git a/build/media_source/com_joomlaupdate/joomla.asset.json b/build/media_source/com_joomlaupdate/joomla.asset.json
index 0f3f6d679889a..73ee972cc431f 100644
--- a/build/media_source/com_joomlaupdate/joomla.asset.json
+++ b/build/media_source/com_joomlaupdate/joomla.asset.json
@@ -10,7 +10,8 @@
"type": "script",
"uri": "com_joomlaupdate/admin-update-default.min.js",
"dependencies": [
- "core"
+ "core",
+ "jquery"
],
"attributes": {
"defer": true
@@ -21,7 +22,8 @@
"type": "script",
"uri": "com_joomlaupdate/default.min.js",
"dependencies": [
- "core"
+ "core",
+ "jquery"
],
"attributes": {
"defer": true
diff --git a/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js b/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js
index d8ed9104948a5..b5bf3af1c168f 100644
--- a/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js
+++ b/build/media_source/com_workflow/js/admin-items-workflow-buttons.es6.js
@@ -38,7 +38,7 @@ Joomla.toggleAllNextElements = (element, className) => {
'use strict';
document.addEventListener('DOMContentLoaded', () => {
- const dropDownBtn = document.getElementById('toolbar-dropdown-status-group');
+ const dropDownBtn = document.getElementById('toolbar-status-group');
const transitions = [].slice.call(dropDownBtn.querySelectorAll('.button-transition'));
const headline = dropDownBtn.querySelector('.button-transition-headline');
const separator = dropDownBtn.querySelector('.button-transition-separator');
diff --git a/build/media_source/legacy/js/bootstrap-init.es5.js b/build/media_source/legacy/js/bootstrap-init.es5.js
deleted file mode 100644
index fcddb5a673e9e..0000000000000
--- a/build/media_source/legacy/js/bootstrap-init.es5.js
+++ /dev/null
@@ -1,219 +0,0 @@
-Joomla = window.Joomla || {};
-
-(function(Joomla) {
- "use strict";
-
- /**
- * Method to invoke a click on button inside an iframe
- *
- * @param {object} options Object with the css selector for the parent element of an iframe
- * and the selector of the button in the iframe that will be clicked
- * { iframeSelector: '', buttonSelector: '' }
- * @returns {boolean}
- *
- * @since 4.0
- */
- Joomla.iframeButtonClick = function(options) {
- if (!options.iframeSelector || !options.buttonSelector) {
- throw new Error('Selector is missing');
- }
-
- var iframe = document.querySelector(options.iframeSelector + ' iframe');
- if (iframe) {
- var button = iframe.contentWindow.document.querySelector(options.buttonSelector);
- if (button) {
- button.click();
- }
- }
- };
-
- jQuery(document).ready(function($) {
- Joomla.Bootstrap = {};
-
- // Initialize some variables
- var accordion = Joomla.getOptions('bootstrap.accordion'),
- alert = Joomla.getOptions('bootstrap.alert'),
- button = Joomla.getOptions('bootstrap.button'),
- carousel = Joomla.getOptions('bootstrap.carousel'),
- dropdown = Joomla.getOptions('bootstrap.dropdown'),
- modals = [].slice.call(document.querySelectorAll('.joomla-modal')),
- popover = Joomla.getOptions('bootstrap.popover'),
- scrollspy = Joomla.getOptions('bootstrap.scrollspy'),
- tabs = Joomla.getOptions('bootstrap.tabs'),
- tooltip = Joomla.getOptions('bootstrap.tooltip');
-
- Joomla.Bootstrap.initModal = function(element) {
- var $self = $(element);
-
- // Comply with the Joomla API
- // Bound element.open()
- if (element) {
- element.open = function () {
- return $self.modal('show');
- };
-
- // Bound element.close()
- element.close = function () {
- return $self.modal('hide');
- };
- }
-
- $self.on('show.bs.modal', function() {
- // Comply with the Joomla API
- // Set the current Modal ID
- Joomla.Modal.setCurrent(element);
-
- // @TODO throw the standard Joomla event
- if ($self.data('url')) {
- var modalBody = $self.find('.modal-body');
- var el;
- modalBody.find('iframe').remove();
-
- // Hacks because com_associations and field modals use pure javascript in the url!
- if ($self.data('iframe').indexOf("document.getElementById") > 0){
- var iframeTextArr = $self.data('iframe').split('+');
- var idFieldArr = iframeTextArr[1].split('"');
-
- idFieldArr[0] = idFieldArr[0].replace(/"/g,'"');
-
- if (!document.getElementById(idFieldArr[1])) {
- el = eval(idFieldArr[0]);
- } else {
- el = document.getElementById(idFieldArr[1]).value;
- }
-
- var data_iframe = iframeTextArr[0] + el + iframeTextArr[2];
- modalBody.prepend(data_iframe);
- } else {
- modalBody.prepend($self.data('iframe'));
- }
- }
- }).on('shown.bs.modal', function() {
- var modalHeight = $('div.modal:visible').outerHeight(true),
- modalHeaderHeight = $('div.modal-header:visible').outerHeight(true),
- modalBodyHeightOuter = $('div.modal-body:visible').outerHeight(true),
- modalBodyHeight = $('div.modal-body:visible').height(),
- modalFooterHeight = $('div.modal-footer:visible').outerHeight(true),
- padding = $self.offsetTop,
- maxModalHeight = ($(window).height()-(padding*2)),
- modalBodyPadding = (modalBodyHeightOuter-modalBodyHeight),
- maxModalBodyHeight = maxModalHeight-(modalHeaderHeight+modalFooterHeight+modalBodyPadding);
- if ($self.data('url')) {
- var iframeHeight = $('.iframe').height();
- if (iframeHeight > maxModalBodyHeight){
- $('.modal-body').css({'max-height': maxModalBodyHeight, 'overflow-y': 'auto'});
- $('.iframe').css('max-height', maxModalBodyHeight-modalBodyPadding);
- }
- }
- // @TODO throw the standard Joomla event
- }).on('hide.bs.modal', function() {
- $('.modal-body').css({'max-height': 'initial'});
- $('.modalTooltip').tooltip('dispose');
- // @TODO throw the standard Joomla event
- }).on('hidden.bs.modal', function() {
- // Comply with the Joomla API
- // Remove the current Modal ID
- Joomla.Modal.setCurrent('');
- // @TODO throw the standard Joomla event
- });
- };
-
- /** Accordion **/
- if (accordion) {
- $.each(accordion, function(index, value) {
- $('#' + index).collapse(
- {
- parent:value.parent,
- toggle:value.toggle
- }
- ).on("show", new Function(value.onShow)())
- .on("shown", new Function(value.onShown)())
- .on("hideme", new Function(value.onHide)())
- .on("hidden", new Function(value.onHidden)());
- });
- }
-
- /** Alert **/
- if (alert) {
- $.each(alert, function(index, value) {
- $('#' + index).alert();
- });
- }
-
- /** Button **/
- if (button) {
- $.each(button, function(index, value) {
- $('#' + index).button();
- });
- }
-
- /** Carousel **/
- if (carousel) {
- $.each(carousel, function(index, value) {
- $('#' + index).carousel(
- {
- interval: value.interval ? value.interval : 5000,
- pause: value.pause ? value.pause : 'hover'
- }
- );
- });
- }
-
- /** Dropdown menu **/
- if (dropdown) {
- $.each(dropdown, function(index, value) {
- $('#' + index).dropdown();
- });
- }
-
- /** Modals **/
- if (modals.length) {
- modals.forEach(function(modal){ Joomla.Bootstrap.initModal(modal); });
- }
-
- /** Popover **/
- if (popover) {
- $.each(popover, function(index, value) {
- value.constraints = [value.constraints];
- $(index).popover(value);
- });
- }
-
- /** Scrollspy **/
- if (scrollspy) {
- $.each(scrollspy, function(index, value) {
- $('#' + index).scrollspy(value);
- });
- }
-
- /** Tabs **/
- if (tabs) {
- $.each(tabs, function(index, value) {
-
- $.each($('#' + index + 'Content').children('.tab-pane'), function(i, v) {
- var titleAttribute = $(v).data('title');
- var activeAttribute = $(v).data('active');
- var idAttribute = $(v).data('id');
-
- if (titleAttribute) {
- var classLink = (activeAttribute != '') ? 'class="nav-link ' + activeAttribute + '"' : 'class="nav-link"';
-
- $('#' + index + 'Tabs').append('' + titleAttribute + ' ');
- }
- });
- });
- }
-
- /** Tooltip **/
- if (tooltip) {
- $.each(tooltip, function(index, value) {
- value.constraints = [value.constraints];
- $(index).tooltip(value)
- .on("show.bs.tooltip", new Function(value.onShow)())
- .on("shown.bs.tooltip", new Function(value.onShown)())
- .on("hide.bs.tooltip", new Function(value.onHide)())
- .on("hidden.bs.tooltip", new Function(value.onHidden)());
- });
- }
- });
-})(Joomla);
diff --git a/build/media_source/mod_multilangstatus/js/admin-multilangstatus.es6.js b/build/media_source/mod_multilangstatus/js/admin-multilangstatus.es6.js
index fe6a8f5704619..6ed4c77f5a18b 100644
--- a/build/media_source/mod_multilangstatus/js/admin-multilangstatus.es6.js
+++ b/build/media_source/mod_multilangstatus/js/admin-multilangstatus.es6.js
@@ -19,6 +19,9 @@
// Append clone before closing body tag
document.body.appendChild(clone);
+
+ // Modal was moved so it needs to be re initialised
+ Joomla.Bootstrap.Initialise.Modal(clone);
}
});
})();
diff --git a/build/media_source/system/js/fields/joomla-field-media.w-c.es6.js b/build/media_source/system/js/fields/joomla-field-media.w-c.es6.js
index ddef064859ad8..0bd84616a5663 100644
--- a/build/media_source/system/js/fields/joomla-field-media.w-c.es6.js
+++ b/build/media_source/system/js/fields/joomla-field-media.w-c.es6.js
@@ -102,7 +102,7 @@
&& Joomla.Bootstrap.Instances
&& Joomla.Bootstrap.Instances.Modal
&& Joomla.Bootstrap.Instances.Modal.get(this.modalElement) === undefined) {
- Joomla.Bootstrap.Methods.initModal(this.modalElement);
+ Joomla.Bootstrap.Initialise.Modal(this.modalElement, { isJoomla: true });
}
if (this.buttonClearEl) {
diff --git a/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js b/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js
index 491dcf6f3156c..4716b1895cd2f 100644
--- a/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js
+++ b/build/media_source/system/js/fields/joomla-field-user.w-c.es6.js
@@ -59,7 +59,7 @@
&& Joomla.Bootstrap.Instances
&& Joomla.Bootstrap.Instances.Modal
&& Joomla.Bootstrap.Instances.Modal.get(this.modal) === undefined) {
- Joomla.Bootstrap.Methods.initModal(this.modal);
+ Joomla.Bootstrap.Initialise.Modal(this.modal, { isJoomla: true });
}
if (this.buttonSelect) {
diff --git a/build/media_source/vendor/bootstrap/js/alert.es6.js b/build/media_source/vendor/bootstrap/js/alert.es6.js
new file mode 100644
index 0000000000000..c677fd9024bd6
--- /dev/null
+++ b/build/media_source/vendor/bootstrap/js/alert.es6.js
@@ -0,0 +1,39 @@
+import Alert from '../../../../../node_modules/bootstrap/js/src/alert';
+
+Joomla = Joomla || {};
+Joomla.Bootstrap = Joomla.Bootstrap || {};
+Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
+Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
+Joomla.Bootstrap.Instances.Alert = new WeakMap();
+
+/**
+ * Initialise the Alert iteractivity
+ *
+ * @param {HTMLElement} el The element that will become an Alert
+ */
+Joomla.Bootstrap.Initialise.Alert = (el) => {
+ if (!(el instanceof Element)) {
+ return;
+ }
+ if (Joomla.Bootstrap.Instances.Alert.get(el) && el.dispose) {
+ el.dispose();
+ }
+ Joomla.Bootstrap.Instances.Alert.set(el, new Alert(el));
+};
+
+// Ensure vanilla mode, for consistency of the events
+if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
+ document.body.dataset.bsNoJquery = '';
+}
+
+// Get the elements/configurations from the PHP
+const alerts = Joomla.getOptions('bootstrap.alert');
+// Initialise the elements
+if (alerts && alerts.length) {
+ alerts.forEach((selector) => {
+ Array.from(document.querySelectorAll(selector))
+ .map((el) => Joomla.Bootstrap.Initialise.Alert(el));
+ });
+}
+
+export default Alert;
diff --git a/build/media_source/vendor/bootstrap/js/button.es6.js b/build/media_source/vendor/bootstrap/js/button.es6.js
new file mode 100644
index 0000000000000..2384f2af28748
--- /dev/null
+++ b/build/media_source/vendor/bootstrap/js/button.es6.js
@@ -0,0 +1,39 @@
+import Button from '../../../../../node_modules/bootstrap/js/src/button';
+
+Joomla = Joomla || {};
+Joomla.Bootstrap = Joomla.Bootstrap || {};
+Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
+Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
+Joomla.Bootstrap.Instances.Button = new WeakMap();
+
+/**
+ * Initialise the Button iteractivity
+ *
+ * @param {HTMLElement} el The element that will become an Button
+ */
+Joomla.Bootstrap.Initialise.Button = (el) => {
+ if (!(el instanceof Element)) {
+ return;
+ }
+ if (Joomla.Bootstrap.Instances.Button.get(el) && el.dispose) {
+ el.dispose();
+ }
+ Joomla.Bootstrap.Instances.Button.set(el, new Button(el));
+};
+
+// Ensure vanilla mode, for consistency of the events
+if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
+ document.body.dataset.bsNoJquery = '';
+}
+
+// Get the elements/configurations from the PHP
+const buttons = Joomla.getOptions('bootstrap.button');
+// Initialise the elements
+if (buttons && buttons.length) {
+ buttons.forEach((selector) => {
+ Array.from(document.querySelectorAll(selector))
+ .map((el) => Joomla.Bootstrap.Initialise.Button(el));
+ });
+}
+
+export default Button;
diff --git a/build/media_source/vendor/bootstrap/js/carousel.es6.js b/build/media_source/vendor/bootstrap/js/carousel.es6.js
new file mode 100644
index 0000000000000..6392fd1a0ba8e
--- /dev/null
+++ b/build/media_source/vendor/bootstrap/js/carousel.es6.js
@@ -0,0 +1,52 @@
+import Carousel from '../../../../../node_modules/bootstrap/js/src/carousel';
+
+Joomla = Joomla || {};
+Joomla.Bootstrap = Joomla.Bootstrap || {};
+Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
+Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
+Joomla.Bootstrap.Instances.Carousel = new WeakMap();
+
+/**
+ * Initialise the Carousel iteractivity
+ *
+ * @param {HTMLElement} el The element that will become an Carousel
+ * @param {object} options The options for this carousel
+ */
+Joomla.Bootstrap.Initialise.Carousel = (el, options) => {
+ if (!(el instanceof Element)) {
+ return;
+ }
+ if (Joomla.Bootstrap.Instances.Carousel.get(el) && el.dispose) {
+ el.dispose();
+ }
+ Joomla.Bootstrap.Instances.Carousel.set(el, new Carousel(el, options));
+};
+
+// Get the elements/configurations from the PHP
+const carousels = Joomla.getOptions('bootstrap.carousel');
+
+// Force Vanilla mode!
+if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
+ document.body.dataset.bsNoJquery = '';
+}
+// Initialise the elements
+if (typeof carousels === 'object' && carousels !== null) {
+ Object.keys(carousels).forEach((carousel) => {
+ const opt = carousels[carousel];
+ const options = {
+ interval: opt.interval ? opt.interval : 5000,
+ keyboard: opt.keyboard ? opt.keyboard : true,
+ pause: opt.pause ? opt.pause : 'hover',
+ slide: opt.slide ? opt.slide : false,
+ wrap: opt.wrap ? opt.wrap : true,
+ touch: opt.touch ? opt.touch : true,
+ };
+
+ const elements = Array.from(document.querySelectorAll(carousel));
+ if (elements.length) {
+ elements.map((el) => Joomla.Bootstrap.Initialise.Carousel(el, options));
+ }
+ });
+}
+
+export default Carousel;
diff --git a/build/media_source/vendor/bootstrap/js/collapse.es6.js b/build/media_source/vendor/bootstrap/js/collapse.es6.js
new file mode 100644
index 0000000000000..567c999821f57
--- /dev/null
+++ b/build/media_source/vendor/bootstrap/js/collapse.es6.js
@@ -0,0 +1,51 @@
+import Collapse from '../../../../../node_modules/bootstrap/js/src/collapse';
+
+Joomla = Joomla || {};
+Joomla.Bootstrap = Joomla.Bootstrap || {};
+Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
+Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
+Joomla.Bootstrap.Instances.Collapse = new WeakMap();
+
+/**
+ * Initialise the Collapse iteractivity
+ *
+ * @param {HTMLElement} el The element that will become an collapse
+ * @param {object} options The options for this collapse
+ */
+Joomla.Bootstrap.Initialise.Collapse = (el, options) => {
+ if (!(el instanceof Element)) {
+ return;
+ }
+ if (Joomla.Bootstrap.Instances.Collapse.get(el) && el.dispose) {
+ el.dispose();
+ }
+ Joomla.Bootstrap.Instances.Collapse.set(el, new Collapse(el, options));
+};
+
+// Ensure vanilla mode, for consistency of the events
+if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
+ document.body.dataset.bsNoJquery = '';
+}
+
+// Get the elements/configurations from the PHP
+const collapses = { ...Joomla.getOptions('bootstrap.collapse'), ...Joomla.getOptions('bootstrap.accordion') };
+// Initialise the elements
+if (typeof collapses === 'object' && collapses !== null) {
+ Object.keys(collapses).forEach((collapse) => {
+ const opt = collapses[collapse];
+ const options = {
+ toggle: opt.toggle ? opt.toggle : true,
+ };
+
+ if (opt.parent) {
+ options.parent = opt.parent;
+ }
+
+ const elements = Array.from(document.querySelectorAll(collapse));
+ if (elements.length) {
+ elements.map((el) => Joomla.Bootstrap.Initialise.Collapse(el, options));
+ }
+ });
+}
+
+export default Collapse;
diff --git a/build/media_source/vendor/bootstrap/js/dropdown.es6.js b/build/media_source/vendor/bootstrap/js/dropdown.es6.js
new file mode 100644
index 0000000000000..8cba264334d30
--- /dev/null
+++ b/build/media_source/vendor/bootstrap/js/dropdown.es6.js
@@ -0,0 +1,48 @@
+import Dropdown from '../../../../../node_modules/bootstrap/js/src/dropdown';
+
+Joomla = Joomla || {};
+Joomla.Bootstrap = Joomla.Bootstrap || {};
+Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
+Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
+Joomla.Bootstrap.Instances.Dropdown = new WeakMap();
+
+/**
+ * Initialise the iteractivity
+ *
+ * @param {HTMLElement} el The element that will become an dropdown
+ * @param {object} options The options for this dropdown
+ */
+Joomla.Bootstrap.Initialise.Dropdown = (el, options) => {
+ if (!(el instanceof Element)) {
+ return;
+ }
+ if (Joomla.Bootstrap.Instances.Dropdown.get(el) && el.dispose) {
+ el.dispose();
+ }
+ Joomla.Bootstrap.Instances.Dropdown.set(el, new Dropdown(el, options));
+};
+
+// Ensure vanilla mode, for consistency of the events
+if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
+ document.body.dataset.bsNoJquery = '';
+}
+
+// Get the elements/configurations from the PHP
+const dropdowns = Joomla.getOptions('bootstrap.dropdown');
+// Initialise the elements
+if (typeof dropdowns === 'object' && dropdowns !== null) {
+ Object.keys(dropdowns).forEach((dropdown) => {
+ const opt = dropdowns[dropdown];
+ const options = {
+ interval: opt.interval ? opt.interval : 5000,
+ pause: opt.pause ? opt.pause : 'hover',
+ };
+
+ const elements = Array.from(document.querySelectorAll(dropdown));
+ if (elements.length) {
+ elements.map((el) => Joomla.Bootstrap.Initialise.Dropdown(el, options));
+ }
+ });
+}
+
+export default Dropdown;
diff --git a/build/media_source/vendor/bootstrap/js/index.es6.js b/build/media_source/vendor/bootstrap/js/index.es6.js
new file mode 100644
index 0000000000000..9585ae01838ae
--- /dev/null
+++ b/build/media_source/vendor/bootstrap/js/index.es6.js
@@ -0,0 +1,23 @@
+import Alert from './alert.es6';
+import Button from './button.es6';
+import Collapse from './collapse.es6';
+import Carousel from './carousel.es6';
+import Dropdown from './dropdown.es6';
+import Modal from './modal.es6';
+import { Popover } from './popover.es6';
+import Scrollspy from './scrollspy.es6';
+import Tab from './tab.es6';
+import Toast from './toast.es6';
+
+export {
+ Alert,
+ Button,
+ Collapse,
+ Carousel,
+ Dropdown,
+ Modal,
+ Popover,
+ Scrollspy,
+ Tab,
+ Toast,
+};
diff --git a/build/media_source/vendor/bootstrap/js/modal.es6.js b/build/media_source/vendor/bootstrap/js/modal.es6.js
new file mode 100644
index 0000000000000..b8da50cc82ac8
--- /dev/null
+++ b/build/media_source/vendor/bootstrap/js/modal.es6.js
@@ -0,0 +1,162 @@
+import Modal from '../../../../../node_modules/bootstrap/js/src/modal';
+
+Joomla = Joomla || {};
+Joomla.Bootstrap = Joomla.Bootstrap || {};
+Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
+Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
+Joomla.Bootstrap.Instances.Modal = new WeakMap();
+
+Joomla.Bootstrap.Initialise.Modal = (modal, options) => {
+ if (!(modal instanceof Element)) {
+ return;
+ }
+ if (Joomla.Bootstrap.Instances.Modal.get(modal) && modal.dispose) {
+ modal.dispose();
+ }
+ Joomla.Bootstrap.Instances.Modal.set(modal, new Modal(modal, options));
+
+ // Comply with the Joomla API - Bound element.open/close
+ modal.open = () => { Joomla.Bootstrap.Instances.Modal.get(modal).show(modal); };
+ modal.close = () => { Joomla.Bootstrap.Instances.Modal.get(modal).hide(); };
+
+ // Do some Joomla specific changes
+ modal.addEventListener('show.bs.modal', () => {
+ // Comply with the Joomla API - Set the current Modal ID
+ Joomla.Modal.setCurrent(modal);
+
+ if (modal.dataset.url) {
+ const modalBody = modal.querySelector('.modal-body');
+ const iframe = modalBody.querySelector('iframe');
+
+ if (iframe) {
+ const addData = modal.querySelector('joomla-field-mediamore');
+
+ if (addData) {
+ addData.parentNode.removeChild(addData);
+ }
+
+ iframe.parentNode.removeChild(iframe);
+ }
+
+ // @todo merge https://github.com/joomla/joomla-cms/pull/20788
+ // Hacks because com_associations and field modals use pure javascript in the url!
+ if (modal.dataset.iframe.indexOf('document.getElementById') > 0) {
+ const iframeTextArr = modal.dataset.iframe.split('+');
+ const idFieldArr = iframeTextArr[1].split('"');
+ let el;
+
+ idFieldArr[0] = idFieldArr[0].replace(/"/g, '"');
+
+ if (!document.getElementById(idFieldArr[1])) {
+ // eslint-disable-next-line no-new-func
+ el = new Function(idFieldArr[0]); // This is UNSAFE!!!!
+ } else {
+ el = document.getElementById(idFieldArr[1]).value;
+ }
+
+ modalBody.insertAdjacentHTML('afterbegin', `${iframeTextArr[0]}${el}${iframeTextArr[2]}`);
+ } else {
+ modalBody.insertAdjacentHTML('afterbegin', modal.dataset.iframe);
+ }
+ }
+ });
+
+ modal.addEventListener('shown.bs.modal', () => {
+ const modalBody = modal.querySelector('.modal-body');
+ const modalHeader = modal.querySelector('.modal-header');
+ const modalFooter = modal.querySelector('.modal-footer');
+ let modalHeaderHeight = 0;
+ let modalFooterHeight = 0;
+ let maxModalBodyHeight = 0;
+ let modalBodyPadding = 0;
+ let modalBodyHeightOuter = 0;
+
+ if (modalBody) {
+ if (modalHeader) {
+ const modalHeaderRects = modalHeader.getBoundingClientRect();
+ modalHeaderHeight = modalHeaderRects.height;
+ modalBodyHeightOuter = modalBody.offsetHeight;
+ }
+ if (modalFooter) {
+ modalFooterHeight = parseFloat(getComputedStyle(modalFooter, null).height.replace('px', ''));
+ }
+
+ const modalBodyHeight = parseFloat(getComputedStyle(modalBody, null).height.replace('px', ''));
+ const padding = modalBody.offsetTop;
+ const maxModalHeight = parseFloat(getComputedStyle(document.body, null).height.replace('px', '')) - (padding * 2);
+ modalBodyPadding = modalBodyHeightOuter - modalBodyHeight;
+ // eslint-disable-next-line max-len
+ maxModalBodyHeight = maxModalHeight - (modalHeaderHeight + modalFooterHeight + modalBodyPadding);
+ }
+
+ if (modal.dataset.url) {
+ const iframeEl = modal.querySelector('iframe');
+ const iframeHeight = parseFloat(getComputedStyle(iframeEl, null).height.replace('px', ''));
+ if (iframeHeight > maxModalBodyHeight) {
+ modalBody.style.maxHeight = maxModalBodyHeight;
+ modalBody.style.overflowY = 'auto';
+ iframeEl.style.maxHeight = maxModalBodyHeight - modalBodyPadding;
+ }
+ }
+ });
+
+ modal.addEventListener('hide.bs.modal', () => {
+ const modalBody = modal.querySelector('.modal-body');
+ modalBody.style.maxHeight = 'initial';
+ });
+
+ modal.addEventListener('hidden.bs.modal', () => {
+ // Comply with the Joomla API - Remove the current Modal ID
+ Joomla.Modal.setCurrent('');
+ });
+};
+
+/**
+ * Method to invoke a click on button inside an iframe
+ *
+ * @param {object} options Object with the css selector for the parent element of an iframe
+ * and the selector of the button in the iframe that will be clicked
+ * { iframeSelector: '', buttonSelector: '' }
+ * @returns {boolean}
+ *
+ * @since 4.0
+ */
+Joomla.iframeButtonClick = (options) => {
+ if (!options.iframeSelector || !options.buttonSelector) {
+ throw new Error('Selector is missing');
+ }
+
+ const iframe = document.querySelector(`${options.iframeSelector} iframe`);
+ if (iframe) {
+ const button = iframe.contentWindow.document.querySelector(options.buttonSelector);
+ if (button) {
+ button.click();
+ }
+ }
+};
+
+// Ensure vanilla mode, for consistency of the events
+if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
+ document.body.dataset.bsNoJquery = '';
+}
+
+// Get the elements/configurations from the PHP
+const modals = Joomla.getOptions('bootstrap.modal');
+// Initialise the elements
+if (typeof modals === 'object' && modals !== null) {
+ Object.keys(modals).forEach((modal) => {
+ const modalEl = document.querySelector(modal);
+ const opt = modals[modal];
+ const options = {
+ backdrop: opt.backdrop ? opt.backdrop : true,
+ keyboard: opt.keyboard ? opt.keyboard : true,
+ focus: opt.focus ? opt.focus : true,
+ };
+
+ if (modalEl) {
+ Joomla.Bootstrap.Initialise.Modal(modalEl, options);
+ }
+ });
+}
+
+export default Modal;
diff --git a/build/media_source/vendor/bootstrap/js/popover.es6.js b/build/media_source/vendor/bootstrap/js/popover.es6.js
new file mode 100644
index 0000000000000..e47c49150d9c8
--- /dev/null
+++ b/build/media_source/vendor/bootstrap/js/popover.es6.js
@@ -0,0 +1,121 @@
+import Popover from '../../../../../node_modules/bootstrap/js/src/popover';
+import Tooltip from '../../../../../node_modules/bootstrap/js/src/tooltip';
+
+Joomla = Joomla || {};
+Joomla.Bootstrap = Joomla.Bootstrap || {};
+Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
+Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
+Joomla.Bootstrap.Instances.Popover = new WeakMap();
+Joomla.Bootstrap.Instances.Tooltip = new WeakMap();
+
+/**
+ * Initialise the Popover iteractivity
+ *
+ * @param {HTMLElement} el The element that will become an popover
+ * @param {object} options The options for this popover
+ */
+Joomla.Bootstrap.Initialise.Popover = (el, options) => {
+ if (!(el instanceof Element)) {
+ return;
+ }
+ if (Joomla.Bootstrap.Instances.Popover.get(el) && el.dispose) {
+ el.dispose();
+ }
+ Joomla.Bootstrap.Instances.Popover.set(el, new Popover(el, options));
+};
+
+/**
+ * Initialise the Tooltip iteractivity
+ *
+ * @param {HTMLElement} el The element that will become an tooltip
+ * @param {object} options The options for this tooltip
+ */
+Joomla.Bootstrap.Initialise.Tooltip = (el, options) => {
+ if (Joomla.Bootstrap.Instances.Tooltip.get(el) && el.dispose) {
+ el.dispose();
+ }
+ Joomla.Bootstrap.Instances.Tooltip.set(el, new Tooltip(el, options));
+};
+
+// Ensure vanilla mode, for consistency of the events
+if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
+ document.body.dataset.bsNoJquery = '';
+}
+
+// Get the elements/configurations from the PHP
+const tooltips = Joomla.getOptions('bootstrap.tooltip');
+const popovers = Joomla.getOptions('bootstrap.popover');
+// Initialise the elements
+if (typeof popovers === 'object' && popovers !== null) {
+ Object.keys(popovers).forEach((popover) => {
+ const opt = popovers[popover];
+ const options = {
+ animation: opt.animation ? opt.animation : true,
+ container: opt.container ? opt.container : false,
+ content: opt.content ? opt.content : '',
+ delay: opt.delay ? opt.delay : 0,
+ html: opt.html ? opt.html : false,
+ placement: opt.placement ? opt.placement : 'top',
+ selector: opt.selector ? opt.selector : false,
+ title: opt.title ? opt.title : '',
+ trigger: opt.trigger ? opt.trigger : 'click',
+ offset: opt.offset ? opt.offset : 0,
+ fallbackPlacement: opt.fallbackPlacement ? opt.fallbackPlacement : 'flip',
+ boundary: opt.boundary ? opt.boundary : 'scrollParent',
+ customClass: opt.customClass ? opt.customClass : '',
+ sanitize: opt.sanitize ? opt.sanitize : true,
+ sanitizeFn: opt.sanitizeFn ? opt.sanitizeFn : null,
+ popperConfig: opt.popperConfig ? opt.popperConfig : null,
+ };
+
+ if (opt.template) {
+ options.template = opt.template;
+ }
+ if (opt.allowList) {
+ options.allowList = opt.allowList;
+ }
+
+ const elements = Array.from(document.querySelectorAll(popover));
+ if (elements.length) {
+ elements.map((el) => Joomla.Bootstrap.Initialise.Popover(el, options));
+ }
+ });
+}
+// Initialise the elements
+if (typeof tooltips === 'object' && tooltips !== null) {
+ Object.keys(tooltips).forEach((tooltip) => {
+ const opt = tooltips[tooltip];
+ const options = {
+ animation: opt.animation ? opt.animation : true,
+ container: opt.container ? opt.container : false,
+ delay: opt.delay ? opt.delay : 0,
+ html: opt.html ? opt.html : false,
+ selector: opt.selector ? opt.selector : false,
+ trigger: opt.trigger ? opt.trigger : 'hover focus',
+ fallbackPlacement: opt.fallbackPlacement ? opt.fallbackPlacement : null,
+ boundary: opt.boundary ? opt.boundary : 'clippingParents',
+ title: opt.title ? opt.title : '',
+ customClass: opt.customClass ? opt.customClass : '',
+ sanitize: opt.sanitize ? opt.sanitize : true,
+ sanitizeFn: opt.sanitizeFn ? opt.sanitizeFn : null,
+ popperConfig: opt.popperConfig ? opt.popperConfig : null,
+ };
+
+ if (opt.placement) {
+ options.placement = opt.placement;
+ }
+ if (opt.template) {
+ options.template = opt.template;
+ }
+ if (opt.allowList) {
+ options.allowList = opt.allowList;
+ }
+
+ const elements = Array.from(document.querySelectorAll(tooltip));
+ if (elements.length) {
+ elements.map((el) => Joomla.Bootstrap.Initialise.Tooltip(el, options));
+ }
+ });
+}
+
+export { Tooltip, Popover };
diff --git a/build/media_source/vendor/bootstrap/js/scrollspy.es6.js b/build/media_source/vendor/bootstrap/js/scrollspy.es6.js
new file mode 100644
index 0000000000000..db650453ce118
--- /dev/null
+++ b/build/media_source/vendor/bootstrap/js/scrollspy.es6.js
@@ -0,0 +1,52 @@
+import Scrollspy from '../../../../../node_modules/bootstrap/js/src/scrollspy';
+
+Joomla = Joomla || {};
+Joomla.Bootstrap = Joomla.Bootstrap || {};
+Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
+Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
+Joomla.Bootstrap.Instances.Scrollspy = new WeakMap();
+
+/**
+ * Initialise the Scrollspy iteractivity
+ *
+ * @param {HTMLElement} el The element that will become a scrollspy
+ * @param {object} options The options for this scrollspy
+ */
+Joomla.Bootstrap.Initialise.Scrollspy = (el, options) => {
+ if (!(el instanceof Element)) {
+ return;
+ }
+ if (Joomla.Bootstrap.Instances.Scrollspy.get(el) && el.dispose) {
+ el.dispose();
+ }
+ Joomla.Bootstrap.Instances.Scrollspy.set(el, new Scrollspy(el, options));
+};
+
+// Ensure vanilla mode, for consistency of the events
+if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
+ document.body.dataset.bsNoJquery = '';
+}
+
+// Get the elements/configurations from the PHP
+const scrollspys = Joomla.getOptions('bootstrap.scrollspy');
+// Initialise the elements
+if (typeof scrollspys === 'object' && scrollspys !== null) {
+ Object.keys(scrollspys).forEach((scrollspy) => {
+ const opt = scrollspys[scrollspy];
+ const options = {
+ offset: opt.offset ? opt.offset : 10,
+ method: opt.method ? opt.method : 'auto',
+ };
+
+ if (opt.target) {
+ options.target = opt.target;
+ }
+
+ const elements = Array.from(document.querySelectorAll(scrollspy));
+ if (elements.length) {
+ elements.map((el) => Joomla.Bootstrap.Initialise.Scrollspy(el, options));
+ }
+ });
+}
+
+export default Scrollspy;
diff --git a/build/media_source/vendor/bootstrap/js/tab.es6.js b/build/media_source/vendor/bootstrap/js/tab.es6.js
new file mode 100644
index 0000000000000..9293cb9df1d34
--- /dev/null
+++ b/build/media_source/vendor/bootstrap/js/tab.es6.js
@@ -0,0 +1,96 @@
+import Tab from '../../../../../node_modules/bootstrap/js/src/tab';
+
+Joomla = Joomla || {};
+Joomla.Bootstrap = Joomla.Bootstrap || {};
+Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
+Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
+Joomla.Bootstrap.Instances.Tab = new WeakMap();
+
+/**
+ * Initialise the Tabs interactivity
+ *
+ * @param {HTMLElement} el The element that will become an collapse
+ * @param {object} options The options for this collapse
+ */
+Joomla.Bootstrap.Initialise.Tab = (el, options) => {
+ if (!(el instanceof Element) && options.isJoomla) {
+ const nSelector = el.split('.')[1];
+ if (!nSelector) {
+ throw new Error('The selector is invalid, check your PHP side');
+ }
+ const tab = document.querySelector(`#${nSelector}Content`);
+ if (tab) {
+ const related = Array.from(tab.children);
+
+ // Build the navigation
+ if (related.length) {
+ related.forEach((element) => {
+ if (!element.classList.contains('tab-pane')) {
+ return;
+ }
+
+ const isActive = element.dataset.active !== '';
+ const ul = document.querySelector(`#${nSelector}Tabs`);
+
+ if (ul) {
+ const link = document.createElement('a');
+ link.href = `#${element.dataset.id}`;
+ link.classList.add('nav-link');
+ if (isActive) {
+ link.classList.add('active');
+ }
+
+ link.dataset.bsToggle = 'tab';
+ link.setAttribute('role', 'tab');
+ link.setAttribute('aria-controls', element.dataset.id);
+ link.setAttribute('aria-selected', element.dataset.id);
+
+ /**
+ * As we are re-rendering text already displayed on the page we judge that there isn't
+ * a risk of XSS attacks
+ */
+ link.innerHTML = element.dataset.title;
+
+ const li = document.createElement('li');
+ li.classList.add('nav-item');
+ li.setAttribute('role', 'presentation');
+ li.appendChild(link);
+
+ ul.appendChild(li);
+ }
+ });
+ }
+
+ if (Joomla.Bootstrap.Instances.Tab.get(tab) && tab.dispose) {
+ tab.dispose();
+ }
+
+ Joomla.Bootstrap.Instances.Tab.set(tab, new Tab(tab));
+ }
+ } else {
+ if (!(el instanceof Element)) {
+ return;
+ }
+ if (Joomla.Bootstrap.Instances.Tab.get(el) && el.dispose) {
+ el.dispose();
+ }
+
+ Joomla.Bootstrap.Instances.Tab.set(el, new Tab(el, options));
+ }
+};
+
+// Ensure vanilla mode, for consistency of the events
+if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
+ document.body.dataset.bsNoJquery = '';
+}
+
+// Get the elements/configurations from the PHP
+const tabs = Joomla.getOptions('bootstrap.tabs');
+// Initialise the elements
+if (typeof tabs === 'object' && tabs !== null) {
+ Object.keys(tabs).forEach((tab) => {
+ Joomla.Bootstrap.Initialise.Tab(tab, tabs[tab]);
+ });
+}
+
+export default Tab;
diff --git a/build/media_source/vendor/bootstrap/js/toast.es6.js b/build/media_source/vendor/bootstrap/js/toast.es6.js
new file mode 100644
index 0000000000000..4bc561ae8a9e0
--- /dev/null
+++ b/build/media_source/vendor/bootstrap/js/toast.es6.js
@@ -0,0 +1,49 @@
+import Toast from '../../../../../node_modules/bootstrap/js/src/toast';
+
+Joomla = Joomla || {};
+Joomla.Bootstrap = Joomla.Bootstrap || {};
+Joomla.Bootstrap.Initialise = Joomla.Bootstrap.Initialise || {};
+Joomla.Bootstrap.Instances = Joomla.Bootstrap.Instances || {};
+Joomla.Bootstrap.Instances.Toast = new WeakMap();
+
+/**
+ * Initialise the iteractivity
+ *
+ * @param {HTMLElement} el The element that will become an toast
+ * @param {object} options The options for this toast
+ */
+Joomla.Bootstrap.Initialise.Toast = (el, options) => {
+ if (!(el instanceof Element)) {
+ return;
+ }
+ if (Joomla.Bootstrap.Instances.Toast.get(el) && el.dispose) {
+ el.dispose();
+ }
+ Joomla.Bootstrap.Instances.Toast.set(el, new Toast(el, options));
+};
+
+// Ensure vanilla mode, for consistency of the events
+if (!Object.prototype.hasOwnProperty.call(document.body.dataset, 'bsNoJquery')) {
+ document.body.dataset.bsNoJquery = '';
+}
+
+// Get the elements/configurations from the PHP
+const toasts = Joomla.getOptions('bootstrap.toast');
+// Initialise the elements
+if (typeof toasts === 'object' && toasts !== null) {
+ Object.keys(toasts).forEach((toast) => {
+ const opt = toasts[toast];
+ const options = {
+ animation: opt.animation ? opt.animation : true,
+ autohide: opt.autohide ? opt.autohide : true,
+ delay: opt.delay ? opt.delay : 5000,
+ };
+
+ const elements = Array.from(document.querySelectorAll(toast));
+ if (elements.length) {
+ elements.map((el) => Joomla.Bootstrap.Initialise.Toast(el, options));
+ }
+ });
+}
+
+export default Toast;
diff --git a/components/com_finder/tmpl/search/default_form.php b/components/com_finder/tmpl/search/default_form.php
index 5f4ee128fcfa3..dcd213e8469d1 100644
--- a/components/com_finder/tmpl/search/default_form.php
+++ b/components/com_finder/tmpl/search/default_form.php
@@ -41,7 +41,7 @@
params->get('show_advanced', 1)) : ?>
-
+
diff --git a/layouts/joomla/form/field/contenthistory.php b/layouts/joomla/form/field/contenthistory.php
index e695f962b2a83..19d97183f43d5 100644
--- a/layouts/joomla/form/field/contenthistory.php
+++ b/layouts/joomla/form/field/contenthistory.php
@@ -68,9 +68,10 @@
?>
>
+ data-bs-toggle="modal"
+ data-bs-target="#versionsModal"
+ >
diff --git a/layouts/joomla/toolbar/dropdown.php b/layouts/joomla/toolbar/dropdown.php
index de05e387d0907..71b43bff715a4 100644
--- a/layouts/joomla/toolbar/dropdown.php
+++ b/layouts/joomla/toolbar/dropdown.php
@@ -39,16 +39,18 @@
-
-
-
-
+
+
+
+ data-bs-toggle="dropdown" data-bs-target=".dropdown-menu" data-bs-display="static" aria-haspopup="true" aria-expanded="false">
+
+
';
}
@@ -441,27 +653,26 @@ public static function endAccordion()
*
* @since 3.0
*/
- public static function addSlide($selector, $text, $id, $class = '')
+ public static function addSlide($selector, $text, $id, $class = '') :string
{
$in = static::$loaded[__CLASS__ . '::startAccordion'][$selector]['active'] === $id ? ' show' : '';
$collapsed = static::$loaded[__CLASS__ . '::startAccordion'][$selector]['active'] === $id ? '' : ' collapsed';
$parent = static::$loaded[__CLASS__ . '::startAccordion'][$selector]['parent'] ?
- ' data-parent="' . static::$loaded[__CLASS__ . '::startAccordion'][$selector]['parent'] . '"' : '';
+ 'data-bs-parent="' . static::$loaded[__CLASS__ . '::startAccordion'][$selector]['parent'] . '"' : '';
$class = (!empty($class)) ? ' ' . $class : '';
$ariaExpanded = $in === 'show' ? true : false;
return <<
-