[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 /** 2 * -------------------------------------------------------------------------- 3 * Bootstrap (v5.1.3): util/index.js 4 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 5 * -------------------------------------------------------------------------- 6 */ 7 const MAX_UID = 1000000; 8 const MILLISECONDS_MULTIPLIER = 1000; 9 const TRANSITION_END = 'transitionend'; // Shoutout AngusCroll (https://goo.gl/pxwQGp) 10 11 const toType = obj => { 12 if (obj === null || obj === undefined) { 13 return `$obj}`; 14 } 15 16 return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase(); 17 }; 18 /** 19 * -------------------------------------------------------------------------- 20 * Public Util Api 21 * -------------------------------------------------------------------------- 22 */ 23 24 25 const getUID = prefix => { 26 do { 27 prefix += Math.floor(Math.random() * MAX_UID); 28 } while (document.getElementById(prefix)); 29 30 return prefix; 31 }; 32 33 const getSelector = element => { 34 let selector = element.getAttribute('data-bs-target'); 35 36 if (!selector || selector === '#') { 37 let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes, 38 // so everything starting with `#` or `.`. If a "real" URL is used as the selector, 39 // `document.querySelector` will rightfully complain it is invalid. 40 // See https://github.com/twbs/bootstrap/issues/32273 41 42 if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) { 43 return null; 44 } // Just in case some CMS puts out a full URL with the anchor appended 45 46 47 if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) { 48 hrefAttr = `#$hrefAttr.split('#')[1]}`; 49 } 50 51 selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null; 52 } 53 54 return selector; 55 }; 56 57 const getSelectorFromElement = element => { 58 const selector = getSelector(element); 59 60 if (selector) { 61 return document.querySelector(selector) ? selector : null; 62 } 63 64 return null; 65 }; 66 67 const getElementFromSelector = element => { 68 const selector = getSelector(element); 69 return selector ? document.querySelector(selector) : null; 70 }; 71 72 const getTransitionDurationFromElement = element => { 73 if (!element) { 74 return 0; 75 } // Get transition-duration of the element 76 77 78 let { 79 transitionDuration, 80 transitionDelay 81 } = window.getComputedStyle(element); 82 const floatTransitionDuration = Number.parseFloat(transitionDuration); 83 const floatTransitionDelay = Number.parseFloat(transitionDelay); // Return 0 if element or transition duration is not found 84 85 if (!floatTransitionDuration && !floatTransitionDelay) { 86 return 0; 87 } // If multiple durations are defined, take the first 88 89 90 transitionDuration = transitionDuration.split(',')[0]; 91 transitionDelay = transitionDelay.split(',')[0]; 92 return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER; 93 }; 94 95 const triggerTransitionEnd = element => { 96 element.dispatchEvent(new Event(TRANSITION_END)); 97 }; 98 99 const isElement = obj => { 100 if (!obj || typeof obj !== 'object') { 101 return false; 102 } 103 104 if (typeof obj.jquery !== 'undefined') { 105 obj = obj[0]; 106 } 107 108 return typeof obj.nodeType !== 'undefined'; 109 }; 110 111 const getElement = obj => { 112 if (isElement(obj)) { 113 // it's a jQuery object or a node element 114 return obj.jquery ? obj[0] : obj; 115 } 116 117 if (typeof obj === 'string' && obj.length > 0) { 118 return document.querySelector(obj); 119 } 120 121 return null; 122 }; 123 124 const typeCheckConfig = (componentName, config, configTypes) => { 125 Object.keys(configTypes).forEach(property => { 126 const expectedTypes = configTypes[property]; 127 const value = config[property]; 128 const valueType = value && isElement(value) ? 'element' : toType(value); 129 130 if (!new RegExp(expectedTypes).test(valueType)) { 131 throw new TypeError(`$componentName.toUpperCase()}: Option "$property}" provided type "$valueType}" but expected type "$expectedTypes}".`); 132 } 133 }); 134 }; 135 136 const isVisible = element => { 137 if (!isElement(element) || element.getClientRects().length === 0) { 138 return false; 139 } 140 141 return getComputedStyle(element).getPropertyValue('visibility') === 'visible'; 142 }; 143 144 const isDisabled = element => { 145 if (!element || element.nodeType !== Node.ELEMENT_NODE) { 146 return true; 147 } 148 149 if (element.classList.contains('disabled')) { 150 return true; 151 } 152 153 if (typeof element.disabled !== 'undefined') { 154 return element.disabled; 155 } 156 157 return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'; 158 }; 159 160 const findShadowRoot = element => { 161 if (!document.documentElement.attachShadow) { 162 return null; 163 } // Can find the shadow root otherwise it'll return the document 164 165 166 if (typeof element.getRootNode === 'function') { 167 const root = element.getRootNode(); 168 return root instanceof ShadowRoot ? root : null; 169 } 170 171 if (element instanceof ShadowRoot) { 172 return element; 173 } // when we don't find a shadow root 174 175 176 if (!element.parentNode) { 177 return null; 178 } 179 180 return findShadowRoot(element.parentNode); 181 }; 182 183 const noop = () => {}; 184 /** 185 * Trick to restart an element's animation 186 * 187 * @param {HTMLElement} element 188 * @return void 189 * 190 * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation 191 */ 192 193 194 const reflow = element => { 195 // eslint-disable-next-line no-unused-expressions 196 element.offsetHeight; 197 }; 198 199 const getjQuery = () => { 200 const { 201 jQuery 202 } = window; 203 204 if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) { 205 return jQuery; 206 } 207 208 return null; 209 }; 210 211 const DOMContentLoadedCallbacks = []; 212 213 const onDOMContentLoaded = callback => { 214 if (document.readyState === 'loading') { 215 // add listener on the first call when the document is in loading state 216 if (!DOMContentLoadedCallbacks.length) { 217 document.addEventListener('DOMContentLoaded', () => { 218 DOMContentLoadedCallbacks.forEach(callback => callback()); 219 }); 220 } 221 222 DOMContentLoadedCallbacks.push(callback); 223 } else { 224 callback(); 225 } 226 }; 227 228 const isRTL = () => document.documentElement.dir === 'rtl'; 229 230 const defineJQueryPlugin = plugin => { 231 onDOMContentLoaded(() => { 232 const $ = getjQuery(); 233 /* istanbul ignore if */ 234 235 if ($) { 236 const name = plugin.NAME; 237 const JQUERY_NO_CONFLICT = $.fn[name]; 238 $.fn[name] = plugin.jQueryInterface; 239 $.fn[name].Constructor = plugin; 240 241 $.fn[name].noConflict = () => { 242 $.fn[name] = JQUERY_NO_CONFLICT; 243 return plugin.jQueryInterface; 244 }; 245 } 246 }); 247 }; 248 249 const execute = callback => { 250 if (typeof callback === 'function') { 251 callback(); 252 } 253 }; 254 255 const executeAfterTransition = function (callback, transitionElement) { 256 let waitForTransition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; 257 258 if (!waitForTransition) { 259 execute(callback); 260 return; 261 } 262 263 const durationPadding = 5; 264 const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding; 265 let called = false; 266 267 const handler = _ref => { 268 let { 269 target 270 } = _ref; 271 272 if (target !== transitionElement) { 273 return; 274 } 275 276 called = true; 277 transitionElement.removeEventListener(TRANSITION_END, handler); 278 execute(callback); 279 }; 280 281 transitionElement.addEventListener(TRANSITION_END, handler); 282 setTimeout(() => { 283 if (!called) { 284 triggerTransitionEnd(transitionElement); 285 } 286 }, emulatedDuration); 287 }; 288 /** 289 * Return the previous/next element of a list. 290 * 291 * @param {array} list The list of elements 292 * @param activeElement The active element 293 * @param shouldGetNext Choose to get next or previous element 294 * @param isCycleAllowed 295 * @return {Element|elem} The proper element 296 */ 297 298 299 const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => { 300 let index = list.indexOf(activeElement); // if the element does not exist in the list return an element depending on the direction and if cycle is allowed 301 302 if (index === -1) { 303 return list[!shouldGetNext && isCycleAllowed ? list.length - 1 : 0]; 304 } 305 306 const listLength = list.length; 307 index += shouldGetNext ? 1 : -1; 308 309 if (isCycleAllowed) { 310 index = (index + listLength) % listLength; 311 } 312 313 return list[Math.max(0, Math.min(index, listLength - 1))]; 314 }; 315 316 /** 317 * -------------------------------------------------------------------------- 318 * Bootstrap (v5.1.3): dom/event-handler.js 319 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 320 * -------------------------------------------------------------------------- 321 */ 322 /** 323 * ------------------------------------------------------------------------ 324 * Constants 325 * ------------------------------------------------------------------------ 326 */ 327 328 const namespaceRegex = /[^.]*(?=\..*)\.|.*/; 329 const stripNameRegex = /\..*/; 330 const stripUidRegex = /::\d+$/; 331 const eventRegistry = {}; // Events storage 332 333 let uidEvent = 1; 334 const customEvents = { 335 mouseenter: 'mouseover', 336 mouseleave: 'mouseout' 337 }; 338 const customEventsRegex = /^(mouseenter|mouseleave)/i; 339 const nativeEvents = new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focusout', 'load', 'unload', 'beforeunload', 'resize', 'move', 'DOMContentLoaded', 'readystatechange', 'error', 'abort', 'scroll']); 340 /** 341 * ------------------------------------------------------------------------ 342 * Private methods 343 * ------------------------------------------------------------------------ 344 */ 345 346 function getUidEvent(element, uid) { 347 return uid && `$uid}::$uidEvent++}` || element.uidEvent || uidEvent++; 348 } 349 350 function getEvent(element) { 351 const uid = getUidEvent(element); 352 element.uidEvent = uid; 353 eventRegistry[uid] = eventRegistry[uid] || {}; 354 return eventRegistry[uid]; 355 } 356 357 function bootstrapHandler(element, fn) { 358 return function handler(event) { 359 event.delegateTarget = element; 360 361 if (handler.oneOff) { 362 EventHandler.off(element, event.type, fn); 363 } 364 365 return fn.apply(element, [event]); 366 }; 367 } 368 369 function bootstrapDelegationHandler(element, selector, fn) { 370 return function handler(event) { 371 const domElements = element.querySelectorAll(selector); 372 373 for (let { 374 target 375 } = event; target && target !== this; target = target.parentNode) { 376 for (let i = domElements.length; i--;) { 377 if (domElements[i] === target) { 378 event.delegateTarget = target; 379 380 if (handler.oneOff) { 381 EventHandler.off(element, event.type, selector, fn); 382 } 383 384 return fn.apply(target, [event]); 385 } 386 } 387 } // To please ESLint 388 389 390 return null; 391 }; 392 } 393 394 function findHandler(events, handler) { 395 let delegationSelector = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; 396 const uidEventList = Object.keys(events); 397 398 for (let i = 0, len = uidEventList.length; i < len; i++) { 399 const event = events[uidEventList[i]]; 400 401 if (event.originalHandler === handler && event.delegationSelector === delegationSelector) { 402 return event; 403 } 404 } 405 406 return null; 407 } 408 409 function normalizeParams(originalTypeEvent, handler, delegationFn) { 410 const delegation = typeof handler === 'string'; 411 const originalHandler = delegation ? delegationFn : handler; 412 let typeEvent = getTypeEvent(originalTypeEvent); 413 const isNative = nativeEvents.has(typeEvent); 414 415 if (!isNative) { 416 typeEvent = originalTypeEvent; 417 } 418 419 return [delegation, originalHandler, typeEvent]; 420 } 421 422 function addHandler(element, originalTypeEvent, handler, delegationFn, oneOff) { 423 if (typeof originalTypeEvent !== 'string' || !element) { 424 return; 425 } 426 427 if (!handler) { 428 handler = delegationFn; 429 delegationFn = null; 430 } // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position 431 // this prevents the handler from being dispatched the same way as mouseover or mouseout does 432 433 434 if (customEventsRegex.test(originalTypeEvent)) { 435 const wrapFn = fn => { 436 return function (event) { 437 if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) { 438 return fn.call(this, event); 439 } 440 }; 441 }; 442 443 if (delegationFn) { 444 delegationFn = wrapFn(delegationFn); 445 } else { 446 handler = wrapFn(handler); 447 } 448 } 449 450 const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn); 451 const events = getEvent(element); 452 const handlers = events[typeEvent] || (events[typeEvent] = {}); 453 const previousFn = findHandler(handlers, originalHandler, delegation ? handler : null); 454 455 if (previousFn) { 456 previousFn.oneOff = previousFn.oneOff && oneOff; 457 return; 458 } 459 460 const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, '')); 461 const fn = delegation ? bootstrapDelegationHandler(element, handler, delegationFn) : bootstrapHandler(element, handler); 462 fn.delegationSelector = delegation ? handler : null; 463 fn.originalHandler = originalHandler; 464 fn.oneOff = oneOff; 465 fn.uidEvent = uid; 466 handlers[uid] = fn; 467 element.addEventListener(typeEvent, fn, delegation); 468 } 469 470 function removeHandler(element, events, typeEvent, handler, delegationSelector) { 471 const fn = findHandler(events[typeEvent], handler, delegationSelector); 472 473 if (!fn) { 474 return; 475 } 476 477 element.removeEventListener(typeEvent, fn, Boolean(delegationSelector)); 478 delete events[typeEvent][fn.uidEvent]; 479 } 480 481 function removeNamespacedHandlers(element, events, typeEvent, namespace) { 482 const storeElementEvent = events[typeEvent] || {}; 483 Object.keys(storeElementEvent).forEach(handlerKey => { 484 if (handlerKey.includes(namespace)) { 485 const event = storeElementEvent[handlerKey]; 486 removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector); 487 } 488 }); 489 } 490 491 function getTypeEvent(event) { 492 // allow to get the native events from namespaced events ('click.bs.button' --> 'click') 493 event = event.replace(stripNameRegex, ''); 494 return customEvents[event] || event; 495 } 496 497 const EventHandler = { 498 on(element, event, handler, delegationFn) { 499 addHandler(element, event, handler, delegationFn, false); 500 }, 501 502 one(element, event, handler, delegationFn) { 503 addHandler(element, event, handler, delegationFn, true); 504 }, 505 506 off(element, originalTypeEvent, handler, delegationFn) { 507 if (typeof originalTypeEvent !== 'string' || !element) { 508 return; 509 } 510 511 const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn); 512 const inNamespace = typeEvent !== originalTypeEvent; 513 const events = getEvent(element); 514 const isNamespace = originalTypeEvent.startsWith('.'); 515 516 if (typeof originalHandler !== 'undefined') { 517 // Simplest case: handler is passed, remove that listener ONLY. 518 if (!events || !events[typeEvent]) { 519 return; 520 } 521 522 removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null); 523 return; 524 } 525 526 if (isNamespace) { 527 Object.keys(events).forEach(elementEvent => { 528 removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1)); 529 }); 530 } 531 532 const storeElementEvent = events[typeEvent] || {}; 533 Object.keys(storeElementEvent).forEach(keyHandlers => { 534 const handlerKey = keyHandlers.replace(stripUidRegex, ''); 535 536 if (!inNamespace || originalTypeEvent.includes(handlerKey)) { 537 const event = storeElementEvent[keyHandlers]; 538 removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector); 539 } 540 }); 541 }, 542 543 trigger(element, event, args) { 544 if (typeof event !== 'string' || !element) { 545 return null; 546 } 547 548 const $ = getjQuery(); 549 const typeEvent = getTypeEvent(event); 550 const inNamespace = event !== typeEvent; 551 const isNative = nativeEvents.has(typeEvent); 552 let jQueryEvent; 553 let bubbles = true; 554 let nativeDispatch = true; 555 let defaultPrevented = false; 556 let evt = null; 557 558 if (inNamespace && $) { 559 jQueryEvent = $.Event(event, args); 560 $(element).trigger(jQueryEvent); 561 bubbles = !jQueryEvent.isPropagationStopped(); 562 nativeDispatch = !jQueryEvent.isImmediatePropagationStopped(); 563 defaultPrevented = jQueryEvent.isDefaultPrevented(); 564 } 565 566 if (isNative) { 567 evt = document.createEvent('HTMLEvents'); 568 evt.initEvent(typeEvent, bubbles, true); 569 } else { 570 evt = new CustomEvent(event, { 571 bubbles, 572 cancelable: true 573 }); 574 } // merge custom information in our event 575 576 577 if (typeof args !== 'undefined') { 578 Object.keys(args).forEach(key => { 579 Object.defineProperty(evt, key, { 580 get() { 581 return args[key]; 582 } 583 584 }); 585 }); 586 } 587 588 if (defaultPrevented) { 589 evt.preventDefault(); 590 } 591 592 if (nativeDispatch) { 593 element.dispatchEvent(evt); 594 } 595 596 if (evt.defaultPrevented && typeof jQueryEvent !== 'undefined') { 597 jQueryEvent.preventDefault(); 598 } 599 600 return evt; 601 } 602 603 }; 604 605 /** 606 * -------------------------------------------------------------------------- 607 * Bootstrap (v5.1.3): dom/data.js 608 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 609 * -------------------------------------------------------------------------- 610 */ 611 612 /** 613 * ------------------------------------------------------------------------ 614 * Constants 615 * ------------------------------------------------------------------------ 616 */ 617 const elementMap = new Map(); 618 var Data = { 619 set(element, key, instance) { 620 if (!elementMap.has(element)) { 621 elementMap.set(element, new Map()); 622 } 623 624 const instanceMap = elementMap.get(element); // make it clear we only want one instance per element 625 // can be removed later when multiple key/instances are fine to be used 626 627 if (!instanceMap.has(key) && instanceMap.size !== 0) { 628 // eslint-disable-next-line no-console 629 console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: $Array.from(instanceMap.keys())[0]}.`); 630 return; 631 } 632 633 instanceMap.set(key, instance); 634 }, 635 636 get(element, key) { 637 if (elementMap.has(element)) { 638 return elementMap.get(element).get(key) || null; 639 } 640 641 return null; 642 }, 643 644 remove(element, key) { 645 if (!elementMap.has(element)) { 646 return; 647 } 648 649 const instanceMap = elementMap.get(element); 650 instanceMap.delete(key); // free up element references if there are no instances left for an element 651 652 if (instanceMap.size === 0) { 653 elementMap.delete(element); 654 } 655 } 656 657 }; 658 659 /** 660 * -------------------------------------------------------------------------- 661 * Bootstrap (v5.1.3): base-component.js 662 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 663 * -------------------------------------------------------------------------- 664 */ 665 /** 666 * ------------------------------------------------------------------------ 667 * Constants 668 * ------------------------------------------------------------------------ 669 */ 670 671 const VERSION = '5.1.3'; 672 673 class BaseComponent { 674 constructor(element) { 675 element = getElement(element); 676 677 if (!element) { 678 return; 679 } 680 681 this._element = element; 682 Data.set(this._element, this.constructor.DATA_KEY, this); 683 } 684 685 dispose() { 686 Data.remove(this._element, this.constructor.DATA_KEY); 687 EventHandler.off(this._element, this.constructor.EVENT_KEY); 688 Object.getOwnPropertyNames(this).forEach(propertyName => { 689 this[propertyName] = null; 690 }); 691 } 692 693 _queueCallback(callback, element) { 694 let isAnimated = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; 695 executeAfterTransition(callback, element, isAnimated); 696 } 697 /** Static */ 698 699 700 static getInstance(element) { 701 return Data.get(getElement(element), this.DATA_KEY); 702 } 703 704 static getOrCreateInstance(element) { 705 let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 706 return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null); 707 } 708 709 static get VERSION() { 710 return VERSION; 711 } 712 713 static get NAME() { 714 throw new Error('You have to implement the static method "NAME", for each component!'); 715 } 716 717 static get DATA_KEY() { 718 return `bs.$this.NAME}`; 719 } 720 721 static get EVENT_KEY() { 722 return `.$this.DATA_KEY}`; 723 } 724 725 } 726 727 /** 728 * -------------------------------------------------------------------------- 729 * Bootstrap (v5.1.3): util/component-functions.js 730 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 731 * -------------------------------------------------------------------------- 732 */ 733 734 const enableDismissTrigger = function (component) { 735 let method = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'hide'; 736 const clickEvent = `click.dismiss$component.EVENT_KEY}`; 737 const name = component.NAME; 738 EventHandler.on(document, clickEvent, `[data-bs-dismiss="$name}"]`, function (event) { 739 if (['A', 'AREA'].includes(this.tagName)) { 740 event.preventDefault(); 741 } 742 743 if (isDisabled(this)) { 744 return; 745 } 746 747 const target = getElementFromSelector(this) || this.closest(`.$name}`); 748 const instance = component.getOrCreateInstance(target); // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method 749 750 instance[method](); 751 }); 752 }; 753 754 /** 755 * -------------------------------------------------------------------------- 756 * Bootstrap (v5.1.3): dom/manipulator.js 757 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 758 * -------------------------------------------------------------------------- 759 */ 760 function normalizeData(val) { 761 if (val === 'true') { 762 return true; 763 } 764 765 if (val === 'false') { 766 return false; 767 } 768 769 if (val === Number(val).toString()) { 770 return Number(val); 771 } 772 773 if (val === '' || val === 'null') { 774 return null; 775 } 776 777 return val; 778 } 779 780 function normalizeDataKey(key) { 781 return key.replace(/[A-Z]/g, chr => `-$chr.toLowerCase()}`); 782 } 783 784 const Manipulator = { 785 setDataAttribute(element, key, value) { 786 element.setAttribute(`data-bs-$normalizeDataKey(key)}`, value); 787 }, 788 789 removeDataAttribute(element, key) { 790 element.removeAttribute(`data-bs-$normalizeDataKey(key)}`); 791 }, 792 793 getDataAttributes(element) { 794 if (!element) { 795 return {}; 796 } 797 798 const attributes = {}; 799 Object.keys(element.dataset).filter(key => key.startsWith('bs')).forEach(key => { 800 let pureKey = key.replace(/^bs/, ''); 801 pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length); 802 attributes[pureKey] = normalizeData(element.dataset[key]); 803 }); 804 return attributes; 805 }, 806 807 getDataAttribute(element, key) { 808 return normalizeData(element.getAttribute(`data-bs-$normalizeDataKey(key)}`)); 809 }, 810 811 offset(element) { 812 const rect = element.getBoundingClientRect(); 813 return { 814 top: rect.top + window.pageYOffset, 815 left: rect.left + window.pageXOffset 816 }; 817 }, 818 819 position(element) { 820 return { 821 top: element.offsetTop, 822 left: element.offsetLeft 823 }; 824 } 825 826 }; 827 828 /** 829 * -------------------------------------------------------------------------- 830 * Bootstrap (v5.1.3): dom/selector-engine.js 831 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 832 * -------------------------------------------------------------------------- 833 */ 834 const NODE_TEXT = 3; 835 const SelectorEngine = { 836 find(selector) { 837 let element = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.documentElement; 838 return [].concat(...Element.prototype.querySelectorAll.call(element, selector)); 839 }, 840 841 findOne(selector) { 842 let element = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.documentElement; 843 return Element.prototype.querySelector.call(element, selector); 844 }, 845 846 children(element, selector) { 847 return [].concat(...element.children).filter(child => child.matches(selector)); 848 }, 849 850 parents(element, selector) { 851 const parents = []; 852 let ancestor = element.parentNode; 853 854 while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE && ancestor.nodeType !== NODE_TEXT) { 855 if (ancestor.matches(selector)) { 856 parents.push(ancestor); 857 } 858 859 ancestor = ancestor.parentNode; 860 } 861 862 return parents; 863 }, 864 865 prev(element, selector) { 866 let previous = element.previousElementSibling; 867 868 while (previous) { 869 if (previous.matches(selector)) { 870 return [previous]; 871 } 872 873 previous = previous.previousElementSibling; 874 } 875 876 return []; 877 }, 878 879 next(element, selector) { 880 let next = element.nextElementSibling; 881 882 while (next) { 883 if (next.matches(selector)) { 884 return [next]; 885 } 886 887 next = next.nextElementSibling; 888 } 889 890 return []; 891 }, 892 893 focusableChildren(element) { 894 const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable="true"]'].map(selector => `$selector}:not([tabindex^="-"])`).join(', '); 895 return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el)); 896 } 897 898 }; 899 900 /** 901 * -------------------------------------------------------------------------- 902 * Bootstrap (v5.1.3): util/scrollBar.js 903 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 904 * -------------------------------------------------------------------------- 905 */ 906 const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'; 907 const SELECTOR_STICKY_CONTENT = '.sticky-top'; 908 909 class ScrollBarHelper { 910 constructor() { 911 this._element = document.body; 912 } 913 914 getWidth() { 915 // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes 916 const documentWidth = document.documentElement.clientWidth; 917 return Math.abs(window.innerWidth - documentWidth); 918 } 919 920 hide() { 921 const width = this.getWidth(); 922 923 this._disableOverFlow(); // give padding to element to balance the hidden scrollbar width 924 925 926 this._setElementAttributes(this._element, 'paddingRight', calculatedValue => calculatedValue + width); // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth 927 928 929 this._setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width); 930 931 this._setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width); 932 } 933 934 _disableOverFlow() { 935 this._saveInitialAttribute(this._element, 'overflow'); 936 937 this._element.style.overflow = 'hidden'; 938 } 939 940 _setElementAttributes(selector, styleProp, callback) { 941 const scrollbarWidth = this.getWidth(); 942 943 const manipulationCallBack = element => { 944 if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) { 945 return; 946 } 947 948 this._saveInitialAttribute(element, styleProp); 949 950 const calculatedValue = window.getComputedStyle(element)[styleProp]; 951 element.style[styleProp] = `$callback(Number.parseFloat(calculatedValue))}px`; 952 }; 953 954 this._applyManipulationCallback(selector, manipulationCallBack); 955 } 956 957 reset() { 958 this._resetElementAttributes(this._element, 'overflow'); 959 960 this._resetElementAttributes(this._element, 'paddingRight'); 961 962 this._resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight'); 963 964 this._resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight'); 965 } 966 967 _saveInitialAttribute(element, styleProp) { 968 const actualValue = element.style[styleProp]; 969 970 if (actualValue) { 971 Manipulator.setDataAttribute(element, styleProp, actualValue); 972 } 973 } 974 975 _resetElementAttributes(selector, styleProp) { 976 const manipulationCallBack = element => { 977 const value = Manipulator.getDataAttribute(element, styleProp); 978 979 if (typeof value === 'undefined') { 980 element.style.removeProperty(styleProp); 981 } else { 982 Manipulator.removeDataAttribute(element, styleProp); 983 element.style[styleProp] = value; 984 } 985 }; 986 987 this._applyManipulationCallback(selector, manipulationCallBack); 988 } 989 990 _applyManipulationCallback(selector, callBack) { 991 if (isElement(selector)) { 992 callBack(selector); 993 } else { 994 SelectorEngine.find(selector, this._element).forEach(callBack); 995 } 996 } 997 998 isOverflowing() { 999 return this.getWidth() > 0; 1000 } 1001 1002 } 1003 1004 /** 1005 * -------------------------------------------------------------------------- 1006 * Bootstrap (v5.1.3): util/backdrop.js 1007 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 1008 * -------------------------------------------------------------------------- 1009 */ 1010 const Default$1 = { 1011 className: 'modal-backdrop', 1012 isVisible: true, 1013 // if false, we use the backdrop helper without adding any element to the dom 1014 isAnimated: false, 1015 rootElement: 'body', 1016 // give the choice to place backdrop under different elements 1017 clickCallback: null 1018 }; 1019 const DefaultType$1 = { 1020 className: 'string', 1021 isVisible: 'boolean', 1022 isAnimated: 'boolean', 1023 rootElement: '(element|string)', 1024 clickCallback: '(function|null)' 1025 }; 1026 const NAME$1 = 'backdrop'; 1027 const CLASS_NAME_FADE = 'fade'; 1028 const CLASS_NAME_SHOW = 'show'; 1029 const EVENT_MOUSEDOWN = `mousedown.bs.$NAME$1}`; 1030 1031 class Backdrop { 1032 constructor(config) { 1033 this._config = this._getConfig(config); 1034 this._isAppended = false; 1035 this._element = null; 1036 } 1037 1038 show(callback) { 1039 if (!this._config.isVisible) { 1040 execute(callback); 1041 return; 1042 } 1043 1044 this._append(); 1045 1046 if (this._config.isAnimated) { 1047 reflow(this._getElement()); 1048 } 1049 1050 this._getElement().classList.add(CLASS_NAME_SHOW); 1051 1052 this._emulateAnimation(() => { 1053 execute(callback); 1054 }); 1055 } 1056 1057 hide(callback) { 1058 if (!this._config.isVisible) { 1059 execute(callback); 1060 return; 1061 } 1062 1063 this._getElement().classList.remove(CLASS_NAME_SHOW); 1064 1065 this._emulateAnimation(() => { 1066 this.dispose(); 1067 execute(callback); 1068 }); 1069 } // Private 1070 1071 1072 _getElement() { 1073 if (!this._element) { 1074 const backdrop = document.createElement('div'); 1075 backdrop.className = this._config.className; 1076 1077 if (this._config.isAnimated) { 1078 backdrop.classList.add(CLASS_NAME_FADE); 1079 } 1080 1081 this._element = backdrop; 1082 } 1083 1084 return this._element; 1085 } 1086 1087 _getConfig(config) { 1088 config = { ...Default$1, 1089 ...(typeof config === 'object' ? config : {}) 1090 }; // use getElement() with the default "body" to get a fresh Element on each instantiation 1091 1092 config.rootElement = getElement(config.rootElement); 1093 typeCheckConfig(NAME$1, config, DefaultType$1); 1094 return config; 1095 } 1096 1097 _append() { 1098 if (this._isAppended) { 1099 return; 1100 } 1101 1102 this._config.rootElement.append(this._getElement()); 1103 1104 EventHandler.on(this._getElement(), EVENT_MOUSEDOWN, () => { 1105 execute(this._config.clickCallback); 1106 }); 1107 this._isAppended = true; 1108 } 1109 1110 dispose() { 1111 if (!this._isAppended) { 1112 return; 1113 } 1114 1115 EventHandler.off(this._element, EVENT_MOUSEDOWN); 1116 1117 this._element.remove(); 1118 1119 this._isAppended = false; 1120 } 1121 1122 _emulateAnimation(callback) { 1123 executeAfterTransition(callback, this._getElement(), this._config.isAnimated); 1124 } 1125 1126 } 1127 1128 /** 1129 * -------------------------------------------------------------------------- 1130 * Bootstrap (v5.1.3): util/focustrap.js 1131 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 1132 * -------------------------------------------------------------------------- 1133 */ 1134 const Default = { 1135 trapElement: null, 1136 // The element to trap focus inside of 1137 autofocus: true 1138 }; 1139 const DefaultType = { 1140 trapElement: 'element', 1141 autofocus: 'boolean' 1142 }; 1143 const NAME = 'focustrap'; 1144 const DATA_KEY = 'bs.focustrap'; 1145 const EVENT_KEY = `.$DATA_KEY}`; 1146 const EVENT_FOCUSIN = `focusin$EVENT_KEY}`; 1147 const EVENT_KEYDOWN_TAB = `keydown.tab$EVENT_KEY}`; 1148 const TAB_KEY = 'Tab'; 1149 const TAB_NAV_FORWARD = 'forward'; 1150 const TAB_NAV_BACKWARD = 'backward'; 1151 1152 class FocusTrap { 1153 constructor(config) { 1154 this._config = this._getConfig(config); 1155 this._isActive = false; 1156 this._lastTabNavDirection = null; 1157 } 1158 1159 activate() { 1160 const { 1161 trapElement, 1162 autofocus 1163 } = this._config; 1164 1165 if (this._isActive) { 1166 return; 1167 } 1168 1169 if (autofocus) { 1170 trapElement.focus(); 1171 } 1172 1173 EventHandler.off(document, EVENT_KEY); // guard against infinite focus loop 1174 1175 EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event)); 1176 EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event)); 1177 this._isActive = true; 1178 } 1179 1180 deactivate() { 1181 if (!this._isActive) { 1182 return; 1183 } 1184 1185 this._isActive = false; 1186 EventHandler.off(document, EVENT_KEY); 1187 } // Private 1188 1189 1190 _handleFocusin(event) { 1191 const { 1192 target 1193 } = event; 1194 const { 1195 trapElement 1196 } = this._config; 1197 1198 if (target === document || target === trapElement || trapElement.contains(target)) { 1199 return; 1200 } 1201 1202 const elements = SelectorEngine.focusableChildren(trapElement); 1203 1204 if (elements.length === 0) { 1205 trapElement.focus(); 1206 } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) { 1207 elements[elements.length - 1].focus(); 1208 } else { 1209 elements[0].focus(); 1210 } 1211 } 1212 1213 _handleKeydown(event) { 1214 if (event.key !== TAB_KEY) { 1215 return; 1216 } 1217 1218 this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD; 1219 } 1220 1221 _getConfig(config) { 1222 config = { ...Default, 1223 ...(typeof config === 'object' ? config : {}) 1224 }; 1225 typeCheckConfig(NAME, config, DefaultType); 1226 return config; 1227 } 1228 1229 } 1230 1231 /** 1232 * -------------------------------------------------------------------------- 1233 * Bootstrap (v5.1.3): util/sanitizer.js 1234 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) 1235 * -------------------------------------------------------------------------- 1236 */ 1237 const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']); 1238 const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i; 1239 /** 1240 * A pattern that recognizes a commonly useful subset of URLs that are safe. 1241 * 1242 * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts 1243 */ 1244 1245 const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i; 1246 /** 1247 * A pattern that matches safe data URLs. Only matches image, video and audio types. 1248 * 1249 * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts 1250 */ 1251 1252 const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i; 1253 1254 const allowedAttribute = (attribute, allowedAttributeList) => { 1255 const attributeName = attribute.nodeName.toLowerCase(); 1256 1257 if (allowedAttributeList.includes(attributeName)) { 1258 if (uriAttributes.has(attributeName)) { 1259 return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue)); 1260 } 1261 1262 return true; 1263 } 1264 1265 const regExp = allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp); // Check if a regular expression validates the attribute. 1266 1267 for (let i = 0, len = regExp.length; i < len; i++) { 1268 if (regExp[i].test(attributeName)) { 1269 return true; 1270 } 1271 } 1272 1273 return false; 1274 }; 1275 1276 const DefaultAllowlist = { 1277 // Global attributes allowed on any supplied element below. 1278 '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN], 1279 a: ['target', 'href', 'title', 'rel'], 1280 area: [], 1281 b: [], 1282 br: [], 1283 col: [], 1284 code: [], 1285 div: [], 1286 em: [], 1287 hr: [], 1288 h1: [], 1289 h2: [], 1290 h3: [], 1291 h4: [], 1292 h5: [], 1293 h6: [], 1294 i: [], 1295 img: ['src', 'srcset', 'alt', 'title', 'width', 'height'], 1296 li: [], 1297 ol: [], 1298 p: [], 1299 pre: [], 1300 s: [], 1301 small: [], 1302 span: [], 1303 sub: [], 1304 sup: [], 1305 strong: [], 1306 u: [], 1307 ul: [] 1308 }; 1309 function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) { 1310 if (!unsafeHtml.length) { 1311 return unsafeHtml; 1312 } 1313 1314 if (sanitizeFn && typeof sanitizeFn === 'function') { 1315 return sanitizeFn(unsafeHtml); 1316 } 1317 1318 const domParser = new window.DOMParser(); 1319 const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html'); 1320 const elements = [].concat(...createdDocument.body.querySelectorAll('*')); 1321 1322 for (let i = 0, len = elements.length; i < len; i++) { 1323 const element = elements[i]; 1324 const elementName = element.nodeName.toLowerCase(); 1325 1326 if (!Object.keys(allowList).includes(elementName)) { 1327 element.remove(); 1328 continue; 1329 } 1330 1331 const attributeList = [].concat(...element.attributes); 1332 const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []); 1333 attributeList.forEach(attribute => { 1334 if (!allowedAttribute(attribute, allowedAttributes)) { 1335 element.removeAttribute(attribute.nodeName); 1336 } 1337 }); 1338 } 1339 1340 return createdDocument.body.innerHTML; 1341 } 1342 1343 export { BaseComponent as B, Data as D, EventHandler as E, FocusTrap as F, Manipulator as M, SelectorEngine as S, typeCheckConfig as a, isRTL as b, getElementFromSelector as c, defineJQueryPlugin as d, enableDismissTrigger as e, getSelectorFromElement as f, getNextActiveElement as g, getElement as h, isVisible as i, isDisabled as j, isElement as k, ScrollBarHelper as l, Backdrop as m, noop as n, findShadowRoot as o, getUID as p, DefaultAllowlist as q, reflow as r, sanitizeHtml as s, triggerTransitionEnd as t };
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 |