[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 import { E as EventHandler, c as getElementFromSelector, i as isVisible, S as SelectorEngine, e as enableDismissTrigger, d as defineJQueryPlugin, B as BaseComponent, l as ScrollBarHelper, m as Backdrop, F as FocusTrap, M as Manipulator, a as typeCheckConfig, r as reflow, b as isRTL } from './dom.js?5.1.3'; 2 3 /** 4 * -------------------------------------------------------------------------- 5 * Bootstrap (v5.1.3): modal.js 6 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 7 * -------------------------------------------------------------------------- 8 */ 9 /** 10 * ------------------------------------------------------------------------ 11 * Constants 12 * ------------------------------------------------------------------------ 13 */ 14 15 const NAME = 'modal'; 16 const DATA_KEY = 'bs.modal'; 17 const EVENT_KEY = `.$DATA_KEY}`; 18 const DATA_API_KEY = '.data-api'; 19 const ESCAPE_KEY = 'Escape'; 20 const Default = { 21 backdrop: true, 22 keyboard: true, 23 focus: true 24 }; 25 const DefaultType = { 26 backdrop: '(boolean|string)', 27 keyboard: 'boolean', 28 focus: 'boolean' 29 }; 30 const EVENT_HIDE = `hide$EVENT_KEY}`; 31 const EVENT_HIDE_PREVENTED = `hidePrevented$EVENT_KEY}`; 32 const EVENT_HIDDEN = `hidden$EVENT_KEY}`; 33 const EVENT_SHOW = `show$EVENT_KEY}`; 34 const EVENT_SHOWN = `shown$EVENT_KEY}`; 35 const EVENT_RESIZE = `resize$EVENT_KEY}`; 36 const EVENT_CLICK_DISMISS = `click.dismiss$EVENT_KEY}`; 37 const EVENT_KEYDOWN_DISMISS = `keydown.dismiss$EVENT_KEY}`; 38 const EVENT_MOUSEUP_DISMISS = `mouseup.dismiss$EVENT_KEY}`; 39 const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss$EVENT_KEY}`; 40 const EVENT_CLICK_DATA_API = `click$EVENT_KEY}$DATA_API_KEY}`; 41 const CLASS_NAME_OPEN = 'modal-open'; 42 const CLASS_NAME_FADE = 'fade'; 43 const CLASS_NAME_SHOW = 'show'; 44 const CLASS_NAME_STATIC = 'modal-static'; 45 const OPEN_SELECTOR = '.modal.show'; 46 const SELECTOR_DIALOG = '.modal-dialog'; 47 const SELECTOR_MODAL_BODY = '.modal-body'; 48 const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="modal"]'; 49 /** 50 * ------------------------------------------------------------------------ 51 * Class Definition 52 * ------------------------------------------------------------------------ 53 */ 54 55 class Modal extends BaseComponent { 56 constructor(element, config) { 57 super(element); 58 this._config = this._getConfig(config); 59 this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element); 60 this._backdrop = this._initializeBackDrop(); 61 this._focustrap = this._initializeFocusTrap(); 62 this._isShown = false; 63 this._ignoreBackdropClick = false; 64 this._isTransitioning = false; 65 this._scrollBar = new ScrollBarHelper(); 66 } // Getters 67 68 69 static get Default() { 70 return Default; 71 } 72 73 static get NAME() { 74 return NAME; 75 } // Public 76 77 78 toggle(relatedTarget) { 79 return this._isShown ? this.hide() : this.show(relatedTarget); 80 } 81 82 show(relatedTarget) { 83 if (this._isShown || this._isTransitioning) { 84 return; 85 } 86 87 const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { 88 relatedTarget 89 }); 90 91 if (showEvent.defaultPrevented) { 92 return; 93 } 94 95 this._isShown = true; 96 97 if (this._isAnimated()) { 98 this._isTransitioning = true; 99 } 100 101 this._scrollBar.hide(); 102 103 document.body.classList.add(CLASS_NAME_OPEN); 104 105 this._adjustDialog(); 106 107 this._setEscapeEvent(); 108 109 this._setResizeEvent(); 110 111 EventHandler.on(this._dialog, EVENT_MOUSEDOWN_DISMISS, () => { 112 EventHandler.one(this._element, EVENT_MOUSEUP_DISMISS, event => { 113 if (event.target === this._element) { 114 this._ignoreBackdropClick = true; 115 } 116 }); 117 }); 118 119 this._showBackdrop(() => this._showElement(relatedTarget)); 120 } 121 122 hide() { 123 if (!this._isShown || this._isTransitioning) { 124 return; 125 } 126 127 const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE); 128 129 if (hideEvent.defaultPrevented) { 130 return; 131 } 132 133 this._isShown = false; 134 135 const isAnimated = this._isAnimated(); 136 137 if (isAnimated) { 138 this._isTransitioning = true; 139 } 140 141 this._setEscapeEvent(); 142 143 this._setResizeEvent(); 144 145 this._focustrap.deactivate(); 146 147 this._element.classList.remove(CLASS_NAME_SHOW); 148 149 EventHandler.off(this._element, EVENT_CLICK_DISMISS); 150 EventHandler.off(this._dialog, EVENT_MOUSEDOWN_DISMISS); 151 152 this._queueCallback(() => this._hideModal(), this._element, isAnimated); 153 } 154 155 dispose() { 156 [window, this._dialog].forEach(htmlElement => EventHandler.off(htmlElement, EVENT_KEY)); 157 158 this._backdrop.dispose(); 159 160 this._focustrap.deactivate(); 161 162 super.dispose(); 163 } 164 165 handleUpdate() { 166 this._adjustDialog(); 167 } // Private 168 169 170 _initializeBackDrop() { 171 return new Backdrop({ 172 isVisible: Boolean(this._config.backdrop), 173 // 'static' option will be translated to true, and booleans will keep their value 174 isAnimated: this._isAnimated() 175 }); 176 } 177 178 _initializeFocusTrap() { 179 return new FocusTrap({ 180 trapElement: this._element 181 }); 182 } 183 184 _getConfig(config) { 185 config = { ...Default, 186 ...Manipulator.getDataAttributes(this._element), 187 ...(typeof config === 'object' ? config : {}) 188 }; 189 typeCheckConfig(NAME, config, DefaultType); 190 return config; 191 } 192 193 _showElement(relatedTarget) { 194 const isAnimated = this._isAnimated(); 195 196 const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog); 197 198 if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { 199 // Don't move modal's DOM position 200 document.body.append(this._element); 201 } 202 203 this._element.style.display = 'block'; 204 205 this._element.removeAttribute('aria-hidden'); 206 207 this._element.setAttribute('aria-modal', true); 208 209 this._element.setAttribute('role', 'dialog'); 210 211 this._element.scrollTop = 0; 212 213 if (modalBody) { 214 modalBody.scrollTop = 0; 215 } 216 217 if (isAnimated) { 218 reflow(this._element); 219 } 220 221 this._element.classList.add(CLASS_NAME_SHOW); 222 223 const transitionComplete = () => { 224 if (this._config.focus) { 225 this._focustrap.activate(); 226 } 227 228 this._isTransitioning = false; 229 EventHandler.trigger(this._element, EVENT_SHOWN, { 230 relatedTarget 231 }); 232 }; 233 234 this._queueCallback(transitionComplete, this._dialog, isAnimated); 235 } 236 237 _setEscapeEvent() { 238 if (this._isShown) { 239 EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => { 240 if (this._config.keyboard && event.key === ESCAPE_KEY) { 241 event.preventDefault(); 242 this.hide(); 243 } else if (!this._config.keyboard && event.key === ESCAPE_KEY) { 244 this._triggerBackdropTransition(); 245 } 246 }); 247 } else { 248 EventHandler.off(this._element, EVENT_KEYDOWN_DISMISS); 249 } 250 } 251 252 _setResizeEvent() { 253 if (this._isShown) { 254 EventHandler.on(window, EVENT_RESIZE, () => this._adjustDialog()); 255 } else { 256 EventHandler.off(window, EVENT_RESIZE); 257 } 258 } 259 260 _hideModal() { 261 this._element.style.display = 'none'; 262 263 this._element.setAttribute('aria-hidden', true); 264 265 this._element.removeAttribute('aria-modal'); 266 267 this._element.removeAttribute('role'); 268 269 this._isTransitioning = false; 270 271 this._backdrop.hide(() => { 272 document.body.classList.remove(CLASS_NAME_OPEN); 273 274 this._resetAdjustments(); 275 276 this._scrollBar.reset(); 277 278 EventHandler.trigger(this._element, EVENT_HIDDEN); 279 }); 280 } 281 282 _showBackdrop(callback) { 283 EventHandler.on(this._element, EVENT_CLICK_DISMISS, event => { 284 if (this._ignoreBackdropClick) { 285 this._ignoreBackdropClick = false; 286 return; 287 } 288 289 if (event.target !== event.currentTarget) { 290 return; 291 } 292 293 if (this._config.backdrop === true) { 294 this.hide(); 295 } else if (this._config.backdrop === 'static') { 296 this._triggerBackdropTransition(); 297 } 298 }); 299 300 this._backdrop.show(callback); 301 } 302 303 _isAnimated() { 304 return this._element.classList.contains(CLASS_NAME_FADE); 305 } 306 307 _triggerBackdropTransition() { 308 const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED); 309 310 if (hideEvent.defaultPrevented) { 311 return; 312 } 313 314 const { 315 classList, 316 scrollHeight, 317 style 318 } = this._element; 319 const isModalOverflowing = scrollHeight > document.documentElement.clientHeight; // return if the following background transition hasn't yet completed 320 321 if (!isModalOverflowing && style.overflowY === 'hidden' || classList.contains(CLASS_NAME_STATIC)) { 322 return; 323 } 324 325 if (!isModalOverflowing) { 326 style.overflowY = 'hidden'; 327 } 328 329 classList.add(CLASS_NAME_STATIC); 330 331 this._queueCallback(() => { 332 classList.remove(CLASS_NAME_STATIC); 333 334 if (!isModalOverflowing) { 335 this._queueCallback(() => { 336 style.overflowY = ''; 337 }, this._dialog); 338 } 339 }, this._dialog); 340 341 this._element.focus(); 342 } // ---------------------------------------------------------------------- 343 // the following methods are used to handle overflowing modals 344 // ---------------------------------------------------------------------- 345 346 347 _adjustDialog() { 348 const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; 349 350 const scrollbarWidth = this._scrollBar.getWidth(); 351 352 const isBodyOverflowing = scrollbarWidth > 0; 353 354 if (!isBodyOverflowing && isModalOverflowing && !isRTL() || isBodyOverflowing && !isModalOverflowing && isRTL()) { 355 this._element.style.paddingLeft = `$scrollbarWidth}px`; 356 } 357 358 if (isBodyOverflowing && !isModalOverflowing && !isRTL() || !isBodyOverflowing && isModalOverflowing && isRTL()) { 359 this._element.style.paddingRight = `$scrollbarWidth}px`; 360 } 361 } 362 363 _resetAdjustments() { 364 this._element.style.paddingLeft = ''; 365 this._element.style.paddingRight = ''; 366 } // Static 367 368 369 static jQueryInterface(config, relatedTarget) { 370 return this.each(function () { 371 const data = Modal.getOrCreateInstance(this, config); 372 373 if (typeof config !== 'string') { 374 return; 375 } 376 377 if (typeof data[config] === 'undefined') { 378 throw new TypeError(`No method named "$config}"`); 379 } 380 381 data[config](relatedTarget); 382 }); 383 } 384 385 } 386 /** 387 * ------------------------------------------------------------------------ 388 * Data Api implementation 389 * ------------------------------------------------------------------------ 390 */ 391 392 393 EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { 394 const target = getElementFromSelector(this); 395 396 if (['A', 'AREA'].includes(this.tagName)) { 397 event.preventDefault(); 398 } 399 400 EventHandler.one(target, EVENT_SHOW, showEvent => { 401 if (showEvent.defaultPrevented) { 402 // only register focus restorer if modal will actually get shown 403 return; 404 } 405 406 EventHandler.one(target, EVENT_HIDDEN, () => { 407 if (isVisible(this)) { 408 this.focus(); 409 } 410 }); 411 }); // avoid conflict when clicking moddal toggler while another one is open 412 413 const allReadyOpen = SelectorEngine.findOne(OPEN_SELECTOR); 414 415 if (allReadyOpen) { 416 Modal.getInstance(allReadyOpen).hide(); 417 } 418 419 const data = Modal.getOrCreateInstance(target); 420 data.toggle(this); 421 }); 422 enableDismissTrigger(Modal); 423 /** 424 * ------------------------------------------------------------------------ 425 * jQuery 426 * ------------------------------------------------------------------------ 427 * add .Modal to jQuery only if jQuery is present 428 */ 429 430 defineJQueryPlugin(Modal); 431 432 Joomla = Joomla || {}; 433 Joomla.Modal = Joomla.Modal || {}; 434 window.bootstrap = window.bootstrap || {}; 435 window.bootstrap.Modal = Modal; 436 const allowed = { 437 iframe: ['src', 'name', 'width', 'height'] 438 }; 439 440 Joomla.initialiseModal = (modal, options) => { 441 if (!(modal instanceof Element)) { 442 return; 443 } // eslint-disable-next-line no-new 444 445 446 new window.bootstrap.Modal(modal, options); // Comply with the Joomla API - Bound element.open/close 447 448 modal.open = () => { 449 window.bootstrap.Modal.getInstance(modal).show(modal); 450 }; 451 452 modal.close = () => { 453 window.bootstrap.Modal.getInstance(modal).hide(); 454 }; // Do some Joomla specific changes 455 456 457 modal.addEventListener('show.bs.modal', () => { 458 // Comply with the Joomla API - Set the current Modal ID 459 Joomla.Modal.setCurrent(modal); 460 461 if (modal.dataset.url) { 462 const modalBody = modal.querySelector('.modal-body'); 463 const iframe = modalBody.querySelector('iframe'); 464 465 if (iframe) { 466 const addData = modal.querySelector('joomla-field-mediamore'); 467 468 if (addData) { 469 addData.parentNode.removeChild(addData); 470 } 471 472 iframe.parentNode.removeChild(iframe); 473 } // @todo merge https://github.com/joomla/joomla-cms/pull/20788 474 // Hacks because com_associations and field modals use pure javascript in the url! 475 476 477 if (modal.dataset.iframe.indexOf('document.getElementById') > 0) { 478 const iframeTextArr = modal.dataset.iframe.split('+'); 479 const idFieldArr = iframeTextArr[1].split('"'); 480 let el; 481 idFieldArr[0] = idFieldArr[0].replace(/"/g, '"'); 482 483 if (!document.getElementById(idFieldArr[1])) { 484 // eslint-disable-next-line no-new-func 485 const fn = new Function(`return $idFieldArr[0]}`); // This is UNSAFE!!!! 486 487 el = fn.call(null); 488 } else { 489 el = document.getElementById(idFieldArr[1]).value; 490 } 491 492 modalBody.insertAdjacentHTML('afterbegin', Joomla.sanitizeHtml(`$iframeTextArr[0]}$el}$iframeTextArr[2]}`, allowed)); 493 } else { 494 modalBody.insertAdjacentHTML('afterbegin', Joomla.sanitizeHtml(modal.dataset.iframe, allowed)); 495 } 496 } 497 }); 498 modal.addEventListener('shown.bs.modal', () => { 499 const modalBody = modal.querySelector('.modal-body'); 500 const modalHeader = modal.querySelector('.modal-header'); 501 const modalFooter = modal.querySelector('.modal-footer'); 502 let modalHeaderHeight = 0; 503 let modalFooterHeight = 0; 504 let maxModalBodyHeight = 0; 505 let modalBodyPadding = 0; 506 let modalBodyHeightOuter = 0; 507 508 if (modalBody) { 509 if (modalHeader) { 510 const modalHeaderRects = modalHeader.getBoundingClientRect(); 511 modalHeaderHeight = modalHeaderRects.height; 512 modalBodyHeightOuter = modalBody.offsetHeight; 513 } 514 515 if (modalFooter) { 516 modalFooterHeight = parseFloat(getComputedStyle(modalFooter, null).height.replace('px', '')); 517 } 518 519 const modalBodyHeight = parseFloat(getComputedStyle(modalBody, null).height.replace('px', '')); 520 const padding = modalBody.offsetTop; 521 const maxModalHeight = parseFloat(getComputedStyle(document.body, null).height.replace('px', '')) - padding * 2; 522 modalBodyPadding = modalBodyHeightOuter - modalBodyHeight; 523 maxModalBodyHeight = maxModalHeight - (modalHeaderHeight + modalFooterHeight + modalBodyPadding); 524 } 525 526 if (modal.dataset.url) { 527 const iframeEl = modal.querySelector('iframe'); 528 const iframeHeight = parseFloat(getComputedStyle(iframeEl, null).height.replace('px', '')); 529 530 if (iframeHeight > maxModalBodyHeight) { 531 modalBody.style.maxHeight = maxModalBodyHeight; 532 modalBody.style.overflowY = 'auto'; 533 iframeEl.style.maxHeight = maxModalBodyHeight - modalBodyPadding; 534 } 535 } 536 }); 537 modal.addEventListener('hide.bs.modal', () => { 538 const modalBody = modal.querySelector('.modal-body'); 539 modalBody.style.maxHeight = 'initial'; 540 }); 541 modal.addEventListener('hidden.bs.modal', () => { 542 // Comply with the Joomla API - Remove the current Modal ID 543 Joomla.Modal.setCurrent(''); 544 }); 545 }; 546 /** 547 * Method to invoke a click on button inside an iframe 548 * 549 * @param {object} options Object with the css selector for the parent element of an iframe 550 * and the selector of the button in the iframe that will be clicked 551 * { iframeSelector: '', buttonSelector: '' } 552 * @returns {boolean} 553 * 554 * @since 4.0.0 555 */ 556 557 558 Joomla.iframeButtonClick = options => { 559 if (!options.iframeSelector || !options.buttonSelector) { 560 throw new Error('Selector is missing'); 561 } 562 563 const iframe = document.querySelector(`$options.iframeSelector} iframe`); 564 565 if (iframe) { 566 const button = iframe.contentWindow.document.querySelector(options.buttonSelector); 567 568 if (button) { 569 button.click(); 570 } 571 } 572 }; 573 574 if (Joomla && Joomla.getOptions) { 575 // Get the elements/configurations from the PHP 576 const modals = Joomla.getOptions('bootstrap.modal'); // Initialise the elements 577 578 if (typeof modals === 'object' && modals !== null) { 579 Object.keys(modals).forEach(modal => { 580 const opt = modals[modal]; 581 const options = { 582 backdrop: opt.backdrop ? opt.backdrop : true, 583 keyboard: opt.keyboard ? opt.keyboard : true, 584 focus: opt.focus ? opt.focus : true 585 }; 586 Array.from(document.querySelectorAll(modal)).map(modalEl => Joomla.initialiseModal(modalEl, options)); 587 }); 588 } 589 } 590 591 export { Modal as M };
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |