{"version":3,"file":"ace.js","sources":["../../js/src/util.js","../../js/src/event-handler.js","../../js/src/general.js","../../js/src/scrollbar.js","../../js/src/sidebar.js","../../js/src/aside.js","../../js/src/toaster.js","../../js/src/card.js","../../js/src/fileinput.js","../../js/src/wysiwyg.js","../../js/src/tab-scroll.js","../../js/src/tab-swipe.js","../../js/src/scroll-top.js","../../js/src/sticky.js","../../js/src/index.umd.js"],"sourcesContent":["/**\r\n * --------------------------------------------------------------------------\r\n * Ace (v4.0.0): util.js\r\n Some Utility Functions\r\n*/\r\n\r\nclass Util {\r\n static isReducedMotion () {\r\n return window.matchMedia('(prefers-reduced-motion)').matches\r\n }\r\n\r\n static isRTL () {\r\n return document.documentElement.classList.contains('rtl') || document.documentElement.dir === 'rtl'\r\n }\r\n\r\n static closest (element, selector) {\r\n if (!element) return null\r\n if ('closest' in element) return element.closest(selector)\r\n\r\n try {\r\n for (let el = element; el !== null; el = el.parentNode) {\r\n if (Util.matches(el, selector)) {\r\n return el\r\n }\r\n }\r\n } catch (e) {}\r\n\r\n return null\r\n }\r\n\r\n static matches (element, selector) {\r\n if (!element || !selector) return false\r\n\r\n if (element === selector) {\r\n // for when selector is not a string, i.e selector is the element itself (needed for when we don't know the types)\r\n return true\r\n }\r\n\r\n try {\r\n if (Util._matches) {\r\n return element.matches(selector)\r\n } else if (Util._msMatches) {\r\n return element.msMatchesSelector(selector)\r\n }\r\n } catch (e) {}\r\n\r\n return false\r\n }\r\n\r\n static isValidSelector (selector) {\r\n if (typeof selector !== 'string') return false\r\n let isValid = true\r\n try {\r\n document.createDocumentFragment().querySelector(selector)\r\n } catch (e) {\r\n isValid = false\r\n }\r\n return isValid\r\n }\r\n\r\n static _insert (element, _elem, _pos = 'afterend') {\r\n if (typeof element === 'string') element = document.querySelector(element)\r\n if (element === null) return null\r\n\r\n // check to see it _elem is a 'selector'\r\n if (Util.isValidSelector(_elem)) {\r\n const tmp = document.querySelector(_elem)\r\n _elem = tmp !== null ? tmp : _elem\r\n }\r\n\r\n let currentElemAtPos = null\r\n switch (_pos) {\r\n case 'afterend':\r\n currentElemAtPos = element.nextElementSibling\r\n break\r\n\r\n case 'beforeend':\r\n currentElemAtPos = element.lastElementChild\r\n break\r\n\r\n case 'afterbegin':\r\n currentElemAtPos = element.firstElementChild\r\n break\r\n\r\n case 'beforebegin':\r\n currentElemAtPos = element.previousElementSibling\r\n break\r\n }\r\n\r\n if (typeof _elem === 'string') {\r\n element.insertAdjacentHTML(_pos, _elem)\r\n\r\n switch (_pos) {\r\n case 'afterend':\r\n _elem = element.nextElementSibling\r\n break\r\n\r\n case 'beforeend':\r\n _elem = element.lastElementChild\r\n break\r\n\r\n case 'afterbegin':\r\n _elem = element.firstElementChild\r\n break\r\n\r\n case 'beforebegin':\r\n _elem = element.previousElementSibling\r\n break\r\n }\r\n } else {\r\n _elem = element.insertAdjacentElement(_pos, _elem)\r\n }\r\n\r\n if (_elem === currentElemAtPos) return null // it means the new element has not been inserted\r\n return _elem\r\n }\r\n\r\n static after (element, _after) {\r\n return Util._insert(element, _after, 'afterend')\r\n }\r\n\r\n static before (element, _before) {\r\n return Util._insert(element, _before, 'beforebegin')\r\n }\r\n\r\n static append (element, _append) {\r\n return Util._insert(element, _append, 'beforeend')\r\n }\r\n\r\n static prepend (element, _prepend) {\r\n return Util._insert(element, _prepend, 'afterbegin')\r\n }\r\n\r\n static wrap (element, _wrap) {\r\n _wrap = Util._insert(element, _wrap, 'afterend')\r\n if (_wrap) _wrap.appendChild(element)\r\n return _wrap\r\n }\r\n\r\n static unwrap (element, remove = true) {\r\n const parent = element.parentNode\r\n Util.after(parent, element)\r\n if (remove) Util.remove(parent)\r\n }\r\n\r\n static empty (element) {\r\n // first remove all events\r\n // element.querySelectorAll('*').forEach((el) => EventHandler.off(el))\r\n element.innerHTML = ''\r\n }\r\n\r\n static remove (element) {\r\n if (typeof element === 'string') {\r\n document.querySelectorAll(element).forEach((el) => {\r\n Util.remove(el)\r\n })\r\n return\r\n }\r\n // first remove all events\r\n // EventHandler.off(element)\r\n return element && element.parentNode && element.parentNode.removeChild(element)\r\n }\r\n\r\n static updateClass (element, className, add = true) {\r\n if (typeof element === 'string') {\r\n document.querySelectorAll(element).forEach((el) => {\r\n Util.updateClass(el, className, add)\r\n })\r\n return\r\n }\r\n\r\n if (!element) return\r\n\r\n const _classes = className.split(/\\s/)\r\n for (let _class of _classes) {\r\n _class = _class.trim()\r\n if (_class.length === 0) continue\r\n\r\n if (add) {\r\n element.classList.add(_class)\r\n } else {\r\n element.classList.remove(_class)\r\n }\r\n }\r\n }\r\n\r\n static addClass (element, className) {\r\n Util.updateClass(element, className, true)\r\n }\r\n\r\n static removeClass (element, className) {\r\n Util.updateClass(element, className, false)\r\n }\r\n\r\n static next (element, selector = null) {\r\n if (!selector) return element.nextElementSibling\r\n\r\n let _next = element\r\n while ((_next = _next.nextElementSibling) && !Util.matches(_next, selector));\r\n return _next\r\n }\r\n\r\n static prev (element, selector = null) {\r\n if (!selector) return element.previousElementSibling\r\n\r\n let _prev = element\r\n while ((_prev = _prev.previousElementSibling) && !Util.matches(_prev, selector));\r\n return _prev\r\n }\r\n\r\n static reflow (element) {\r\n return element.offsetTop\r\n }\r\n\r\n static css (element, property) {\r\n return window.getComputedStyle(element)[property]\r\n }\r\n\r\n static getScrollbarInfo (recalc = false) {\r\n if (recalc === false && Util._scrollbarInfo !== null) return Util._scrollbarInfo\r\n\r\n const scrollDiv = document.createElement('div')\r\n scrollDiv.style.overflow = 'scroll'\r\n scrollDiv.style.position = 'absolute'\r\n scrollDiv.style.width = '50px'\r\n scrollDiv.style.height = '50px'\r\n\r\n const scrollbar = {}\r\n\r\n document.body.appendChild(scrollDiv)\r\n scrollbar.width = parseInt(scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth)\r\n document.documentElement.style.setProperty('--scrollbar-width', scrollbar.width + 'px')\r\n\r\n let thinWidth = scrollbar.width\r\n if (window.CSS) {\r\n scrollbar.thin = window.CSS.supports('scrollbar-width', 'thin')// currently only firefox 64+ supports it\r\n if (scrollbar.thin) {\r\n scrollDiv.style['scrollbar-width'] = 'thin'\r\n thinWidth = parseInt(scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth)\r\n }\r\n\r\n scrollbar.overlay = window.CSS.supports('overflow', 'overlay')\r\n } else {\r\n scrollbar.thin = false\r\n\r\n scrollDiv.style.overflow = 'overlay'// Webkit/Chromium based browsers support it\r\n scrollbar.overlay = scrollbar.width > 0 && parseInt(scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth) === 0\r\n }\r\n document.documentElement.style.setProperty('--moz-scrollbar-thin', thinWidth + 'px')\r\n\r\n scrollDiv.style['-ms-overflow-style'] = '-ms-autohiding-scrollbar'// IE\r\n scrollbar.autohide = scrollbar.width > 0 && parseInt(scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth) === 0\r\n\r\n /// //////////////////////////////////\r\n document.body.removeChild(scrollDiv)\r\n Util._scrollbarInfo = scrollbar\r\n\r\n return Util._scrollbarInfo\r\n }\r\n}\r\nUtil._supportsTransitionStart = null// static property\r\nUtil._scrollbarInfo = null// static property\r\n\r\nUtil._matches = typeof document.body.matches === 'function'\r\nUtil._msMatches = typeof document.body.msMatchesSelector === 'function'\r\n\r\n/**\r\n* ------------------------------------------------------------------------\r\n* ------------------------------------------------------------------------\r\n*/\r\n\r\nexport default Util\r\n","/**\r\n *\r\n * We are using EventHandler from Bootstrap 5\r\n *\r\n */\r\n\r\n// polyfills are from MDN\r\n(function () {\r\n if (typeof window.CustomEvent !== 'function') {\r\n function CustomEvent (event, params) {\r\n params = params || { bubbles: false, cancelable: false, detail: null }\r\n const evt = document.createEvent('CustomEvent')\r\n evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail)\r\n return evt\r\n }\r\n\r\n window.CustomEvent = CustomEvent\r\n }\r\n\r\n if (!String.prototype.startsWith) {\r\n Object.defineProperty(String.prototype, 'startsWith', {\r\n value: function (search, rawPos) {\r\n const pos = rawPos > 0 ? rawPos | 0 : 0\r\n return this.substring(pos, pos + search.length) === search\r\n }\r\n })\r\n }\r\n\r\n if (!String.prototype.includes) {\r\n String.prototype.includes = function (search, start) {\r\n 'use strict'\r\n\r\n if (search instanceof RegExp) {\r\n throw TypeError('first argument must not be a RegExp')\r\n }\r\n if (start === undefined) { start = 0 }\r\n return this.indexOf(search, start) !== -1\r\n }\r\n }\r\n})()\r\n\r\n/**\r\n * --------------------------------------------------------------------------\r\n * Bootstrap (v5.0.0-beta3): dom/event-handler.js\r\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\r\n * --------------------------------------------------------------------------\r\n */\r\n\r\nconst getjQuery = () => {\r\n const { jQuery } = window\r\n\r\n if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\r\n return jQuery\r\n }\r\n\r\n return null\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Constants\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\r\nconst stripNameRegex = /\\..*/\r\nconst stripUidRegex = /::\\d+$/\r\nconst eventRegistry = {} // Events storage\r\nlet uidEvent = 1\r\nconst customEvents = {\r\n // mouseenter: 'mouseover',\r\n // mouseleave: 'mouseout'\r\n}\r\nconst nativeEvents = [\r\n 'click',\r\n 'dblclick',\r\n 'mouseup',\r\n 'mousedown',\r\n 'contextmenu',\r\n 'mousewheel',\r\n 'DOMMouseScroll',\r\n 'mouseover',\r\n 'mouseout',\r\n 'mousemove',\r\n 'selectstart',\r\n 'selectend',\r\n 'keydown',\r\n 'keypress',\r\n 'keyup',\r\n 'orientationchange',\r\n 'touchstart',\r\n 'touchmove',\r\n 'touchend',\r\n 'touchcancel',\r\n 'pointerdown',\r\n 'pointermove',\r\n 'pointerup',\r\n 'pointerleave',\r\n 'pointercancel',\r\n 'gesturestart',\r\n 'gesturechange',\r\n 'gestureend',\r\n 'focus',\r\n 'blur',\r\n 'change',\r\n 'reset',\r\n 'select',\r\n 'submit',\r\n 'focusin',\r\n 'focusout',\r\n 'load',\r\n 'unload',\r\n 'beforeunload',\r\n 'resize',\r\n 'move',\r\n 'DOMContentLoaded',\r\n 'readystatechange',\r\n 'error',\r\n 'abort',\r\n 'scroll',\r\n 'transitionstart',\r\n 'transitionend',\r\n 'animationstart',\r\n 'animationend'\r\n]\r\n\r\nconst isNativeEvent = (eventName) => nativeEvents.indexOf(eventName) >= 0\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Private methods\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nfunction getUidEvent (element, uid) {\r\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\r\n}\r\n\r\nfunction getEvent (element) {\r\n const uid = getUidEvent(element)\r\n\r\n element.uidEvent = uid\r\n eventRegistry[uid] = eventRegistry[uid] || {}\r\n\r\n return eventRegistry[uid]\r\n}\r\n\r\nfunction bootstrapHandler (element, fn) {\r\n return function handler (event) {\r\n event.delegateTarget = element\r\n\r\n if (handler.oneOff) {\r\n EventHandler.off(element, event.type, fn)\r\n }\r\n\r\n return fn.apply(element, [event])\r\n }\r\n}\r\n\r\nfunction bootstrapDelegationHandler (element, selector, fn) {\r\n return function handler (event) {\r\n const domElements = element.querySelectorAll(selector)\r\n\r\n for (let { target } = event; target && target !== this; target = target.parentNode) {\r\n for (let i = domElements.length; i--;) {\r\n if (domElements[i] === target) {\r\n event.delegateTarget = target\r\n\r\n if (handler.oneOff) {\r\n EventHandler.off(element, event.type, fn)\r\n }\r\n\r\n return fn.apply(target, [event])\r\n }\r\n }\r\n }\r\n\r\n // To please ESLint\r\n return null\r\n }\r\n}\r\n\r\nfunction findHandler (events, handler, delegationSelector = null) {\r\n const uidEventList = Object.keys(events)\r\n\r\n for (let i = 0, len = uidEventList.length; i < len; i++) {\r\n const event = events[uidEventList[i]]\r\n\r\n if (event.originalHandler === handler && event.delegationSelector === delegationSelector) {\r\n return event\r\n }\r\n }\r\n\r\n return null\r\n}\r\n\r\nfunction normalizeParams (originalTypeEvent, handler, delegationFn) {\r\n const delegation = typeof handler === 'string'\r\n const originalHandler = delegation ? delegationFn : handler\r\n\r\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\r\n let typeEvent = originalTypeEvent.replace(stripNameRegex, '')\r\n const custom = customEvents[typeEvent]\r\n\r\n if (custom) {\r\n typeEvent = custom\r\n }\r\n\r\n const isNative = isNativeEvent(typeEvent)\r\n\r\n if (!isNative) {\r\n typeEvent = originalTypeEvent\r\n }\r\n\r\n return [delegation, originalHandler, typeEvent]\r\n}\r\n\r\nfunction addHandler (element, originalTypeEvent, handler, delegationFn, oneOff) {\r\n if (typeof originalTypeEvent !== 'string' || !element) {\r\n return\r\n }\r\n\r\n if (!handler) {\r\n handler = delegationFn\r\n delegationFn = null\r\n }\r\n\r\n const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn)\r\n const events = getEvent(element)\r\n const handlers = events[typeEvent] || (events[typeEvent] = {})\r\n const previousFn = findHandler(handlers, originalHandler, delegation ? handler : null)\r\n\r\n if (previousFn) {\r\n previousFn.oneOff = previousFn.oneOff && oneOff\r\n\r\n return\r\n }\r\n\r\n const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, ''))\r\n const fn = delegation\r\n ? bootstrapDelegationHandler(element, handler, delegationFn)\r\n : bootstrapHandler(element, handler)\r\n\r\n fn.delegationSelector = delegation ? handler : null\r\n fn.originalHandler = originalHandler\r\n fn.oneOff = oneOff\r\n fn.uidEvent = uid\r\n handlers[uid] = fn\r\n\r\n element.addEventListener(typeEvent, fn, delegation)\r\n}\r\n\r\nfunction removeHandler (element, events, typeEvent, handler, delegationSelector) {\r\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\r\n\r\n if (!fn) {\r\n return\r\n }\r\n\r\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\r\n delete events[typeEvent][fn.uidEvent]\r\n}\r\n\r\nfunction removeNamespacedHandlers (element, events, typeEvent, namespace) {\r\n const storeElementEvent = events[typeEvent] || {}\r\n\r\n Object.keys(storeElementEvent).forEach(handlerKey => {\r\n if (handlerKey.includes(namespace)) {\r\n const event = storeElementEvent[handlerKey]\r\n\r\n removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)\r\n }\r\n })\r\n}\r\n\r\nconst EventHandler = {\r\n on (element, event, handler, delegationFn) {\r\n addHandler(element, event, handler, delegationFn, false)\r\n },\r\n\r\n one (element, event, handler, delegationFn) {\r\n addHandler(element, event, handler, delegationFn, true)\r\n },\r\n\r\n off (element, originalTypeEvent, handler, delegationFn) {\r\n if (typeof originalTypeEvent !== 'string' || !element) {\r\n return\r\n }\r\n\r\n const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn)\r\n const inNamespace = typeEvent !== originalTypeEvent\r\n const events = getEvent(element)\r\n const isNamespace = originalTypeEvent.startsWith('.')\r\n\r\n if (typeof originalHandler !== 'undefined') {\r\n // Simplest case: handler is passed, remove that listener ONLY.\r\n if (!events || !events[typeEvent]) {\r\n return\r\n }\r\n\r\n removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null)\r\n return\r\n }\r\n\r\n if (isNamespace) {\r\n Object.keys(events).forEach(elementEvent => {\r\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\r\n })\r\n }\r\n\r\n const storeElementEvent = events[typeEvent] || {}\r\n Object.keys(storeElementEvent).forEach(keyHandlers => {\r\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\r\n\r\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\r\n const event = storeElementEvent[keyHandlers]\r\n\r\n removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector)\r\n }\r\n })\r\n },\r\n\r\n trigger (element, event, args) {\r\n if (typeof event !== 'string' || !element) {\r\n return null\r\n }\r\n\r\n const $ = getjQuery()\r\n const typeEvent = event.replace(stripNameRegex, '')\r\n const inNamespace = event !== typeEvent\r\n const isNative = isNativeEvent(typeEvent)\r\n\r\n let jQueryEvent\r\n let bubbles = true\r\n let nativeDispatch = true\r\n let defaultPrevented = false\r\n let evt = null\r\n\r\n if (inNamespace && $) {\r\n jQueryEvent = $.Event(event, args)\r\n\r\n $(element).trigger(jQueryEvent)\r\n bubbles = !jQueryEvent.isPropagationStopped()\r\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\r\n defaultPrevented = jQueryEvent.isDefaultPrevented()\r\n }\r\n\r\n if (isNative) {\r\n evt = document.createEvent('HTMLEvents')\r\n evt.initEvent(typeEvent, bubbles, true)\r\n } else {\r\n evt = new window.CustomEvent(event, {\r\n bubbles,\r\n cancelable: true\r\n })\r\n }\r\n\r\n // merge custom information in our event\r\n if (typeof args !== 'undefined') {\r\n Object.keys(args).forEach(key => {\r\n Object.defineProperty(evt, key, {\r\n get () {\r\n return args[key]\r\n }\r\n })\r\n })\r\n }\r\n\r\n if (defaultPrevented) {\r\n evt.preventDefault()\r\n }\r\n\r\n if (nativeDispatch) {\r\n element.dispatchEvent(evt)\r\n }\r\n\r\n if (evt.defaultPrevented && typeof jQueryEvent !== 'undefined') {\r\n jQueryEvent.preventDefault()\r\n }\r\n\r\n return evt\r\n }\r\n}\r\n\r\nexport default EventHandler\r\n","/**\r\n * --------------------------------------------------------------------------\r\n * Ace (v4.0.0): general.js\r\n General Ace Functions\r\n*/\r\n\r\nimport Util from './util'\r\n\r\nclass Basic {\r\n static _HandleBasics () {\r\n Basic._HandleGeneral()\r\n\r\n if (typeof window.jQuery === 'undefined' || typeof window.bootstrap === 'undefined') return\r\n\r\n Basic._handleAlerts()\r\n\r\n Basic._handleDropdowns()\r\n\r\n Basic._handleNavbar()\r\n }\r\n\r\n static _HandleGeneral () {\r\n window.addEventListener('DOMContentLoaded', () => {\r\n document.body.classList.add('is-document-loaded')\r\n })\r\n\r\n // for IE\r\n if (window.NodeList && !window.NodeList.prototype.forEach) {\r\n window.NodeList.prototype.forEach = Array.prototype.forEach\r\n }\r\n }\r\n\r\n /**\r\n * collapse .alert instead of fading it out\r\n */\r\n static _handleAlerts () {\r\n const $ = window.jQuery\r\n\r\n $(document)\r\n .on('close.bs.alert.alert-collapse', '.alert.alert-collapse', function (e) {\r\n e.preventDefault()\r\n $(this).wrap('
').parent().collapse('hide').one('hidden.bs.collapse.alert-collapse', function () {\r\n $(this).remove()\r\n })\r\n })\r\n }\r\n\r\n /// ////////\r\n\r\n static _handleDropdowns () {\r\n const $ = window.jQuery\r\n\r\n // dismiss (hide) a dropdown menu\r\n const _dismissDropdown = function () {\r\n const menu = Util.closest(this, '.dropdown-menu')\r\n const dropdown = menu.parentNode\r\n const toggle = dropdown.querySelector('[data-toggle=dropdown]')\r\n\r\n $(toggle).dropdown('hide')\r\n menu.classList.remove('show')\r\n dropdown.classList.remove('show')\r\n }\r\n\r\n // hide dropdown when clicked on an element inside it with `data-dismiss=dropdown` attribute\r\n $(document)\r\n .on('click', '[data-dismiss=dropdown]', function (e) {\r\n e.preventDefault()\r\n _dismissDropdown.call(e.target)\r\n })\r\n\r\n // hide dropdown when a `form` inside it is submitted\r\n $(document)\r\n .on('submit', '.dropdown-menu form[data-submit=dismiss]', function (e) {\r\n e.preventDefault()\r\n _dismissDropdown.call(e.target)\r\n })\r\n\r\n // don't hide dropdown when clicked inside a `.dropdown-clickable` element\r\n $(document)\r\n .on('click.dropdown-clickable', '.dropdown-clickable', function (e) {\r\n e.stopImmediatePropagation()\r\n })\r\n\r\n // hide `body` scrollbars when dropdowns are opened in mobile view\r\n $(document)\r\n .on('shown.bs.dropdown', '.dropdown.dd-backdrop', function () {\r\n // check `display` of .dropdown::before, if not visible it means `backdrop` is not visible (applied)\r\n if (window.getComputedStyle(this, ':before').display === 'none') return\r\n\r\n // the device width is such that backdrop is visible (.dropdown-inner is visible)\r\n const scrollbarInfo = Util.getScrollbarInfo()\r\n if (scrollbarInfo.width === 0) {\r\n document.body.classList.add('mob-dropdown-body')\r\n }\r\n this.classList.add('backdrop-shown')// used later to add `.navbar-modal` class to .navbar\r\n\r\n $(this)\r\n .one('hidden.bs.dropdown', function () {\r\n document.body.classList.remove('mob-dropdown-body')\r\n this.classList.remove('backdrop-shown')\r\n })\r\n })\r\n }\r\n\r\n /// ////////\r\n\r\n static _handleNavbar () {\r\n const $ = window.jQuery\r\n\r\n // hide `.navbar-collapse` when clicked on it (specifically on the backdrop in mobile view)\r\n $(document)\r\n .on('click', '.navbar-backdrop.collapse.show', function (e) {\r\n if (e.target === this) $(this).collapse('hide')\r\n })\r\n\r\n // hide dropdown when a `form` inside it is submitted\r\n $(document)\r\n .on('submit', '.navbar-collapse.show form[data-submit=dismiss]', function (e) {\r\n e.preventDefault()\r\n $(this).closest('.navbar-collapse').collapse('hide')\r\n })\r\n\r\n // when navbar or a dropdown-menu inside it is displayed, move focus to the \".autofocus\" element.\r\n // For example a search box can be .autofocus\r\n\r\n let currentOpenCollapse = null\r\n $(document)\r\n .on('shown.bs.dropdown', '.navbar .dropdown', function () {\r\n const autofocus = this.querySelector('.autofocus')\r\n if (autofocus) autofocus.focus()\r\n })\r\n .on('show.bs.collapse', '.navbar-collapse', function (ev) {\r\n if (ev.isDefaultPrevented()) return\r\n // also hide body scrollbars in mobile devices\r\n if (this.classList.contains('navbar-backdrop')) {\r\n const scrollbarInfo = Util.getScrollbarInfo()\r\n if (scrollbarInfo.width === 0) {\r\n document.body.classList.add('mob-navbar-body')\r\n }\r\n }\r\n\r\n const previousOpenCollapse = currentOpenCollapse\r\n currentOpenCollapse = ev.target\r\n\r\n if (previousOpenCollapse !== null) {\r\n $('.navbar-collapse.show').css('transition-duration', '1ms').collapse('hide').css('transition-duration', '')\r\n }\r\n })\r\n .on('shown.bs.collapse', '.navbar-collapse', function () {\r\n const autofocus = this.querySelector('.autofocus')\r\n if (autofocus) autofocus.focus()\r\n })\r\n .on('hidden.bs.collapse', function (ev) {\r\n if (currentOpenCollapse === ev.target) {\r\n // no more open collapsed (the currentOpenCollapse it the last one)\r\n document.body.classList.remove('mob-navbar-body')\r\n currentOpenCollapse = null\r\n }\r\n })\r\n\r\n // if navbar dropdowns are not entirely inside window area, move them accordingly\r\n const _adjustDropdown = function () {\r\n const isRTL = Util.isRTL()\r\n const isRightAligned = this.classList.contains('dropdown-menu-right')\r\n\r\n const _dir = !isRightAligned ? (!isRTL ? 'left' : 'right') : (!isRTL ? 'right' : 'left')\r\n const prop = 'margin-' + _dir\r\n\r\n this.style.removeProperty(prop)\r\n\r\n let moveBy = 0\r\n const rect = this.getBoundingClientRect()\r\n if (rect.left < 0) {\r\n moveBy = parseInt(-1 * rect.left) + 5\r\n } else {\r\n const sw = document.body.scrollWidth\r\n if (rect.right > sw) {\r\n moveBy = parseInt(sw - rect.right - 5)\r\n }\r\n }\r\n\r\n if (moveBy < 5) return\r\n\r\n if (isRightAligned) moveBy *= -1\r\n this.style.setProperty(prop, moveBy + 'px', 'important')\r\n }\r\n\r\n $(document)\r\n .on('transitionstart.adjust', '.navbar .dropdown-mega .dropdown-menu', function (ev) {\r\n // adjust when hovered (dropdown-hover)\r\n if (ev.target !== this || ev.originalEvent.propertyName !== 'transform') return\r\n _adjustDropdown.call(this)\r\n })\r\n .on('shown.bs.dropdown', '.navbar .dropdown', function () {\r\n // adjus when \"shown\" (click)\r\n if (this.classList.contains('dropdown-mega')) {\r\n const dropdown = this.querySelector('.dropdown-menu[data-display=\"static\"]')\r\n if (dropdown !== null) _adjustDropdown.call(dropdown)\r\n }\r\n\r\n // when a .dropdown is opened, add .navbar-open to increase z-index, so that dropdowns go above 'asides', etc\r\n const navbar = Util.closest(this, '.navbar')\r\n if (!navbar) return\r\n if (this.classList.contains('backdrop-shown')) navbar.classList.add('navbar-modal')\r\n else navbar.classList.add('navbar-open')\r\n })\r\n .on('hidden.bs.dropdown', '.navbar .dropdown', function () {\r\n const navbar = Util.closest(this, '.navbar')\r\n if (!navbar) return\r\n navbar.classList.remove('navbar-open')\r\n navbar.classList.remove('navbar-modal')\r\n })\r\n }\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n*/\r\n\r\nBasic._HandleBasics()\r\n\r\nexport default Basic\r\n","/**\r\n * --------------------------------------------------------------------------\r\n * Ace (v4.0.0): scrollbar.js\r\n*/\r\n\r\nimport Util from './util'\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Constants\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nconst NAME = 'aceScroll'\r\nconst VERSION = '4.0.0'\r\nconst DATA_KEY = 'ace.scroll'\r\nconst EVENT_KEY = `.${DATA_KEY}`\r\nconst DATA_API_KEY = '.data-api'\r\n\r\nconst Event = {\r\n LOAD_DATA_API: `load${EVENT_KEY}${DATA_API_KEY}`\r\n}\r\n\r\nconst Selector = {\r\n ACE_SCROLL: '[ace-scroll]',\r\n DATA_ACE_SCROLL: '[data-ace-scroll]'\r\n}\r\n\r\nconst DefaultType = {\r\n type: 'string',\r\n smooth: 'boolean',\r\n\r\n height: '(number|null)',\r\n lock: 'boolean',\r\n\r\n ignore: '(string|null)',\r\n\r\n plugin: 'string',\r\n options: '(object|null)', // plugin settings\r\n\r\n color: '(string|null)',\r\n autohide: '(boolean|null)'\r\n}\r\n\r\nconst Default = {\r\n type: 'native',\r\n smooth: false,\r\n\r\n height: null,\r\n lock: false,\r\n\r\n ignore: null,\r\n\r\n plugin: 'SimpleBar',\r\n options: null,\r\n\r\n color: null,\r\n autohide: true\r\n}\r\n\r\nclass Scrollbar {\r\n constructor (element, config) {\r\n this._element\t= element\r\n this._config = this._getConfig(config)\r\n\r\n this._scrollbarInfo = Util.getScrollbarInfo()\r\n\r\n this.enableScrollbars()\r\n }\r\n\r\n static get VERSION () {\r\n return VERSION\r\n }\r\n\r\n static get DefaultType () {\r\n return DefaultType\r\n }\r\n\r\n static get Default () {\r\n return Default\r\n }\r\n\r\n enableScrollbars () {\r\n /**\r\n this._element.scrollTop = 0\r\n // For firefox. Because it has persistent scroll position on page reload\r\n // which doesn't look good when changing overflow: hidden to overflow: scroll on hover\r\n */\r\n\r\n // no scrollbars when specified\r\n if (this._config.ignore !== null) {\r\n if (this._config.ignore === 'mobile' && this._scrollbarInfo.width === 0 && 'ontouchstart' in window && window.matchMedia('(max-width: 840px)').matches) return\r\n else if (this._config.ignore === 'desktop' && this._scrollbarInfo.width > 0) return\r\n }\r\n\r\n this.update(this._config.height)\r\n this.lock(this._config.lock)\r\n\r\n this._element.classList.remove('ace-scroll', 'ace-scroll-mob', 'ace-scroll-wrap')\r\n if (this._config.type === 'native') {\r\n this._addNativeScrolls()\r\n } else if (this._config.type === 'auto') {\r\n this._preferNativeScrolls()\r\n } else if (this._config.type === 'plugin') {\r\n this._addPluginScrolls()\r\n }\r\n }\r\n\r\n update (_height) {\r\n if (!_height) return\r\n if (!isNaN(_height)) _height += 'px'\r\n this._element.style.maxHeight = _height\r\n }\r\n\r\n lock (_lock) {\r\n if (_lock) this._element.classList.add('ace-scroll-lock')\r\n else this._element.classList.remove('ace-scroll-lock')\r\n }\r\n\r\n _addNativeScrolls (smooth) {\r\n if (this._scrollbarInfo.width === 0) this._element.classList.add('ace-scroll-mob')// mobile device\r\n else {\r\n this._element.classList.add('ace-scroll')\r\n\r\n if (this._config.color !== null) this._element.classList.add('ace-scroll-' + this._config.color)\r\n if (this._config.autohide === false) this._element.classList.add('is-always-on')\r\n\r\n const _smooth = typeof smooth !== 'undefined' ? smooth : this._config.smooth\r\n if (_smooth) {\r\n // wrap children inside an .ace-scroll-inner\r\n const wrapper = document.createElement('div')\r\n wrapper.classList.add('ace-scroll-inner')\r\n wrapper.style.color = window.getComputedStyle(this._element).color\r\n\r\n while (this._element.firstChild) {\r\n wrapper.appendChild(this._element.firstChild)\r\n }\r\n this._element.appendChild(wrapper)\r\n\r\n /// ///////\r\n // disable the initial transition effects\r\n this._element.style.transition = 'none'\r\n\r\n this._element.classList.add('ace-scroll-wrap')\r\n this._element.offsetHeight// reflow\r\n this._element.style.transition = ''\r\n }\r\n }\r\n }\r\n\r\n _preferNativeScrolls () {\r\n if (this._scrollbarInfo.width === 0 || this._scrollbarInfo.overlay || this._scrollbarInfo.thin || !this._hasScrollbarPlugin()) {\r\n this._addNativeScrolls()\r\n } else {\r\n this._addPluginScrolls()\r\n }\r\n }\r\n\r\n _addPluginScrolls () {\r\n if (this._hasScrollbarPlugin()) {\r\n return new window[this._config.plugin](this._element, this._config.options)\r\n } else {\r\n this._addNativeScrolls()\r\n }\r\n }\r\n\r\n _hasScrollbarPlugin () {\r\n return !!window[this._config.plugin]\r\n }\r\n\r\n _getConfig (config) {\r\n let options = this._element.getAttribute('ace-scroll') || this._element.getAttribute('data-ace-scroll') || {}\r\n if (!isNaN(options)) options = { height: parseInt(options) }\r\n else if (options.length > 1) {\r\n try {\r\n options = JSON.parse(options)\r\n } catch (e) {}\r\n }\r\n\r\n config = {\r\n ...Default,\r\n ...typeof config === 'object' && config ? config : {},\r\n ...typeof options === 'object' && options ? options : {}\r\n }\r\n\r\n if (typeof window.bootstrap !== 'undefined') {\r\n window.bootstrap.Util.typeCheckConfig(\r\n NAME,\r\n config,\r\n this.constructor.DefaultType\r\n )\r\n }\r\n\r\n return config\r\n }\r\n\r\n // Static methods\r\n static getInstance (element, config = null) {\r\n if (!element) throw new Error('element for Scrollbar is null')\r\n\r\n const name = `__${NAME}__`\r\n if (typeof element[name] !== 'undefined') return element[name]\r\n\r\n element[name] = new Scrollbar(element, config)\r\n return element[name]\r\n }\r\n\r\n static _jQueryInterface (config) {\r\n return this.each(function () {\r\n const $this = window.jQuery(this)\r\n let data = $this.data(DATA_KEY)\r\n\r\n let options = this.getAttribute('ace-scroll') || this.getAttribute('data-ace-scroll') || {}\r\n if (!isNaN(options)) options = { height: parseInt(options) }\r\n else if (options.length > 1) {\r\n try {\r\n options = JSON.parse(options)\r\n } catch (e) {}\r\n }\r\n\r\n const _config = {\r\n ...Default,\r\n ...$this.data(),\r\n ...typeof config === 'object' && config ? config : {},\r\n ...typeof options === 'object' && options ? options : {}\r\n }\r\n\r\n if (!data) {\r\n data = Scrollbar.getInstance(this, _config)\r\n $this.data(DATA_KEY, data)\r\n }\r\n\r\n if (typeof config === 'string') {\r\n if (typeof data[config] === 'undefined') {\r\n throw new TypeError(`No method named \"${config}\"`)\r\n }\r\n data[config]()\r\n }\r\n })\r\n }\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * jQuery\r\n * ------------------------------------------------------------------------\r\n*/\r\nif (typeof window.jQuery !== 'undefined') {\r\n const $ = window.jQuery\r\n\r\n $(window).on(Event.LOAD_DATA_API, () => {\r\n const scrollbars = ([].slice.call(document.querySelectorAll(Selector.ACE_SCROLL))).concat([].slice.call(document.querySelectorAll(Selector.DATA_ACE_SCROLL)))\r\n\r\n for (let i = 0; i < scrollbars.length; i++) {\r\n const $scrollbars = $(scrollbars[i])\r\n Scrollbar._jQueryInterface.call($scrollbars, $scrollbars.data())\r\n }\r\n })\r\n\r\n const JQUERY_NO_CONFLICT = $.fn[NAME]\r\n $.fn[NAME] = Scrollbar._jQueryInterface\r\n $.fn[NAME].Constructor = Scrollbar\r\n $.fn[NAME].noConflict = () => {\r\n $.fn[NAME] = JQUERY_NO_CONFLICT\r\n return Scrollbar._jQueryInterface\r\n }\r\n}\r\n\r\nexport default Scrollbar\r\n","/**\r\n * --------------------------------------------------------------------------\r\n * Ace (v4.0.0): sidebar.js\r\n Handling Sidebar\r\n*/\r\n\r\nimport Util from './util'\r\nimport EventHandler from './event-handler'\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Constants\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nconst NAME = 'aceSidebar'\r\nconst VERSION = '4.0.0'\r\nconst DATA_KEY = 'ace.sidebar'\r\nconst EVENT_KEY = `.${DATA_KEY}`\r\nconst DATA_API_KEY = '.data-api'\r\n\r\nconst Event = {\r\n SHOW: `show${EVENT_KEY}`,\r\n HIDE: `hide${EVENT_KEY}`,\r\n COLLAPSE: `collapse${EVENT_KEY}`,\r\n EXPAND: `expand${EVENT_KEY}`,\r\n SHOWN: `shown${EVENT_KEY}`,\r\n HIDDEN: `hidden${EVENT_KEY}`,\r\n COLLAPSED: `collapsed${EVENT_KEY}`,\r\n EXPANDED: `expanded${EVENT_KEY}`,\r\n LOAD_DATA_API: `load${EVENT_KEY}${DATA_API_KEY}`,\r\n CLICK_DATA_API: `click${EVENT_KEY}${DATA_API_KEY}`\r\n}\r\n\r\nconst Selector = {\r\n SIDEBAR: '.sidebar',\r\n DATA_TOGGLE: '[data-toggle=\"sidebar\"]',\r\n DATA_TOGGLE_MOBILE: '[data-toggle-mobile=\"sidebar\"]'\r\n}\r\n\r\nconst DefaultType = {\r\n swipe: 'boolean',\r\n dismiss: 'boolean',\r\n backdrop: 'boolean',\r\n\r\n gotoactive: 'boolean',\r\n subscroll: 'boolean',\r\n subtoggle: 'boolean',\r\n\r\n pullup: 'boolean'\r\n}\r\n\r\nconst Default = {\r\n swipe: false,\r\n dismiss: false,\r\n backdrop: false,\r\n\r\n gotoactive: false,\r\n subscroll: true,\r\n subtoggle: true,\r\n\r\n pullup: false\r\n}\r\n\r\nconst ClassName = {\r\n DESKTOP_HIDE: 'collapsed',\r\n MOBILE_SHOW: 'sidebar-visible',\r\n COLLAPSED:\t'collapsed',\r\n\r\n TOGGLING: 'toggling',\r\n\r\n INNER_HOVER: 'is-hover',\r\n\r\n BACKDROP: 'sidebar-backdrop',\r\n\r\n HORIZONTAL: 'sidebar-h'\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Class Definition\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nclass Sidebar {\r\n constructor (element, config) {\r\n this._config = this._getConfig(config)\r\n\r\n this._hasTransitionEvent = false\r\n this._hasTransitionEventMobile = false\r\n this._isTransitioning = false\r\n this._isTransitioningMobile = false\r\n\r\n this._sidebar = element\r\n\r\n Util.reflow(this._sidebar) // force reflow, so that if we instantly call 'collapse' or 'expand', transition effect takes place\r\n this._sidebar.classList.add('sidebar')\r\n this._inner = this._sidebar.querySelector('.sidebar-inner')\r\n this._scroller = this._sidebar.querySelector('[class*=\"ace-scroll\"]')\r\n\r\n this._isSubOpening = false\r\n if (this._sidebar.querySelector('.submenu.show') !== null) this._sidebar.classList.add('has-open')\r\n\r\n this._pullupEnabled = false\r\n this._pullupCallback = null\r\n\r\n this._triggerArray = [].slice.call(document.querySelectorAll(\r\n `[data-toggle=\"sidebar\"][href=\"#${element.id}\"],` +\r\n `[data-toggle=\"sidebar\"][data-target=\"#${element.id}\"]`\r\n ))\r\n this._triggerArrayMobile = [].slice.call(document.querySelectorAll(\r\n `[data-toggle-mobile=\"sidebar\"][href=\"#${element.id}\"],` +\r\n `[data-toggle-mobile=\"sidebar\"][data-target=\"#${element.id}\"]`\r\n ))\r\n\r\n this._horizontal = this._sidebar.classList.contains(ClassName.HORIZONTAL)\r\n this._desktopCollapsedClass = this._triggerArray.length > 0 ? (this._triggerArray[0].getAttribute('data-toggle-class') || ClassName.DESKTOP_HIDE) : ClassName.DESKTOP_HIDE\r\n\r\n //\r\n this._collapsed = this._sidebar.classList.contains(this._desktopCollapsedClass)\r\n this._hidden = !this._sidebar.classList.contains(ClassName.MOBILE_SHOW)\r\n\r\n EventHandler.on(this._inner, 'focus', 'input', (e) => {\r\n if (!this._collapsed) return\r\n this._inner.classList.add('has-focus')\r\n EventHandler.one(e.delegateTarget, 'blur', () => {\r\n this._inner.classList.remove('has-focus')\r\n })\r\n })\r\n //\r\n\r\n this._handleTriggerEvents()\r\n\r\n if (this._config.subtoggle) this.enableSubmenuToggle()\r\n\r\n if (this._config.pullup) this.enableSubmenuPullup()\r\n if (this._config.gotoactive) this.scrollToActive()\r\n if (this._config.backdrop) {\r\n this._sidebar.classList.add(ClassName.BACKDROP)\r\n } else if (this._sidebar.classList.contains(ClassName.BACKDROP)) {\r\n this._config.backdrop = true\r\n }\r\n\r\n if (!this._horizontal && this._collapsed) {\r\n this._addTransitionEvent()\r\n }\r\n }\r\n\r\n // Getters\r\n static get VERSION () {\r\n return VERSION\r\n }\r\n\r\n static get Default () {\r\n return Default\r\n }\r\n\r\n static get DefaultType () {\r\n return DefaultType\r\n }\r\n\r\n _handleTriggerEvents () {\r\n this._triggerArray.forEach((el) => {\r\n el.addEventListener('click', () => this.toggle(el))\r\n })\r\n\r\n this._triggerArrayMobile.forEach((el) => {\r\n el.addEventListener('click', () => this.toggleMobile(el))\r\n })\r\n }\r\n\r\n toggle (btn = null) {\r\n if (this._sidebar.classList.contains(this._desktopCollapsedClass)) {\r\n this.expand(btn)\r\n } else {\r\n this.collapse(btn)\r\n }\r\n }\r\n\r\n toggleMobile (btn = null) {\r\n if (!this._sidebar.classList.contains(ClassName.MOBILE_SHOW)) {\r\n this.show(btn)\r\n } else {\r\n this.hide(btn)\r\n }\r\n }\r\n\r\n /// ////\r\n\r\n expand (btn = null) {\r\n if (!this._hasTransitionEvent) this._addTransitionEvent()\r\n if (this._isTransitioning || !this._collapsed) return\r\n\r\n const ev = EventHandler.trigger(this._sidebar, Event.EXPAND)\r\n if (ev.defaultPrevented) return\r\n\r\n this._isTransitioning = true\r\n this._collapsed = false\r\n\r\n this._sidebar.classList.add(ClassName.TOGGLING)\r\n this._sidebar.classList.remove(this._desktopCollapsedClass)\r\n\r\n this._updateTriggerBtns(this._triggerArray, true)\r\n\r\n /**\r\n * If no transition or horizontal or in mobile view (width == 0)\r\n */\r\n if (Util.isReducedMotion() || this._sidebar.classList.contains('no-transition') || this._horizontal || this._sidebar.offsetWidth === 0) this._toggleCompleted()// call completion now\r\n\r\n //\r\n if (this._pullupEnabled) this._resetPullUp()\r\n }\r\n\r\n collapse (btn = null) {\r\n if (!this._hasTransitionEvent) this._addTransitionEvent()\r\n if (this._isTransitioning || this._collapsed) return\r\n\r\n const ev = EventHandler.trigger(this._sidebar, Event.COLLAPSE)\r\n if (ev.defaultPrevented) return\r\n\r\n this._isTransitioning = true\r\n this._collapsed = true\r\n\r\n this._sidebar.classList.add(ClassName.TOGGLING)\r\n this._sidebar.classList.add(this._desktopCollapsedClass)\r\n\r\n this._updateTriggerBtns(this._triggerArray, false)\r\n\r\n /**\r\n * If no transition or horizontal or in mobile view (width == 0)\r\n */\r\n if (Util.isReducedMotion() || this._sidebar.classList.contains('no-transition') || this._horizontal || this._sidebar.offsetWidth === 0) this._toggleCompleted()// call completion now\r\n\r\n //\r\n if (this._pullupEnabled) this._resetPullUp()\r\n\r\n // if the triggering button is inside sidebar and we want it to remain expanded (.let-expanded), add .is-hover class as well\r\n if (btn !== null && this._sidebar.classList.contains('expandable') && this._sidebar.classList.contains('let-expanded') && this._inner.contains(btn)) {\r\n this._inner.classList.add(ClassName.INNER_HOVER)\r\n }\r\n }\r\n\r\n isCollapsed () {\r\n return this._collapsed\r\n }\r\n\r\n show (btn = null) {\r\n if (!this._hasTransitionEventMobile) this._addTransitionEventMobile()\r\n if (this._isTransitioningMobile || !this._hidden) return\r\n\r\n const ev = EventHandler.trigger(this._sidebar, Event.SHOW)\r\n if (ev.defaultPrevented) return\r\n\r\n this._isTransitioningMobile = true\r\n this._hidden = false\r\n\r\n this._sidebar.classList.add(ClassName.MOBILE_SHOW)\r\n this._updateTriggerBtns(this._triggerArrayMobile, true)\r\n\r\n // hide sidebar if clicked outside of it\r\n if (this._config.dismiss) {\r\n this._triggerArrayMobile.forEach((el) => { el.style.pointerEvents = 'none' }) // disable this button, because if we click on it, it will hide and then instantly show the sidebar again\r\n\r\n EventHandler.on(document, 'mouseup.sidebar-dismiss', (e) => {\r\n if (!this._inner.contains(e.target)) { // if clicked outside sidebar\r\n this.hide()\r\n }\r\n })\r\n }\r\n\r\n if (this._config.swipe) this.enableSwipeHide()\r\n\r\n if (Util.isReducedMotion()) this._toggleMobileCompleted()// call completion now\r\n\r\n // in some webkit mobile browsers, sidebar scrolling works but scrollbars are not visible, unless something like this forces it to become visible\r\n if (this._scroller && !this._scroller.classList.contains('overflow-hidden')) {\r\n this._scroller.classList.add('overflow-hidden')\r\n Util.reflow(this._scroller)// force redraw\r\n this._scroller.classList.remove('overflow-hidden')\r\n }\r\n\r\n // hide body scrollbars\r\n // if sidebar is fixed and has backdrop or is .sidebar-push\r\n const scrollbarInfo = Util.getScrollbarInfo()\r\n if (scrollbarInfo.width === 0 && this._sidebar.classList.contains('sidebar-fixed') && (this._config.backdrop || this._sidebar.classList.contains('sidebar-push'))) {\r\n document.body.classList.add('mob-sidebar-body')\r\n }\r\n }\r\n\r\n hide (btn = null) {\r\n if (!this._hasTransitionEventMobile) this._addTransitionEventMobile()\r\n if (this._isTransitioningMobile || this._hidden) return\r\n\r\n const ev = EventHandler.trigger(this._sidebar, Event.HIDE)\r\n if (ev.defaultPrevented) return\r\n\r\n this._isTransitioningMobile = true\r\n this._hidden = true\r\n\r\n this._sidebar.classList.remove(ClassName.MOBILE_SHOW)\r\n this._updateTriggerBtns(this._triggerArrayMobile, false)\r\n\r\n if (this._config.dismiss) {\r\n this._triggerArrayMobile.forEach((el) => { el.style.pointerEvents = '' })\r\n EventHandler.off(document, '.sidebar-dismiss')\r\n }\r\n if (this._config.swipe) {\r\n EventHandler.off(document, '.sidebar-swipe')\r\n }\r\n\r\n if (Util.isReducedMotion()) this._toggleMobileCompleted()// call completion now\r\n }\r\n\r\n isHidden () {\r\n return this._hidden\r\n }\r\n\r\n _updateTriggerBtns (btns, expanded = false) {\r\n for (let i = 0, len = btns.length; i < len; i++) {\r\n if (expanded) btns[i].classList.remove(ClassName.COLLAPSED)\r\n else btns[i].classList.add(ClassName.COLLAPSED)\r\n\r\n btns[i].setAttribute('aria-expanded', expanded)\r\n }\r\n }\r\n\r\n _toggleCompleted () {\r\n this._isTransitioning = false\r\n this._sidebar.classList.remove(ClassName.TOGGLING)\r\n\r\n const expanded = !this._sidebar.classList.contains(this._desktopCollapsedClass)\r\n if (expanded) {\r\n this._inner.classList.remove(ClassName.INNER_HOVER)\r\n EventHandler.trigger(this._sidebar, Event.EXPANDED)\r\n } else {\r\n EventHandler.trigger(this._sidebar, Event.COLLAPSED)\r\n }\r\n }\r\n\r\n _toggleMobileCompleted () {\r\n this._isTransitioningMobile = false\r\n const shown = this._sidebar.classList.contains(ClassName.MOBILE_SHOW)\r\n if (shown) EventHandler.trigger(this._sidebar, Event.SHOWN)\r\n else {\r\n document.body.classList.remove('mob-sidebar-body')\r\n if (this._config.swipe) {\r\n document.body.classList.remove('mob-sidebarswipe-body')\r\n }\r\n\r\n EventHandler.trigger(this._sidebar, Event.HIDDEN)\r\n }\r\n }\r\n\r\n _addTransitionEvent () {\r\n if (this._hasTransitionEvent) return\r\n this._hasTransitionEvent = true\r\n let counter = 0\r\n\r\n this._sidebar.addEventListener('transitionend', (e) => {\r\n if (e.target !== this._sidebar) return// make sure its not the children triggerring the event!\r\n\r\n this._toggleCompleted()\r\n\r\n counter = 0\r\n })\r\n\r\n // add 'is-hover' class to '.sidebar-inner' when it becomes expanded (i.e. when mouse hovers it)\r\n this._inner.addEventListener('transitionstart', (e) => {\r\n // skip on mobile (in which propertyName is `transform`)\r\n if (e.target !== this._inner || this._isTransitioning || e.propertyName !== 'width') return\r\n\r\n counter++\r\n if (counter === 1) this._inner.classList.add(ClassName.INNER_HOVER)\r\n })\r\n\r\n this._inner.addEventListener('transitionend', (e) => {\r\n // skip `transitionend` on mobile (in which propertyName is `transform`)\r\n if (e.target !== this._inner || e.propertyName !== 'width') return\r\n\r\n if (this._inner.clientWidth < 140) {\r\n // just to make sure we remove the extra class name when not needed\r\n this._inner.classList.remove(ClassName.INNER_HOVER)\r\n counter = 0\r\n // blur input element\r\n if (document.activeElement.tagName === 'INPUT' && this._inner.contains(document.activeElement)) document.activeElement.blur()\r\n }\r\n })\r\n }\r\n\r\n _addTransitionEventMobile () {\r\n if (this._hasTransitionEventMobile) return\r\n this._hasTransitionEventMobile = true\r\n\r\n this._inner.addEventListener('transitionstart', (e) => {\r\n if (e.target !== this._inner || e.propertyName !== 'transform') return\r\n\r\n this._toggleMobileCompleted()\r\n })\r\n }\r\n\r\n // swipe to hide sidebar\r\n enableSwipeHide () {\r\n let x1 = 0\r\n let y1 = 0\r\n let swipeDir = 0\r\n\r\n let isRTL = false\r\n let lastX = 0\r\n\r\n let pushContent = false\r\n let sidebarWidth = 0\r\n\r\n const touchMoveCallback = (ev) => {\r\n const touches = ev.changedTouches[0] || null\r\n if (!touches) return\r\n\r\n const newX = touches.pageX\r\n const newY = touches.pageY\r\n lastX = newX\r\n\r\n if (swipeDir === 0) {\r\n const diffY = Math.abs(y1 - newY)\r\n const diffX = Math.abs(x1 - newX)\r\n\r\n if (diffY > diffX) {\r\n swipeDir = 2// vertical i.e. scroll\r\n if (this._scroller) this._scroller.classList.remove('overflow-hidden')\r\n document.body.classList.remove('mob-sidebarswipe-body')\r\n\r\n EventHandler.off(document, 'touchmove.sidebar-swipe')\r\n } else if (diffX > 10) {\r\n swipeDir = 1// horizontal swipe\r\n this._inner.setAttribute('style', 'transition: none !important; touch-action: none;')\r\n if (this._scroller) this._scroller.classList.add('overflow-hidden')\r\n document.body.classList.add('mob-sidebarswipe-body')\r\n }\r\n }\r\n if (swipeDir !== 1) return\r\n\r\n const moveX = parseInt(x1 - newX)\r\n if ((!isRTL && moveX > 0) || (isRTL && moveX < 0)) { // move it outside of view\r\n this._inner.style.transform = 'translateX(' + (-1 * moveX) + 'px)'\r\n if (pushContent) this._sidebar.style.width = (sidebarWidth - (moveX > 0 ? moveX : -1 * moveX)) + 'px'\r\n } else {\r\n this._inner.style.transform = ''\r\n if (pushContent) this._sidebar.style.width = ''\r\n }\r\n }\r\n\r\n let t1 = 0\r\n EventHandler.on(document, 'touchstart.sidebar-swipe', (e) => {\r\n const touches = e.changedTouches[0] || null\r\n if (!touches) return\r\n\r\n x1 = touches.pageX\r\n y1 = touches.pageY\r\n\r\n t1 = Date.now()\r\n isRTL = Util.isRTL()\r\n\r\n pushContent = this._sidebar.classList.contains('sidebar-push')\r\n if (pushContent) {\r\n sidebarWidth = this._sidebar.clientWidth\r\n this._sidebar.style.minWidth = 'auto'\r\n this._sidebar.style.transition = 'none'\r\n }\r\n\r\n EventHandler.on(document, 'touchmove.sidebar-swipe', (e) => {\r\n touchMoveCallback(e)\r\n })\r\n })\r\n\r\n const touchEndHandler = (e) => {\r\n const touches = e.changedTouches[0] || null\r\n // if (!touches) return // in case we're coming from a `dismiss` mouseup event\r\n\r\n this._inner.setAttribute('style', '')\r\n if (pushContent) {\r\n this._sidebar.style.width = ''\r\n this._sidebar.style.minWidth = ''\r\n this._sidebar.style.transition = ''\r\n }\r\n\r\n const x2 = touches !== null ? touches.pageX : lastX\r\n const t2 = Date.now()\r\n\r\n if (swipeDir === 1 &&\r\n ( // dismiss if moved by more than 100px or moved more than 40px in a short time (less than 300ms)\r\n (!isRTL && (x1 - x2 > 100 || (x1 - x2 > 40 && t2 - t1 < 300))) || (isRTL && (x1 - x2 < -100 || (x1 - x2 < -40 && t2 - t1 < 300)))\r\n )\r\n ) { // if moved more than 100px or 40px in less than 300ms\r\n this.hide()\r\n } else {\r\n // remove '.mob-sidebarswipe-body' to bring back body scrollbars if sidebar isn't swiped to hide\r\n // but we probably won't have body scrollbars because of `.mob-sidebar-body`\r\n document.body.classList.remove('mob-sidebarswipe-body')\r\n }\r\n\r\n // bring back sidebar scrollbars\r\n if (this._scroller) this._scroller.classList.remove('overflow-hidden')\r\n\r\n swipeDir = 0\r\n }\r\n\r\n EventHandler.on(document, 'touchend.sidebar-swipe', touchEndHandler)\r\n EventHandler.on(document, 'touchcancel.sidebar-swipe', touchEndHandler)\r\n }\r\n\r\n enableSubmenuToggle () {\r\n this._isSubOpening = false\r\n const _jQueryBS = typeof jQuery !== 'undefined' && typeof bootstrap !== 'undefined'\r\n\r\n EventHandler.on(this._sidebar, 'click', '.dropdown-toggle', (ev) => {\r\n ev.preventDefault()\r\n if (this._isSubOpening) return\r\n\r\n const navItem = Util.closest(ev.delegateTarget, '.nav-item')// get the parent LI.nav-item\r\n const subMenu = navItem.querySelector('* > .submenu')// get the direct submenu (not the children)\r\n const navLink = navItem.querySelector('* > .nav-link')// get the parent LI.nav-item\r\n\r\n if (!subMenu || !navLink) return\r\n\r\n if ((this._collapsed && this._sidebar.classList.contains('hoverable')) || this._sidebar.classList.contains('sidebar-hover')) {\r\n // don't toggle submenu if submenu is supposed to be displayed as popup (this includes horizontal sidebar when it's `.sidebar-hover`)\r\n if (window.getComputedStyle(subMenu).position === 'absolute') return\r\n }\r\n\r\n if (subMenu.classList.contains('collapsing')) return// don't toggle in the middle of toggling\r\n\r\n // hide sibling submenus\r\n navItem.classList.add('is-toggling')\r\n navItem.parentNode.querySelectorAll('* > .nav-item.open').forEach((_item) => {\r\n if (_item === navItem) return\r\n _item.classList.add('is-toggling')\r\n\r\n _item.classList.remove('open')\r\n\r\n const sub = _item.querySelector('* > .submenu.show')\r\n if (sub) {\r\n if (_jQueryBS) window.jQuery(sub).collapse('hide')\r\n else sub.classList.remove('show')\r\n }\r\n })\r\n\r\n // toggle submenu\r\n if (navItem.classList.contains('open')) {\r\n navItem.classList.remove('open')\r\n navLink.classList.add('collapsed')\r\n\r\n this._sidebar.classList.remove('has-open')\r\n\r\n if (_jQueryBS) window.jQuery(subMenu).collapse('hide')\r\n else subMenu.classList.remove('show')\r\n } else {\r\n this._isSubOpening = true\r\n\r\n navItem.classList.add('open')\r\n navLink.classList.remove('collapsed')\r\n\r\n this._sidebar.classList.add('has-open')\r\n\r\n if (_jQueryBS) window.jQuery(subMenu).collapse('show')\r\n else subMenu.classList.add('show')\r\n }\r\n\r\n if (_jQueryBS) {\r\n if (!subMenu.getAttribute('data-sub-event')) {\r\n subMenu\r\n .setAttribute('data-sub-event', 'true')\r\n\r\n window.jQuery(subMenu).on('shown.bs.collapse.is-toggling hidden.bs.collapse.is-toggling', () => {\r\n this._submenuIsToggled()\r\n })\r\n }\r\n } else {\r\n this._submenuIsToggled()\r\n }\r\n\r\n if (navItem && navItem.classList.contains('open')) this._submenuScroll(subMenu)\r\n })\r\n }\r\n\r\n _submenuIsToggled () {\r\n this._isSubOpening = false\r\n\r\n this._sidebar.querySelectorAll('.is-toggling').forEach((el) => {\r\n el.classList.remove('is-toggling')\r\n })\r\n\r\n // firefox continues to disable scroll chaining when sidebar is not scrollable anymore, so a little fix around here\r\n if ('MozAppearance' in document.documentElement.style) {\r\n if (this._scroller === null) return\r\n if (this._scroller.scrollHeight <= this._scroller.clientHeight) {\r\n this._scroller.style.overscrollBehavior = 'auto'\r\n } else this._scroller.style.overscrollBehavior = ''\r\n }\r\n }\r\n\r\n // scroll submenu into view (only on modern browsers)\r\n _submenuScroll (subMenu, delay = 150) {\r\n if (subMenu && !Util.isReducedMotion() && 'scrollBehavior' in document.documentElement.style && this._config.subscroll && this._sidebar.classList.contains('sidebar-fixed')) {\r\n if (this._sidebar.classList.contains(ClassName.HORIZONTAL)) {\r\n if (window.getComputedStyle(subMenu).position === 'absolute') return // no scroll for desktop horizontal menu (when it's not `.sidebar-hover`)\r\n }\r\n\r\n setTimeout(() => {\r\n subMenu.scrollIntoView({\r\n behavior: 'smooth',\r\n block: 'nearest'\r\n })\r\n }, delay)\r\n }\r\n }\r\n\r\n enableSubmenuPullup () {\r\n if (this._pullupEnabled) return\r\n this._pullupEnabled = true\r\n\r\n const marginProp = 'margin-' + (!Util.isRTL() ? 'left' : 'right')\r\n\r\n if (this._pullupCallback === null) {\r\n this._pullupCallback = (ev) => {\r\n if (ev.target !== ev.delegateTarget || ev.propertyName !== marginProp || !(this._collapsed || this._sidebar.classList.contains('sidebar-hover'))) return\r\n\r\n const subMenu = ev.target\r\n const navItem = subMenu.parentNode\r\n\r\n const navText = navItem.querySelector('* > .nav-link > .nav-text.fadeable')// only first level nav-text items\r\n\r\n if (navItem) navItem.classList.remove('submenu-pullup')\r\n subMenu.style.transform = ''\r\n if (navText) navText.style.transform = ''\r\n\r\n /// ///////////////////////\r\n\r\n const rect = subMenu.getBoundingClientRect()\r\n const wh = window.innerHeight\r\n\r\n let diff = parseInt(rect.bottom - wh)\r\n\r\n if (diff > 0) { // if submenu bottom is below window area\r\n // check to see if submenu top will go out of window if we move it up by \"diff\" pixels\r\n // also consider that the first level item's .nav-text shouldn't go out of window's top\r\n const navTextHeight = navText ? navText.clientHeight : 0\r\n let navbarHeight = document.querySelector('.navbar')\r\n navbarHeight = navbarHeight ? navbarHeight.clientHeight : 0\r\n\r\n const diff2 = rect.top - navTextHeight - diff - navbarHeight// don't go above navbar\r\n if (diff2 < 0) diff = diff + diff2\r\n\r\n diff = parseInt(diff) + 1// so that submenu's border is visible\r\n if (this._collapsed) {\r\n if (navTextHeight && diff > navTextHeight / 2 && navItem) navItem.classList.add('submenu-pullup')// this class makes the .sub-arrow's color white, to match submenu color\r\n } else {\r\n if (navItem) navItem.classList.add('submenu-pullup')\r\n }\r\n\r\n subMenu.style.transform = `translateY(-${diff}px)`\r\n if (this._collapsed && navText) {\r\n navText.style.transform = `translateY(-${diff}px)`\r\n }\r\n }\r\n }\r\n }\r\n\r\n EventHandler.on(this._sidebar, 'transitionstart', '.submenu', this._pullupCallback)\r\n }\r\n\r\n disableSubmenuPullup () {\r\n this._pullupEnabled = false\r\n if (this._pullupCallback) EventHandler.off(this._sidebar, 'transitionstart', '.submenu', this._pullupCallback)\r\n this._resetPullUp()\r\n }\r\n\r\n _resetPullUp () {\r\n this._sidebar.querySelectorAll('.submenu-pullup').forEach((_item) => {\r\n _item.classList.remove('submenu-pullup')\r\n _item.querySelectorAll('.nav-text, .submenu').forEach((el) => {\r\n el.style.transform = ''\r\n })\r\n })\r\n }\r\n\r\n // scroll active item into view\r\n scrollToActive () {\r\n if (!this._sidebar.classList.contains('sidebar-fixed') || this._scroller === null) return\r\n\r\n const active = this._sidebar.querySelector('.nav-item.active:not(.open) > .nav-link')\r\n try {\r\n active.scrollIntoView({ behavior: 'auto', block: 'end' })// or block: \"center\"?\r\n this._scroller.scrollTop = this._scroller.scrollTop + 30\r\n } catch (e) {}\r\n }\r\n\r\n //\r\n _getConfig (config) {\r\n config = {\r\n ...Default,\r\n ...typeof config === 'object' && config ? config : {}\r\n }\r\n\r\n if (typeof window.bootstrap !== 'undefined') {\r\n window.bootstrap.Util.typeCheckConfig(\r\n NAME,\r\n config,\r\n this.constructor.DefaultType\r\n )\r\n }\r\n\r\n return config\r\n }\r\n\r\n // Static methods\r\n static getInstance (element, config = null) {\r\n if (!element) throw new Error('element for Sidebar is null')\r\n\r\n const name = `__${NAME}__`\r\n if (typeof element[name] !== 'undefined') return element[name]\r\n\r\n element[name] = new Sidebar(element, config)\r\n return element[name]\r\n }\r\n\r\n static _jQueryInterface (config) {\r\n return this.each(function () {\r\n const $this = window.jQuery(this)\r\n let data = $this.data(DATA_KEY)\r\n\r\n const _config = {\r\n ...Default,\r\n ...$this.data(),\r\n ...typeof config === 'object' && config ? config : {}\r\n }\r\n\r\n if (!data) {\r\n data = Sidebar.getInstance(this, _config)\r\n $this.data(DATA_KEY, data)\r\n }\r\n\r\n if (typeof config === 'string') {\r\n if (typeof data[config] === 'undefined') {\r\n throw new TypeError(`No method named \"${config}\"`)\r\n }\r\n data[config]()\r\n }\r\n })\r\n }\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * jQuery\r\n * ------------------------------------------------------------------------\r\n*/\r\n\r\nif (typeof window.jQuery !== 'undefined') {\r\n const $ = window.jQuery\r\n $(window).on(Event.LOAD_DATA_API, () => {\r\n const sidebars = [].slice.call(document.querySelectorAll(Selector.SIDEBAR))\r\n\r\n for (let i = 0; i < sidebars.length; i++) {\r\n const $sidebar = $(sidebars[i])\r\n Sidebar._jQueryInterface.call($sidebar, $sidebar.data())\r\n }\r\n })\r\n\r\n const JQUERY_NO_CONFLICT = $.fn[NAME]\r\n $.fn[NAME] = Sidebar._jQueryInterface\r\n $.fn[NAME].Constructor = Sidebar\r\n $.fn[NAME].noConflict = () => {\r\n $.fn[NAME] = JQUERY_NO_CONFLICT\r\n return Sidebar._jQueryInterface\r\n }\r\n}\r\n\r\nexport default Sidebar\r\n","/**\r\n * --------------------------------------------------------------------------\r\n * Ace (v4.0.0): aside.js\r\n Aside element based on Bootstrap's modal\r\n*/\r\n\r\nimport Util from './util'\r\nimport EventHandler from './event-handler'\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Constants\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nconst NAME = 'aceAside'\r\nconst VERSION = '4.0.0'\r\nconst DATA_KEY = 'ace.aside'\r\nconst EVENT_KEY = `.${DATA_KEY}`\r\n\r\nconst Event = {\r\n SHOW: `show${EVENT_KEY}`,\r\n HIDE: `hide${EVENT_KEY}`\r\n}\r\n\r\nconst DefaultType = {\r\n placement: 'string',\r\n // margin: 'number',\r\n\r\n fade: 'boolean',\r\n\r\n autohide: '(boolean|number)',\r\n dismiss: 'boolean',\r\n\r\n blocking: 'boolean',\r\n backdrop: '(boolean|string)',\r\n\r\n container: 'boolean',\r\n belowNav: 'boolean',\r\n aboveNav: 'boolean',\r\n\r\n width: '(boolean|number)',\r\n height: '(boolean|number)',\r\n\r\n scroll: '(boolean|string)'\r\n}\r\n\r\nconst Default = {\r\n placement: 'center',\r\n // margin: 0,\r\n\r\n fade: false,\r\n\r\n autohide: false,\r\n dismiss: false,\r\n\r\n blocking: false,\r\n backdrop: false,\r\n\r\n container: false,\r\n belowNav: false,\r\n aboveNav: false,\r\n\r\n width: false,\r\n height: false,\r\n\r\n scroll: 'body'\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Class Definition\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nclass Aside {\r\n constructor (element, config) {\r\n this._config = this._getConfig(config)\r\n this.element = element\r\n\r\n this._jQueryBS = typeof window.jQuery !== 'undefined' && typeof window.jQuery.fn.modal !== 'undefined'\r\n\r\n this._init(this._config)\r\n }\r\n\r\n static get VERSION () {\r\n return VERSION\r\n }\r\n\r\n static get DefaultType () {\r\n return DefaultType\r\n }\r\n\r\n static get Default () {\r\n return Default\r\n }\r\n\r\n _init (config) {\r\n const $ = this._jQueryBS ? window.jQuery : null\r\n\r\n this._setPlacement(config.placement)\r\n\r\n this.element.classList.add('ace-aside')\r\n\r\n if (!config.blocking) {\r\n this.element.classList.add('modal-nb')\r\n this.element.setAttribute('data-backdrop', 'false')\r\n if ($) {\r\n $(this.element).data('backdrop', false)\r\n }\r\n } else {\r\n if (config.backdrop) {\r\n this.element.setAttribute('data-backdrop-bg', config.backdrop)\r\n }\r\n this.element.setAttribute('data-backdrop', 'true')\r\n if ($) {\r\n $(this.element).data('backdrop', true)\r\n }\r\n }\r\n\r\n if (config.dismiss) this.element.classList.add('modal-dismiss')\r\n\r\n if (config.fade) {\r\n this.element.classList.add('aside-fade')\r\n this.element.classList.add('fade')\r\n }\r\n\r\n if (config.belowNav) this.element.classList.add('aside-below-nav')\r\n if (config.aboveNav) this.element.classList.add('aside-above-nav')\r\n\r\n if (config.extraClass) this.element.className += ` ${config.extraClass}`\r\n\r\n if (config.container) {\r\n this.element.classList.add('container')\r\n const bdc = document.querySelector('.body-container')\r\n if (bdc !== null && bdc.classList.contains('container-plus')) {\r\n this.element.classList.add('container-plus')\r\n }\r\n }\r\n\r\n if (config.width) {\r\n const dialog = this.element.querySelector('.modal-dialog')\r\n if (dialog) {\r\n dialog.style.width = isNaN(config.width) ? config.width : this._config.width + 'px'\r\n }\r\n }\r\n\r\n if (config.height) {\r\n const dialog = this.element.querySelector('.modal-dialog')\r\n if (dialog) {\r\n dialog.style.height = isNaN(config.height) ? config.height : this._config.height + 'px'\r\n }\r\n }\r\n\r\n // if (/^(content|body)$/.test(config.scroll)) {\r\n // let content = this.element.querySelector('.modal-content')\r\n // if (content) content.classList.add('scroll-' + config.scroll)\r\n // }\r\n\r\n if (!$) return\r\n\r\n $(this.element).off('shown.bs.modal.autohide')\r\n if (config.autohide) {\r\n $(this.element).on('shown.bs.modal.autohide', () => {\r\n setTimeout(() => {\r\n this.hide()\r\n }, config.autohide)\r\n })\r\n }\r\n }\r\n\r\n _setPlacement (placement = 'center') {\r\n const placementMap = {\r\n t: 'aside-top',\r\n top: 'aside-top',\r\n tc: 'aside-top aside-c',\r\n tr: 'aside-top aside-r',\r\n tl: 'aside-top aside-l',\r\n\r\n b: 'aside-bottom',\r\n bottom: 'aside-bottom',\r\n bc: 'aside-bottom aside-c',\r\n br: 'aside-bottom aside-r',\r\n bl: 'aside-bottom aside-l',\r\n\r\n r: 'aside-right',\r\n right: 'aside-right',\r\n rc: 'aside-right aside-m',\r\n\r\n l: 'aside-left',\r\n left: 'aside-left',\r\n lc: 'aside-left aside-m',\r\n\r\n c: 'aside-center',\r\n center: 'aside-center'\r\n }\r\n\r\n placement = placement || 'c'\r\n const className = placementMap[placement] || 'aside-center'\r\n if (placement === 'c' || placement === 'center') {\r\n this._config.fade = true\r\n this.element.classList.remove('container')\r\n }\r\n\r\n this.element.className = this.element.className + ' ' + className\r\n }\r\n\r\n // Public methods\r\n show () {\r\n const event = EventHandler.trigger(this.element, Event.SHOW)\r\n if (event.defaultPrevented) {\r\n return\r\n }\r\n\r\n if (this._jQueryBS) {\r\n window.jQuery(this.element).modal('show')\r\n }\r\n }\r\n\r\n hide () {\r\n const event = EventHandler.trigger(this.element, Event.HIDE)\r\n if (event.defaultPrevented) {\r\n return\r\n }\r\n\r\n if (this._jQueryBS) {\r\n window.jQuery(this.element).modal('hide')\r\n }\r\n }\r\n\r\n // Private methods\r\n _getConfig (config) {\r\n config = {\r\n ...Default,\r\n ...typeof config === 'object' && config ? config : {}\r\n }\r\n\r\n if (this._jQueryBS) {\r\n window.bootstrap.Util.typeCheckConfig(\r\n NAME,\r\n config,\r\n this.constructor.DefaultType\r\n )\r\n }\r\n\r\n return config\r\n }\r\n\r\n // Static methods\r\n static getInstance (element, config = null) {\r\n if (!element) throw new Error('element for Aside is null')\r\n\r\n const name = `__${NAME}__`\r\n if (typeof element[name] !== 'undefined') return element[name]\r\n\r\n element[name] = new Aside(element, config)\r\n return element[name]\r\n }\r\n\r\n static _jQueryInterface (config) {\r\n return this.each(function () {\r\n const $this = window.jQuery(this)\r\n let data = $this.data(DATA_KEY)\r\n\r\n const _config = {\r\n ...Default,\r\n ...$this.data(),\r\n ...typeof config === 'object' && config ? config : {}\r\n }\r\n\r\n if (!data) {\r\n data = Aside.getInstance(this, _config)\r\n $this.data(DATA_KEY, data)\r\n }\r\n\r\n if (typeof config === 'string') {\r\n if (typeof data[config] === 'undefined') {\r\n throw new TypeError(`No method named \"${config}\"`)\r\n }\r\n data[config]()\r\n }\r\n })\r\n }\r\n\r\n /// ///////////////////////\r\n /// ///////////////////////\r\n /// ///////////////////////////\r\n static _HandleAside () {\r\n const _jQueryBS = typeof window.jQuery !== 'undefined' && typeof window.jQuery.fn.modal !== 'undefined'\r\n if (!_jQueryBS) return\r\n const $ = window.jQuery\r\n\r\n const visibleModalSelector = '.modal.show:not(.modal-nb)'\r\n\r\n document.querySelectorAll('.ace-aside.modal-nb').forEach((el) => el.setAttribute('data-backdrop', 'false'))\r\n\r\n $('.ace-aside.modal-nb').data('backdrop', false)\r\n\r\n const onBeforeShow = (modal) => {\r\n if (modal.classList.contains('modal-nb')) {\r\n if (document.querySelector(visibleModalSelector) === null) { // if there are no normal modals open\r\n document.body.classList.add('modal-nb')// disable .modal-open effects for .modal-nb\r\n }\r\n } else {\r\n if (!modal.classList.contains('ace-aside')) {\r\n // check to see if we will have modal scrollbars\r\n modal.style.display = 'block'\r\n if (modal.scrollHeight > modal.clientHeight) document.body.classList.add('modal-scroll')\r\n const scrollbars = Util.getScrollbarInfo()\r\n if (scrollbars.width === 0) document.body.classList.add('scrollbar-w0')\r\n modal.style.display = ''\r\n }\r\n\r\n // set modal padding value (equal to scrollbar width)\r\n document.body.style.setProperty('--modal-padding', (window.innerWidth - document.body.scrollWidth) + 'px')\r\n\r\n const isModalOff = modal.className.match(/modal-off(?:(?:-([a-z]+))|\\s|$)/i)\r\n\r\n const backdropBg = modal.getAttribute('data-backdrop-bg')\r\n if (backdropBg || isModalOff) {\r\n setTimeout(function () {\r\n const backdrops = document.querySelectorAll('.modal-backdrop')\r\n if (backdrops.length > 0) {\r\n const backdrop = backdrops[backdrops.length - 1]\r\n if (backdropBg) backdrop.classList.add(backdropBg)\r\n\r\n // add d-{sm|md|lg|xl}-none to backdrop\r\n if (isModalOff) {\r\n const modalOff = (isModalOff[1] && isModalOff[1].length > 0) ? `-${isModalOff[1]}` : ''\r\n backdrop.classList.add(`d${modalOff}-none`)\r\n }\r\n }\r\n }, 0)\r\n }\r\n\r\n const blur = modal.getAttribute('data-blur')\r\n if (blur !== null && window.CSS) {\r\n /**\r\n // using `backdrop-filter` is less intrusive but doesn't have the same blur effect\r\n if (window.CSS.supports(\"backdrop-filter\", \"none\")) {\r\n setTimeout(function () {\r\n $('.modal-backdrop:last-child').addClass('modal-blur')\r\n }, 0)\r\n }\r\n else */\r\n if (window.CSS.supports('filter', 'none')) {\r\n const bodyContainer = document.querySelector('.body-container')\r\n if (bodyContainer !== null) {\r\n document.body.classList.add('modal-blur')\r\n bodyContainer.style.filter = 'blur(' + blur + ')'\r\n\r\n const modalParent = modal.parentNode\r\n const modalSibling = modal.nextSibling\r\n\r\n document.body.appendChild(modal)\r\n\r\n $(modal).one('hidden.bs.modal.blur', () => {\r\n modalParent.insertBefore(modal, modalSibling)\r\n document.body.classList.remove('modal-blur')\r\n bodyContainer.style.filter = ''\r\n })\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n /// /////////////////////////////\r\n const onAfterShow = (modal) => {\r\n if (modal.classList.contains('modal-nb')) {\r\n document.body.classList.remove('modal-nb')\r\n\r\n if (document.querySelector(visibleModalSelector) === null) { // if no blocking modals\r\n document.body.classList.remove('modal-open')// disable .modal-open effects\r\n document.body.style.paddingRight = ''// and remove paddingRight\r\n }\r\n\r\n if (modal.classList.contains('modal-dismiss') || modal.getAttribute('data-dismiss') === 'true') {\r\n modal._dismissAsideEvent = ($event) => {\r\n if (!modal.contains($event.target)) { // clicked outside modal\r\n // why timeout?\r\n // because if we click on the same button that triggers this modal, its 'hide' function will be called and instantly followed by 'show' function\r\n // so we first let 'show' be called and then we call 'hide'\r\n document.removeEventListener('mouseup', modal._dismissAsideEvent)\r\n modal._dismissAsideEvent = null\r\n\r\n setTimeout(() => {\r\n $(modal).modal('hide')\r\n }, 0)\r\n }\r\n }\r\n // why `mouseup`? because 'click' may get 'stopPropagated' in some plugins such as Bootstrap's dropdown\r\n document.addEventListener('mouseup', modal._dismissAsideEvent)\r\n }\r\n }\r\n }\r\n\r\n const onAfterHide = (modal) => {\r\n if (document.querySelector(visibleModalSelector) === null) document.body.style.paddingRight = ''// required for rare cases that body padding is still not cleared\r\n else document.body.classList.add('modal-open') // sometimes an aside is closed (so .modal-open is removed) but a .modal is still open (so we add .modal-open again)\r\n\r\n if (!modal.classList.contains('modal-nb')) {\r\n document.body.classList.remove('modal-scroll')\r\n document.body.classList.remove('scrollbar-w0')\r\n }\r\n\r\n if (typeof modal._dismissAsideEvent === 'function') {\r\n document.removeEventListener('mouseup', modal._dismissAsideEvent)\r\n }\r\n }\r\n\r\n /// //////////////////////////////////////\r\n $(document)\r\n .on('show.bs.modal', '.modal', (e) => {\r\n if (e.defaultPrevented || e.isDefaultPrevented()) return\r\n onBeforeShow(e.target)\r\n })\r\n .on('shown.bs.modal', '.modal', function (e) {\r\n onAfterShow(e.target)\r\n })\r\n .on('hidden.bs.modal', '.modal', function (e) {\r\n onAfterHide(e.target)\r\n })\r\n\r\n // enable modal functionality for modal boxes and asides that are shown (.show) by default\r\n $('.modal.show').modal('show')\r\n }// _HandleAside\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * jQuery\r\n * ------------------------------------------------------------------------\r\n*/\r\n\r\nif (typeof jQuery !== 'undefined') {\r\n const $ = window.jQuery\r\n Aside._HandleAside()\r\n\r\n const JQUERY_NO_CONFLICT = $.fn[NAME]\r\n $.fn[NAME] = Aside._jQueryInterface\r\n $.fn[NAME].Constructor = Aside\r\n $.fn[NAME].noConflict = () => {\r\n $.fn[NAME] = JQUERY_NO_CONFLICT\r\n return Aside._jQueryInterface\r\n }\r\n}\r\n\r\nexport default Aside\r\n","/**\r\n * --------------------------------------------------------------------------\r\n * Ace (v4.0.0): toaster.js\r\n Wrapper for Bootstrap's toast elements\r\n*/\r\n\r\nimport Util from './util'\r\nimport EventHandler from './event-handler'\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Constants\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nconst NAME = 'aceToaster'\r\nconst VERSION = '4.0.0'\r\nconst DATA_KEY = 'ace.toaster'\r\nconst EVENT_KEY = `.${DATA_KEY}`\r\n\r\nconst Event = {\r\n CLEAR: `clear${EVENT_KEY}`,\r\n ADD: `add${EVENT_KEY}`,\r\n ADDED: `added${EVENT_KEY}`\r\n}\r\n\r\nconst DefaultType = {\r\n placement: 'string',\r\n close: 'boolean',\r\n autoremove: 'boolean',\r\n delay: 'number',\r\n template: 'string',\r\n alert: 'boolean'\r\n}\r\n\r\nconst Default = {\r\n placement: 'tr',\r\n close: true,\r\n autoremove: true,\r\n delay: 2500,\r\n template: '
',\r\n alert: true\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Class Definition\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nclass Toaster {\r\n constructor () {\r\n this._lastToastId = 0\r\n this.element = null\r\n\r\n this._jQueryBS = typeof window.jQuery !== 'undefined' && typeof window.bootstrap !== 'undefined'\r\n this._tempParent = document.createElement('DIV')\r\n }\r\n\r\n static get VERSION () {\r\n return VERSION\r\n }\r\n\r\n static get DefaultType () {\r\n return DefaultType\r\n }\r\n\r\n static get Default () {\r\n return Default\r\n }\r\n\r\n // Public methods\r\n add (config) {\r\n const _config = this._getConfig(config)\r\n\r\n const newToast = Util.append(this._tempParent, _config.template)\r\n\r\n this._lastToastId++\r\n newToast.classList.add('ace-toaster-item')\r\n newToast.id = `ace-toaster-item-${this._lastToastId}`\r\n newToast.setAttribute('aria-atomic', 'true')\r\n\r\n if (_config.alert) {\r\n newToast.setAttribute('role', 'alert')\r\n newToast.setAttribute('aria-live', 'assertive')\r\n } else {\r\n newToast.setAttribute('role', 'status')\r\n newToast.setAttribute('aria-live', 'polite')\r\n }\r\n\r\n const toastHeader = newToast.querySelector('.toast-header')\r\n if (_config.title && toastHeader) {\r\n const title = typeof _config.title === 'function' ? _config.title.call(this.element, _config) : _config.title\r\n\r\n Util.append(toastHeader, `
${title}
`)\r\n }\r\n\r\n if (_config.close) {\r\n let close = newToast.querySelector('[data-dismiss=\"toast\"]')\r\n if (close === null) {\r\n close = Util.append(toastHeader, '')\r\n }\r\n\r\n close.className += ` ${_config.closeClass || 'close'}`\r\n }\r\n\r\n if (_config.body) {\r\n const body = newToast.querySelector('.toast-body')\r\n if (body !== null) {\r\n Util.append(body, typeof _config.body === 'function' ? _config.body.call(this.element, _config) : _config.body)\r\n if (_config.bodyClass) body.className += ` ${_config.bodyClass}`\r\n }\r\n }\r\n\r\n if (_config.image) {\r\n const image = newToast.querySelector('.toast-image')\r\n if (image !== null) {\r\n Util.append(image, ``)\r\n }\r\n }\r\n\r\n if (_config.icon) {\r\n const image = newToast.querySelector('.toast-image')\r\n if (image !== null) {\r\n const icon = Util.append(image, _config.icon)\r\n if (!_config.image && _config.imageClass) {\r\n icon.className += ` ${_config.imageClass}`\r\n }\r\n }\r\n }\r\n\r\n if (!(_config.image || _config.icon)) newToast.querySelectorAll('.toast-image').forEach((el) => Util.remove(el))\r\n\r\n if (_config.className) {\r\n newToast.className += ` ${_config.className}`\r\n }\r\n if (_config.headerClass && toastHeader) {\r\n toastHeader.className += ` ${_config.headerClass}`\r\n }\r\n\r\n // if delay is below 30, we consider it as seconds, not milliseconds\r\n _config.delay = _config.delay > 30 ? _config.delay : _config.delay * 1000\r\n\r\n if (_config.progress && !_config.sticky && _config.autohide !== false) {\r\n const progress = Util.append(newToast, `
`)\r\n progress.style.transitionDuration = `${parseInt(_config.delay * 1.015)}ms`\r\n progress.style.width = _config.progressReverse ? 'calc(100% - 1px)' : 0\r\n // progress.offsetWidth\r\n setTimeout(() => {\r\n progress.style.width = _config.progressReverse ? 0 : 'calc(100% - 2px)'\r\n }, 0)\r\n }\r\n\r\n return this._addToContainer(newToast, _config)\r\n }\r\n\r\n // add an existing toast element to our container\r\n addEl (element, config) {\r\n const _config = this._getConfig(config)\r\n\r\n this.element = element\r\n this.element.classList.add('ace-toaster-item')\r\n if (!this.element.getAttribute('id')) this.element.setAttribute('id', `ace-toaster-item-${++this._lastToastId}`)\r\n\r\n this._addToContainer(this.element, _config, false)\r\n }\r\n\r\n // add toast element to container\r\n _addToContainer (toast, _config, isNewElement = true) {\r\n // trigger ADD event before adding it to our container\r\n\r\n const addEvent = EventHandler.trigger(document, Event.ADD, { target: toast })\r\n if (addEvent.defaultPrevented) {\r\n if (isNewElement) Util.remove(toast)\r\n return null\r\n }\r\n // end of trigger\r\n\r\n // add the toaster container to body\r\n let container = document.querySelector(`.ace-toaster-container.position-${_config.placement}`)\r\n if (container === null) {\r\n container = Util.append(document.body, `
`)\r\n }\r\n if (_config.belowNav) {\r\n container.classList.add('toaster-below-nav')\r\n }\r\n\r\n // this last container should appear above other ones ?\r\n // let topContainer = document.querySelector('.ace-toaster-container-on-top')\r\n // if (topContainer !== null) topContainer.classList.remove('ace-toaster-container-on-top')\r\n // container.classList.add('ace-toaster-container-on-top')\r\n\r\n // add to container\r\n Util.append(container, toast)\r\n Util.wrap(toast, '
')\r\n\r\n // without having an initial .toast element, fade-in animation isn't taking place??!!\r\n let dummy = document.getElementById('ace-toaster-dummy-toast-1')\r\n if (dummy === null) dummy = Util.append(document.body, '
')\r\n if (this._jQueryBS) {\r\n window.jQuery(dummy).toast('show')\r\n }\r\n /// ///////////////////////////////////////////////\r\n\r\n const _toastOptions = {}\r\n if (_config.sticky === true || _config.autohide === false) _toastOptions.autohide = false\r\n if (_config.animation === false) _toastOptions.animation = false\r\n _toastOptions.delay = _config.delay\r\n\r\n if (_config.width) toast.style.width = isNaN(_config.width) ? _config.width : _config.width + 'px'\r\n\r\n if (this._jQueryBS) {\r\n window.jQuery(toast)\r\n .toast(_toastOptions)\r\n .toast('show')\r\n .one('hidden.bs.toast.1', function () {\r\n // show it again (invisibly with opacity = 0) and use bootstrap Collapse plugin to hide it, so that other toasts stacked below it move up smoothly\r\n const $toast = window.jQuery(toast)\r\n $toast.removeClass('hide').parent().addClass('show').collapse('hide').one('hidden.bs.collapse', function () {\r\n $toast.toast('dispose')\r\n $toast.parent().collapse('dispose')\r\n\r\n if (_config.autoremove) {\r\n $toast.parent().remove()\r\n } else {\r\n if (!isNewElement) {\r\n $toast.unwrap() // remove the wrapper\r\n }\r\n }\r\n })\r\n })\r\n }\r\n\r\n // trigger ADDED event before adding it to DOM\r\n EventHandler.trigger(document, Event.ADDED, { target: toast })\r\n\r\n return toast\r\n }\r\n\r\n // hide toasts\r\n remove (id, instant = false) {\r\n this.hide(id, true, instant)\r\n }\r\n\r\n removeAll (placement = null, instant = false) {\r\n this.hideAll(placement, true, instant)\r\n }\r\n\r\n // remove toast by ID or element reference\r\n hide (id, remove = false, instant = false) {\r\n const selector = isNaN(id) ? id : '#ace-toaster-item-' + parseInt(id)\r\n this._hideBySelector(selector, remove, instant)\r\n }\r\n\r\n // remove ALL toasts\r\n hideAll (placement = null, remove = false, instant = false) {\r\n // trigger CLEAR event before removing ALL\r\n const clearEvent = EventHandler.trigger(document, Event.CLEAR, { detail: { placement: placement || 'all', remove: remove } })\r\n if (clearEvent.defaultPrevented) {\r\n return\r\n }\r\n // end of trigger\r\n\r\n let selector = '.toast.ace-toaster-item'\r\n if (placement) selector = `.ace-toaster-container.position-${placement} ${selector}`\r\n this._hideBySelector(selector, remove, instant)\r\n }\r\n\r\n _hideBySelector (selector, remove = false, instant = false) {\r\n if (!this._jQueryBS) return\r\n\r\n window.jQuery(selector).each(function () {\r\n const $toast = window.jQuery(this)\r\n if (!instant && $toast.is(':visible')) {\r\n // fade out and then remove\r\n $toast.toast('hide')\r\n .off('hidden.bs.toast.1')// remove the previous handler above (because it has autoremove)\r\n .one('hidden.bs.toast.2', function () {\r\n $toast.toast('dispose')\r\n if (remove) $toast.remove()\r\n })\r\n } else {\r\n $toast.toast('dispose')\r\n // instantly remove if not visible\r\n if (remove) $toast.remove()\r\n }\r\n })\r\n }\r\n\r\n // Private methods\r\n _getConfig (config) {\r\n config = {\r\n ...Default,\r\n ...typeof config === 'object' && config ? config : {}\r\n }\r\n\r\n if (typeof window.bootstrap !== 'undefined') {\r\n window.bootstrap.Util.typeCheckConfig(\r\n NAME,\r\n config,\r\n this.constructor.DefaultType\r\n )\r\n }\r\n\r\n return config\r\n }\r\n\r\n // Static methods\r\n static _jQueryInterface (config) {\r\n return this.each(function () {\r\n config = {\r\n ...{ autoremove: false }, // don't autoremove it\r\n ...window.jQuery(this).data(),\r\n ...typeof config === 'object' && config ? config : {}\r\n }\r\n\r\n window.jQuery[NAME].addEl(this, config)\r\n // jQuery[NAME] is an instance of Toaster\r\n })\r\n }\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * jQuery\r\n * ------------------------------------------------------------------------\r\n*/\r\n\r\nif (typeof window.jQuery !== 'undefined') {\r\n const $ = window.jQuery\r\n\r\n $[NAME] = new Toaster()\r\n const JQUERY_NO_CONFLICT = $.fn[NAME]\r\n $.fn[NAME] = Toaster._jQueryInterface\r\n $.fn[NAME].Constructor = Toaster\r\n $.fn[NAME].noConflict = () => {\r\n $.fn[NAME] = JQUERY_NO_CONFLICT\r\n return Toaster._jQueryInterface\r\n }\r\n}\r\n\r\nexport default Toaster\r\n","/**\r\n * --------------------------------------------------------------------------\r\n * Ace (v4.0.0): card.js\r\n Cards based on Bootstrap's cards\r\n*/\r\n\r\nimport Util from './util'\r\nimport EventHandler from './event-handler'\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Constants\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nconst NAME = 'aceCard'\r\nconst VERSION = '4.0.0'\r\nconst DATA_KEY = 'ace.card'\r\nconst EVENT_KEY = `.${DATA_KEY}`\r\nconst DATA_API_KEY = '.data-api'\r\n\r\nconst Event = {\r\n SHOW: `show${EVENT_KEY}`,\r\n HIDE: `hide${EVENT_KEY}`,\r\n SHOWN: `shown${EVENT_KEY}`,\r\n HIDDEN: `hidden${EVENT_KEY}`,\r\n CLOSE: `close${EVENT_KEY}`,\r\n CLOSED: `closed${EVENT_KEY}`,\r\n EXPAND: `expand${EVENT_KEY}`,\r\n EXPANDED: `expanded${EVENT_KEY}`,\r\n RESTORE: `restore${EVENT_KEY}`,\r\n RESTORED: `restored${EVENT_KEY}`,\r\n RELOAD: `reload${EVENT_KEY}`,\r\n RELOADED: `reloaded${EVENT_KEY}`,\r\n CLICK_DATA_API: `click${EVENT_KEY}${DATA_API_KEY}`\r\n}\r\n\r\nconst Selector = {\r\n DATA_ACTION: '.card [data-action]'\r\n}\r\n\r\nconst DefaultType = {\r\n toggle: 'boolean'\r\n}\r\n\r\nconst Default = {\r\n toggle: true\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Class Definition\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nclass Card {\r\n constructor (element, config) {\r\n this._config = this._getConfig(config)\r\n\r\n this.element = element\r\n Util.reflow(this.element) // force reflow, so that if we instantly call 'close' etc, transition effect takes place\r\n\r\n this.isTransitioning = false\r\n\r\n this.loader = null\r\n this._jQueryBS = typeof window.jQuery !== 'undefined' && typeof window.jQuery.fn.collapse !== 'undefined'\r\n }\r\n\r\n static get VERSION () {\r\n return VERSION\r\n }\r\n\r\n static get DefaultType () {\r\n return DefaultType\r\n }\r\n\r\n static get Default () {\r\n return Default\r\n }\r\n\r\n reload () {\r\n const ev = EventHandler.trigger(this.element, Event.RELOAD)\r\n if (ev.defaultPrevented) return\r\n\r\n this.startLoading()\r\n }\r\n\r\n startLoading (loadingHtml = '') {\r\n this.loader = Util.append(this.element, `
${loadingHtml}
`)\r\n }\r\n\r\n stopLoading () {\r\n if (this.loader === null) return\r\n Util.remove(this.loader)\r\n this.loader = null\r\n\r\n EventHandler.trigger(this.element, Event.RELOADED)\r\n }\r\n\r\n closeFast () {\r\n const ev = EventHandler.trigger(this.element, Event.CLOSE)\r\n if (ev.defaultPrevented) return\r\n\r\n Util.remove(this.element)\r\n EventHandler.trigger(this.element, Event.CLOSED)\r\n }\r\n\r\n close () {\r\n const ev = EventHandler.trigger(this.element, Event.CLOSE)\r\n if (ev.defaultPrevented || this.isTransitioning) return\r\n\r\n this.isTransitioning = true\r\n if (this.isFullscreen()) Util.remove(Util.next(this.element, '.card-expanded-placeholder'))// remove the placeholder\r\n\r\n const _closeComplete = () => {\r\n this.isTransitioning = false\r\n Util.remove(this.element)\r\n EventHandler.trigger(this.element, Event.CLOSED)\r\n }\r\n\r\n if (Util.isReducedMotion()) _closeComplete()\r\n else {\r\n this.element.classList.add('fade')\r\n\r\n this.element.addEventListener('transitionend', (e) => {\r\n if (e.target !== this.element) return// because transitionend might fire for children elements (like animated toolbar buttons)\r\n _closeComplete()\r\n })\r\n }\r\n }\r\n\r\n toggle (type) {\r\n if (!this._config.toggle) return\r\n\r\n const body = this.element.querySelector('.card-body')\r\n if (body === null) return\r\n\r\n const action = (type && typeof type === 'string' && type.match(/show|hide/)[0]) || (body.offsetParent !== null ? 'hide' : 'show')\r\n\r\n const eventName = action === 'hide' ? 'hide' : 'show'\r\n const ev = EventHandler.trigger(this.element, eventName + EVENT_KEY)\r\n if (ev.defaultPrevented || this.isTransitioning) return\r\n\r\n this.isTransitioning = true\r\n\r\n this._toggleIcon(type && typeof type === 'object' && type instanceof window.HTMLElement ? type : null, action)\r\n\r\n ///\r\n\r\n const eventCompleteName = action === 'hide' ? 'hidden' : 'shown'\r\n\r\n if (this._jQueryBS) {\r\n if (action === 'hide') body.classList.add('show')// .show class required for bs collapse plugin\r\n\r\n window.jQuery(body).collapse(action).one(eventCompleteName + '.bs.collapse', () => {\r\n this.isTransitioning = false\r\n EventHandler.trigger(this.element, eventCompleteName + EVENT_KEY)\r\n })\r\n } else {\r\n if (action === 'hide') body.classList.remove('show')\r\n else body.classList.add('show')\r\n this.isTransitioning = false\r\n EventHandler.trigger(this.element, eventCompleteName + EVENT_KEY)\r\n }\r\n }\r\n\r\n hide () {\r\n this.toggle('hide')\r\n }\r\n\r\n show () {\r\n this.toggle('show')\r\n }\r\n\r\n toggleFast (type) {\r\n if (!this._config.toggle) return\r\n\r\n const body = this.element.querySelector('.card-body')\r\n if (body === null) return\r\n\r\n const action = (type && typeof type === 'string' && type.match(/show|hide/)[0]) || (body.offsetParent !== null ? 'hide' : 'show')\r\n\r\n const eventName = action === 'hide' ? 'hide' : 'show'\r\n const ev = EventHandler.trigger(this.element, eventName + EVENT_KEY)\r\n if (ev.defaultPrevented) return\r\n\r\n body.classList.add('collapse')\r\n if (action === 'hide') body.classList.remove('show')\r\n else body.classList.add('show')\r\n\r\n this._toggleIcon(type && typeof type === 'object' && type instanceof window.HTMLElement ? type : null, action)\r\n\r\n const eventCompleteName = action === 'hide' ? 'hidden' : 'shown'\r\n EventHandler.trigger(this.element, eventCompleteName + EVENT_KEY)\r\n }\r\n\r\n hideFast () {\r\n this.toggleFast('hide')\r\n }\r\n\r\n showFast () {\r\n this.toggleFast('show')\r\n }\r\n\r\n _toggleIcon (button, action) {\r\n if (!button) {\r\n button = this.element.querySelector('a[data-action=toggle]')\r\n }\r\n\r\n //\r\n if (button) {\r\n if (action === 'show') {\r\n button.classList.remove('collapsed')\r\n } else {\r\n button.classList.add('collapsed')\r\n }\r\n }\r\n }\r\n\r\n // fullscreen\r\n expand (expand, animate) {\r\n const button = this.element.querySelector('* > .card-header [data-action=expand]')\r\n\r\n const _fullscreen = this.isFullscreen()\r\n\r\n const $expand = expand === true || !_fullscreen\r\n animate = !((animate === false || Util.isReducedMotion()))// default is true\r\n\r\n const params = ['left', 'top', 'width', 'height']\r\n\r\n if ($expand) {\r\n if (_fullscreen) return false// return if already fullscreen\r\n\r\n const ev = EventHandler.trigger(this.element, Event.EXPAND)\r\n if (ev.defaultPrevented || this.isTransitioning) return false\r\n\r\n if (button) button.classList.add('active')\r\n\r\n if (animate) {\r\n this.isTransitioning = true\r\n\r\n const rect = this.element.getBoundingClientRect()\r\n params.forEach((param) => { this.element.style[param] = parseInt(rect[param]) + 'px' })\r\n\r\n this.element.classList.add('card-expanding')\r\n\r\n const transitionFn = (e) => {\r\n if (e.target !== this.element) return// because transitionend might fire for children elements (like animated icons of toolbar)\r\n\r\n this.element.removeEventListener('transitionend', transitionFn)\r\n this.element.classList.remove('card-expanding')\r\n\r\n this.isTransitioning = false\r\n EventHandler.trigger(this.element, Event.EXPANDED)\r\n }\r\n this.element.addEventListener('transitionend', transitionFn)\r\n\r\n Util.after(this.element, `
`)\r\n\r\n Util.reflow(this.element)// to force browser apply css/dom changes\r\n params.forEach((param) => { this.element.style[param] = '' })\r\n }\r\n\r\n this.element.classList.add('card-expand')\r\n if (!animate) {\r\n EventHandler.trigger(this.element, Event.EXPANDED)\r\n }\r\n } else { // restore\r\n if (!_fullscreen) return false// return if already not fullscreen\r\n\r\n const ev = EventHandler.trigger(this.element, Event.RESTORE)\r\n if (ev.defaultPrevented || this.isTransitioning) return false\r\n\r\n if (button) button.classList.remove('active')\r\n\r\n animate = animate && this.element.nextElementSibling !== null && this.element.nextElementSibling.classList.contains('card-expanded-placeholder')\r\n if (animate) {\r\n this.isTransitioning = true\r\n\r\n const rect = this.element.nextElementSibling.getBoundingClientRect()\r\n\r\n this.element.classList.add('card-expanding')\r\n params.forEach((param) => { this.element.style[param] = parseInt(rect[param]) + 'px' })\r\n\r\n const transitionFn = (e) => {\r\n if (e.target !== this.element) return// because transitionend might fire for children elements (like animated icons of toolbar)\r\n\r\n this.element.removeEventListener('transitionend', transitionFn)\r\n this.element.classList.remove('card-expanding')\r\n params.forEach((param) => { this.element.style[param] = '' })\r\n\r\n Util.remove(this.element.nextElementSibling)\r\n\r\n this.isTransitioning = false\r\n EventHandler.trigger(this.element, Event.RESTORED)\r\n }\r\n this.element.addEventListener('transitionend', transitionFn)\r\n }\r\n\r\n this.element.classList.remove('card-expand')\r\n if (!animate) {\r\n EventHandler.trigger(this.element, Event.RESTORED)\r\n }\r\n }\r\n\r\n return true\r\n }// function expand\r\n\r\n expandFast () {\r\n return this.expand(true, false)\r\n }\r\n\r\n restore () {\r\n return this.expand(false)\r\n }\r\n\r\n restoreFast () {\r\n return this.expand(false, false)\r\n }\r\n\r\n isFullscreen () {\r\n return this.element.classList.contains('card-expand')\r\n }\r\n\r\n _getConfig (config) {\r\n config = {\r\n ...Default,\r\n ...typeof config === 'object' && config ? config : {}\r\n }\r\n\r\n if (typeof window.bootstrap !== 'undefined') {\r\n window.bootstrap.Util.typeCheckConfig(\r\n NAME,\r\n config,\r\n this.constructor.DefaultType\r\n )\r\n }\r\n\r\n return config\r\n }\r\n\r\n // Static methods\r\n static getInstance (element, config = null) {\r\n if (!element) throw new Error('element for Card is null')\r\n\r\n const name = `__${NAME}__`\r\n if (typeof element[name] !== 'undefined') return element[name]\r\n\r\n element[name] = new Card(element, config)\r\n return element[name]\r\n }\r\n\r\n static _jQueryInterface (config, value) {\r\n return this.each(function () {\r\n const $this = window.jQuery(this)\r\n let data = $this.data(DATA_KEY)\r\n\r\n const _config = {\r\n // ...Default,\r\n ...$this.data(),\r\n ...typeof config && typeof config === 'object' ? config : {}\r\n }\r\n\r\n if (!data) {\r\n data = Card.getInstance(this, _config)\r\n $this.data(DATA_KEY, data)\r\n }\r\n\r\n if (typeof config === 'string') {\r\n if (typeof data[config] === 'undefined') {\r\n throw new TypeError(`No method named \"${config}\"`)\r\n }\r\n data[config](value)\r\n }\r\n })\r\n }\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * jQuery\r\n * ------------------------------------------------------------------------\r\n*/\r\n\r\nif (typeof jQuery !== 'undefined') {\r\n const $ = window.jQuery\r\n\r\n EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_ACTION, function (event) {\r\n const actionBtn = event.delegateTarget\r\n if (actionBtn.tagName === 'A') {\r\n event.preventDefault()\r\n }\r\n\r\n const card = Util.closest(actionBtn, '.card')\r\n if (card === null) return\r\n\r\n const action = actionBtn.getAttribute('data-action')\r\n const ev = EventHandler.trigger(card, action + EVENT_KEY)\r\n if (ev.defaultPrevented) return\r\n\r\n try {\r\n $(card)[NAME](action, actionBtn)\r\n } catch (e) {}\r\n })\r\n\r\n const JQUERY_NO_CONFLICT = $.fn[NAME]\r\n $.fn[NAME] = Card._jQueryInterface\r\n $.fn[NAME].Constructor = Card\r\n $.fn[NAME].noConflict = () => {\r\n $.fn[NAME] = JQUERY_NO_CONFLICT\r\n return Card._jQueryInterface\r\n }\r\n}\r\n\r\nexport default Card\r\n","/**\r\n * --------------------------------------------------------------------------\r\n * Ace (v4.0.0): fileinput.js\r\n * Custom styling for default browser file input\r\n*/\r\n\r\nimport Util from './util'\r\nimport EventHandler from './event-handler'\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Constants\r\n * ------------------------------------------------------------------------\r\n*/\r\n\r\nconst NAME = 'aceFileInput'\r\nconst VERSION = '4.0.0'\r\nconst DATA_KEY = 'ace.file'\r\nconst EVENT_KEY = `.${DATA_KEY}`\r\n\r\nconst Event = {\r\n CHANGED: `changed${EVENT_KEY}`,\r\n INVALID: `invalid${EVENT_KEY}`,\r\n CLEAR: `clear${EVENT_KEY}`,\r\n PREVIEW_FAILED: `preview_failed${EVENT_KEY}`\r\n}\r\n\r\nconst Default = {\r\n style: false,\r\n persistent: false,\r\n\r\n container: 'border-1 brc-grey-l2 brc-h-warning-m1',\r\n\r\n btnChooseClass: 'bgc-default text-white px-2 pt-2 text-90 my-1px mr-1px',\r\n btnChangeClass: 'bgc-blue text-white px-2 pt-2 text-90 my-1px mr-1px',\r\n\r\n btnChooseText: 'Choose',\r\n btnChangeText: 'Change',\r\n\r\n placeholderClass: 'text-grey-m2 px-1',\r\n placeholderText: 'No file chosen',\r\n placeholderIcon: '',\r\n\r\n iconClass: 'mx-2px',\r\n\r\n reset: '',\r\n resetText: '',\r\n resetIcon: '',\r\n\r\n droppable: false,\r\n thumbnail: false, // large, fit, small\r\n previewImage: true,\r\n\r\n allowExt: null,\r\n denyExt: null,\r\n allowMime: null,\r\n denyMime: null,\r\n maxSize: null,\r\n\r\n previewSize: false,\r\n previewWidth: false,\r\n previewHeight: false,\r\n\r\n // callbacks\r\n beforeChange: null,\r\n\r\n fileIcons: {\r\n file: '',\r\n image: '',\r\n video: '',\r\n audio: '',\r\n document: '',\r\n archive: '',\r\n code: ''\r\n }\r\n}\r\n\r\nconst DefaultType = {\r\n persistent: 'boolean',\r\n\r\n style: '(boolean|string)',\r\n\r\n btn: '(string|undefined)',\r\n container: '(string|undefined)',\r\n icon: '(string|undefined)',\r\n\r\n placeholderText: '(string|undefined)',\r\n placeholderIcon: '(string|undefined)',\r\n btnChooseText: '(string|undefined)',\r\n btnChangeText: '(string|undefined)',\r\n\r\n reset: '(string|undefined)',\r\n resetText: '(string|undefined)',\r\n resetIcon: '(string|undefined)',\r\n\r\n droppable: 'boolean',\r\n thumbnail: '(boolean|string)',\r\n previewImage: 'boolean',\r\n\r\n allowExt: '(string|null)',\r\n denyExt: '(string|null)',\r\n allowMime: '(string|null)',\r\n denyMime: '(string|null)',\r\n maxSize: '(number|null)',\r\n\r\n previewSize: '(boolean|number)',\r\n previewWidth: '(boolean|number)',\r\n previewHeight: '(boolean|number)',\r\n\r\n fileIcons: '(object|null)',\r\n\r\n // callbacks\r\n beforeChange: '(function|null)'\r\n}\r\n\r\nconst PreviewError = {\r\n FILE_LOAD_FAILED: 1,\r\n IMAGE_LOAD_FAILED: 2,\r\n THUMBNAIL_FAILED: 3\r\n}\r\n\r\nclass ImagePreviewError extends Error {\r\n constructor (message, code) {\r\n super(message)\r\n this.code = code\r\n }\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Class Definition\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nclass FileInput {\r\n constructor (element, config) {\r\n this.settings = this._getConfig(config)\r\n\r\n this.settings.fileIcons = {\r\n ...Default.fileIcons,\r\n ...this.settings.fileIcons || {}\r\n }\r\n\r\n this.fileList = []\r\n this.selectMethod = ''\r\n\r\n this._hasMultiple = 'multiple' in document.createElement('INPUT')\r\n this._hasFileList = 'FileList' in window// file list enabled in modern browsers\r\n this._hasFileReader = 'FileReader' in window\r\n this._hasFile = 'File' in window\r\n\r\n this.element = element\r\n this.disabled = false\r\n this.canReset = true\r\n\r\n this._hasAcceptAttr = this.element.getAttribute('accept') !== null\r\n\r\n // if new files selected (via file dialog), handle them\r\n EventHandler.off(this.element, 'change.aceFileInput')\r\n EventHandler.on(this.element, 'change.aceFileInput', () => {\r\n if (this.disabled) return\r\n return this._handleOnChange()\r\n })\r\n\r\n // if a parent form is 'reset', reset UI as well\r\n const parentForm = Util.closest(this.element, 'form')\r\n if (parentForm) {\r\n EventHandler.off(parentForm, 'reset.aceFileInput')\r\n EventHandler.on(parentForm, 'reset.aceFileInput', () => {\r\n this.resetInputData()\r\n this.resetInputUI()\r\n })\r\n }\r\n\r\n const parentLabel = Util.closest(this.element, 'label')\r\n let tagName = 'label'\r\n if (parentLabel) {\r\n parentLabel.classList.add('d-block')\r\n tagName = 'span'// if not inside a \"LABEL\" tag, use \"LABEL\" tag, otherwise use \"SPAN\"\r\n }\r\n\r\n this._wrap = Util.wrap(this.element, `<${tagName} class=\"ace-file-input\" />`)\r\n\r\n this._applySettings()\r\n }\r\n\r\n // Getters\r\n static get VERSION () {\r\n return VERSION\r\n }\r\n\r\n static get DefaultType () {\r\n return DefaultType\r\n }\r\n\r\n _getConfig (config) {\r\n config = {\r\n ...Default,\r\n ...config\r\n }\r\n\r\n if (typeof window.bootstrap !== 'undefined') {\r\n window.bootstrap.Util.typeCheckConfig(\r\n NAME,\r\n config,\r\n this.constructor.DefaultType\r\n )\r\n }\r\n\r\n return config\r\n }\r\n\r\n _applySettings () {\r\n this._jQueryBS = typeof window.jQuery !== 'undefined' && typeof window.bootstrap !== 'undefined'\r\n\r\n this._isMulti = this.element.getAttribute('multiple') && this._hasMultiple\r\n this._isDropStyle = this.settings.style === 'drop'\r\n\r\n if (this._isDropStyle) {\r\n if (!this.settings.thumbnail) this.settings.thumbnail = 'small'\r\n this._wrap.classList.add('ace-file-multiple')\r\n } else {\r\n this._wrap.classList.remove('ace-file-multiple')\r\n }\r\n\r\n this._wrap.querySelectorAll('*:not([type=file])').forEach((el) => Util.remove(el))// remove all except our input, good for when changing settings\r\n\r\n const placeholder = `
\r\n\r\n ${this.settings.placeholderIcon || ''}\r\n\r\n\r\n ${this.settings.placeholderText}\r\n` + (!this._isDropStyle ? `${this.settings.btnChooseText}` : '') + '
'\r\n\r\n Util.after(this.element, `
${placeholder}
`)\r\n\r\n this.container = this.element.nextElementSibling\r\n\r\n if (this.settings.reset !== false) {\r\n const remove = this.settings.reset.length > 0 ? this.settings.reset : (!this._isDropStyle ? 'position-rc text-danger mr-n25 w-3 radius-2 border-1 brc-h-danger-m4 text-center' : 'position-tr bgc-white text-danger mt-n25 mr-n25 w-4 h-4 text-center pt-2px radius-round border-2 brc-grey-m4 brc-h-danger-m3')\r\n\r\n const btn = Util.append(this._wrap, `${this.settings.resetIcon}`)\r\n\r\n if (this.settings.resetText && this._jQueryBS && window.jQuery.fn.tooltip) window.jQuery(btn).tooltip({ container: 'body' })\r\n\r\n btn.addEventListener('click', (ev) => {\r\n ev.preventDefault()\r\n if (!this.canReset) return\r\n\r\n const event = EventHandler.trigger(this.element, Event.CLEAR)\r\n if (event.defaultPrevented) return\r\n\r\n this.resetInput()\r\n })\r\n }\r\n\r\n if (this.settings.droppable && this._hasFileList) {\r\n this._enableFileDrop()\r\n }\r\n\r\n // set 'accept' attribute if not set\r\n if (!this._hasAcceptAttr) {\r\n this._setAcceptAttr(this.settings.allowExt, this.settings.allowMime)\r\n }\r\n }\r\n\r\n showFileList ($files, innerCall) {\r\n const files = $files || this.fileList\r\n if (!files || !files.length) return\r\n\r\n /// //////////////////////////////////\r\n if (!this.settings.persistent) {\r\n this.resetInputUI()\r\n }\r\n\r\n this.container.classList.add('selected')\r\n this.container.querySelectorAll('.ace-file-placeholder').forEach((el) => el.classList.add('d-none'))\r\n\r\n for (let i = 0; i < files.length; i++) {\r\n let filename = ''\r\n let format = false\r\n\r\n if (typeof files[i] === 'string') filename = files[i]\r\n\r\n else if (this._hasFile && files[i] instanceof window.File) filename = files[i].name.trim()\r\n\r\n else if (files[i] instanceof Object && Object.prototype.hasOwnProperty.call(files[i], 'name')) {\r\n // format & name specified by user (pre-displaying name, etc)\r\n filename = files[i].name\r\n if (Object.prototype.hasOwnProperty.call(files[i], 'type')) format = files[i].type\r\n if (!Object.prototype.hasOwnProperty.call(files[i], 'path')) files[i].path = files[i].name\r\n } else continue\r\n\r\n let index = filename.lastIndexOf('\\\\') + 1\r\n if (index === 0) index = filename.lastIndexOf('/') + 1\r\n filename = filename.substr(index)\r\n\r\n if (!format) {\r\n if ((/\\.(jpe?g|png|gif|svg|bmp|tiff?|webp)$/i).test(filename)) {\r\n format = 'image'\r\n } else if ((/\\.(mpe?g|flv|mov|avi|swf|mp4|mkv|webm|wmv|3gp)$/i).test(filename)) {\r\n format = 'video'\r\n } else if ((/\\.(mp3|ogg|wav|wma|amr|aac)$/i).test(filename)) {\r\n format = 'audio'\r\n } else if ((/\\.(pdf|docx?|rtf|txt)$/i).test(filename)) {\r\n format = 'document'\r\n } else if ((/\\.(zip|rar|tar)$/i).test(filename)) {\r\n format = 'archive'\r\n } else if ((/\\.(html?|js|s?css|less|php|py|aspx?|rb|c|cpp|java|cs)$/i).test(filename)) {\r\n format = 'code'\r\n } else format = 'file'\r\n }\r\n\r\n const fileIcon = this.settings.fileIcons[format]\r\n\r\n let className = 'ace-file-item d-flex h-100'\r\n if (this.settings.thumbnail) className += ` ${this.settings.thumbnail !== 'small' ? 'flex-column my-2px py-2' : 'mx-1 py-1'} align-items-center`\r\n\r\n const label = Util.append(this.container, `
\r\n${fileIcon}\r\n${filename}` +\r\n (!this._isDropStyle ? `${this.settings.btnChangeText}` : '') +\r\n '
')\r\n\r\n const type = (innerCall === true && this._hasFile && files[i] instanceof window.File) ? files[i].type.trim() : ''\r\n const canPreview = this.settings.previewImage !== false && this._hasFileReader && this.settings.thumbnail &&\r\n\t\t\t\t\t((type.length > 0 && type.match('image')) || (type.length === 0 && format === 'image'))// the second one is for older Android's default browser which gives an empty text for file.type\r\n if (canPreview) {\r\n try {\r\n this._previewImage(files[i], label)\r\n .catch((result) => {\r\n EventHandler.trigger(this.element, Event.PREVIEW_FAILED, { $_previewError: { filename: filename, code: result.code } })\r\n })\r\n } catch (e) {\r\n // for IE that doesn't support Promises\r\n EventHandler.trigger(this.element, Event.PREVIEW_FAILED, { $_previewError: { filename: filename, code: PreviewError.FILE_LOAD_FAILED } })\r\n }\r\n }\r\n }\r\n }\r\n\r\n resetInput () {\r\n this.resetInputUI()\r\n this.resetInputField()\r\n this.resetInputData()\r\n }\r\n\r\n resetInputUI () {\r\n this.container.querySelectorAll('div:not(.ace-file-placeholder)').forEach((el) => Util.remove(el))\r\n this.container.querySelectorAll('.ace-file-placeholder').forEach((el) => el.classList.remove('d-none'))\r\n\r\n this.container.classList.remove('selected') // hides 'close' button\r\n this.stopLoading()\r\n }\r\n\r\n resetInputField () {\r\n this.element.value = ''\r\n this.element.type = ''\r\n this.element.type = 'file'\r\n }\r\n\r\n resetInputData () {\r\n this.fileList = []\r\n this.selectMethod = ''\r\n\r\n if (this._jQueryBS && window.jQuery(this.element).data('ace_input_files')) {\r\n window.jQuery(this.element).removeData('ace_input_files')\r\n window.jQuery(this.element).removeData('ace_input_method')\r\n }\r\n }\r\n\r\n enableReset () {\r\n this.canReset = true\r\n }\r\n\r\n disableReset () {\r\n this.canReset = false\r\n }\r\n\r\n disable () {\r\n this.disabled = true\r\n this.element.setAttribute('disabled', 'disabled')\r\n this.element.classList.add('disabled')\r\n }\r\n\r\n enable () {\r\n this.disabled = false\r\n this.element.removeAttribute('disabled')\r\n this.element.classList.remove('disabled')\r\n }\r\n\r\n files () {\r\n return this.fileList.length > 0 ? this.fileList : null\r\n }\r\n\r\n method () {\r\n return this.selectMethod\r\n }\r\n\r\n updateSettings (newSettings) {\r\n this.settings = {\r\n ...this.settings,\r\n ...newSettings || {}\r\n }\r\n\r\n this.settings.fileIcons = {\r\n ...this.settings.fileIcons,\r\n ...newSettings.fileIcons || {}\r\n }\r\n\r\n this._applySettings()\r\n }\r\n\r\n startLoading (loadingHtml = '') {\r\n let loader = this._wrap.querySelector('.ace-file-overlay')\r\n if (loader === null) {\r\n loader = Util.append(this._wrap, '
')\r\n\r\n EventHandler.on(loader, 'click', (ev) => {\r\n ev.stopImmediatePropagation()\r\n ev.preventDefault()\r\n })\r\n\r\n this.element.setAttribute('readonly', 'true')// for IE\r\n }\r\n loader.innerHTML = loadingHtml\r\n }\r\n\r\n stopLoading () {\r\n const loader = this._wrap.querySelector('.ace-file-overlay')\r\n if (loader === null) {\r\n this.element.removeAttribute('readonly')\r\n return\r\n }\r\n EventHandler.off(loader, 'click')\r\n Util.remove(loader)\r\n }\r\n\r\n _enableFileDrop () {\r\n const dropbox = this.element.parentNode\r\n\r\n EventHandler.off(dropbox, 'dragenter')\r\n EventHandler.on(dropbox, 'dragenter', (e) => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n })\r\n\r\n EventHandler.off(dropbox, 'dragover')\r\n EventHandler.on(dropbox, 'dragover', (e) => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n })\r\n\r\n EventHandler.off(dropbox, 'drop')\r\n EventHandler.on(dropbox, 'drop', (e) => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n\r\n if (this.disabled) return\r\n\r\n const dt = e.dataTransfer\r\n let tmpFileList = dt.files\r\n if (!this._isMulti && tmpFileList.length > 1) { // single file upload, but dragged multiple files\r\n const tmpfiles = []\r\n tmpfiles.push(tmpFileList[0])\r\n tmpFileList = tmpfiles// keep only first file\r\n }\r\n\r\n tmpFileList = this._processFiles(tmpFileList, true)// true means files have been dropped\r\n if (tmpFileList === false) return false\r\n\r\n this.selectMethod = 'drop'\r\n\r\n // const fileArray = [...tmpFileList]\r\n const fileArray = []\r\n for (let f = 0; f < tmpFileList.length; f++) fileArray.push(tmpFileList[f])\r\n\r\n if (this.settings.persistent) {\r\n this.fileList = this.fileList.concat(fileArray)\r\n } else {\r\n this.fileList = fileArray\r\n }\r\n\r\n if (this._jQueryBS) {\r\n window.jQuery(this.element).data('ace_input_files', this.fileList)\r\n window.jQuery(this.element).data('ace_input_method', this.selectMethod)\r\n }\r\n\r\n this.showFileList(fileArray, true)\r\n\r\n EventHandler.trigger(this.element, Event.CHANGED, { $_selectedFiles: { list: this.fileList, method: this.selectMethod } })\r\n\r\n return true\r\n })\r\n }\r\n\r\n /// ///////////\r\n\r\n _handleOnChange () {\r\n let tmpFileList = this.element.files || [this.element.value]// make it an array\r\n\r\n tmpFileList = this._processFiles(tmpFileList, false)// false means files have been selected, not dropped\r\n if (tmpFileList === false) return false\r\n\r\n // const fileArray = [...tmpFileList];\r\n const fileArray = []\r\n for (let f = 0; f < tmpFileList.length; f++) fileArray.push(tmpFileList[f])\r\n\r\n this.selectMethod = 'select'\r\n\r\n if (this.settings.persistent) {\r\n this.fileList = this.fileList.concat(fileArray)\r\n } else {\r\n this.fileList = fileArray\r\n }\r\n\r\n if (this._jQueryBS) {\r\n window.jQuery(this.element).data('ace_input_files', this.fileList)\r\n window.jQuery(this.element).data('ace_input_method', this.selectMethod)\r\n }\r\n\r\n this.showFileList(fileArray, true)\r\n\r\n EventHandler.trigger(this.element, Event.CHANGED, { $_selectedFiles: { list: this.fileList, method: this.selectMethod } })\r\n\r\n return true\r\n }\r\n\r\n _previewImage (file, label) {\r\n return new Promise((resolve, reject) => {\r\n const icon = label.querySelector('.ace-file-icon')// it should be out of onload, otherwise all onloads may target the same $icon because of delays\r\n if (icon) Util.empty(icon)\r\n\r\n const getImage = function (src, $file) {\r\n const img = Util.prepend(icon, \"\")\r\n\r\n // no error/load event is triggered in some browsers such as firefox mobile\r\n // so we wait a while and then reject the promise\r\n let waitTimer = setTimeout(() => {\r\n waitTimer = null\r\n removeEvents()\r\n imgFailed(img)\r\n }, 6000)\r\n\r\n const onLoad = () => {\r\n removeEvents()\r\n imgLoaded(img, $file)\r\n }\r\n\r\n const onError = () => {\r\n removeEvents()\r\n imgFailed(img)\r\n }\r\n\r\n const removeEvents = () => {\r\n if (waitTimer) {\r\n clearTimeout(waitTimer)\r\n waitTimer = null\r\n }\r\n\r\n img.removeEventListener('load', onLoad) // call only once\r\n img.removeEventListener('error', onError) // remove the other one too\r\n }\r\n\r\n img.addEventListener('load', onLoad)\r\n img.addEventListener('error', onError)\r\n\r\n img.src = src\r\n }\r\n\r\n const imgLoaded = (img, $file) => { // if image loaded successfully\r\n let size = this.settings.previewSize\r\n\r\n if (!size) {\r\n if (this.settings.previewWidth || this.settings.previewHeight) {\r\n size = { previewWidth: this.settings.previewWidth, previewHeight: this.settings.previewHeight }\r\n } else {\r\n size = 50\r\n if (this.settings.thumbnail === 'large') size = 150\r\n }\r\n }\r\n if (this.settings.thumbnail === 'fit') size = icon.parentNode.offsetWidth\r\n else if (typeof size === 'number') size = parseInt(Math.min(size, icon.parentNode.offsetWidth))\r\n\r\n const svg = /svg/.test($file.type)\r\n const thumb = !svg ? this._getThumbnail(img, size, $file.type) : false//, file.type;\r\n if (thumb === null) {\r\n // if making thumbnail fails\r\n Util.remove(img)\r\n\r\n reject(new ImagePreviewError('Thumbnail Failed', PreviewError.THUMBNAIL_FAILED))\r\n return\r\n }\r\n\r\n const showPreview = true\r\n if (showPreview) {\r\n if (svg) {\r\n if (this.settings.thumbnail === 'small') {\r\n img.style.width = size + 'px'\r\n } else {\r\n if (img.width > img.height) {\r\n img.style.width = size + 'px'\r\n } else {\r\n img.style.height = size + 'px'\r\n }\r\n }\r\n } else {\r\n let w = thumb.previewWidth\r\n let h = thumb.previewHeight\r\n\r\n if (this.settings.thumbnail === 'small') {\r\n w = h = parseInt(Math.max(w, h))\r\n } else {\r\n icon.classList.add('thumbnail-large')\r\n }\r\n\r\n img.style.background = `url(${thumb.src}) center no-repeat`\r\n img.style.width = w + 'px'\r\n img.style.height = h + 'px'\r\n\r\n img.setAttribute('data-src', thumb.src)\r\n img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg=='\r\n }\r\n\r\n img.style.display = ''\r\n }\r\n\r\n /// ////////////////\r\n resolve()\r\n }\r\n const imgFailed = function (img) {\r\n // for example when a file has image extenstion, but format is something else\r\n Util.remove(img)\r\n reject(new ImagePreviewError('Image Load Failed', PreviewError.IMAGE_LOAD_FAILED))\r\n }\r\n\r\n if (this._hasFile && file instanceof window.File) {\r\n const reader = new window.FileReader()\r\n reader.onload = function (e) {\r\n getImage(e.target.result, file)\r\n }\r\n reader.onerror = function (e) {\r\n reject(new ImagePreviewError('File Load Failed', PreviewError.FILE_LOAD_FAILED))\r\n }\r\n reader.readAsDataURL(file)\r\n } else {\r\n if (file instanceof Object && Object.prototype.hasOwnProperty.call(file, 'path')) {\r\n getImage(file.path, file)// file is a file name (path) --- this is used to pre-show user-selected image\r\n }\r\n }\r\n })\r\n }\r\n\r\n /// //////////\r\n\r\n _getThumbnail (img, size, type) {\r\n let imgWidth = img.width\r\n let imgHeight = img.height\r\n\r\n //* *IE10** is not giving correct width using img.width\r\n imgWidth = imgWidth > 0 ? imgWidth : img.offsetWidth\r\n imgHeight = imgHeight > 0 ? imgHeight : img.offsetHeight\r\n\r\n let previewSize = false\r\n let previewHeight = false\r\n let previewWidth = false\r\n\r\n if (typeof size === 'number') previewSize = size\r\n else if (size instanceof Object) {\r\n if (size.previewWidth && !size.previewHeight) previewWidth = size.previewWidth\r\n else if (size.previewHeight && !size.previewWidth) previewHeight = size.previewHeight\r\n else if (size.previewWidth && size.previewHeight) {\r\n previewWidth = size.previewWidth\r\n previewHeight = size.previewHeight\r\n }\r\n }\r\n\r\n if (previewSize) {\r\n if (imgWidth > imgHeight) {\r\n previewWidth = previewSize\r\n previewHeight = parseInt(imgHeight / imgWidth * previewWidth)\r\n } else {\r\n previewHeight = previewSize\r\n previewWidth = parseInt(imgWidth / imgHeight * previewHeight)\r\n }\r\n } else {\r\n if (!previewHeight && previewWidth) {\r\n previewHeight = parseInt(imgHeight / imgWidth * previewWidth)\r\n } else if (previewHeight && !previewWidth) {\r\n previewWidth = parseInt(imgWidth / imgHeight * previewHeight)\r\n }\r\n }\r\n\r\n let dataURL\r\n try {\r\n const canvas = document.createElement('canvas')\r\n canvas.width = previewWidth\r\n canvas.height = previewHeight\r\n\r\n const context = canvas.getContext('2d')\r\n context.imageSmoothingQuality = 'medium'\r\n context.drawImage(img, 0, 0, imgWidth, imgHeight, 0, 0, previewWidth, previewHeight)\r\n dataURL = canvas.toDataURL(type, 0.8)\r\n // dataURL = canvas.toDataURL();\r\n } catch (e) {\r\n dataURL = null\r\n }\r\n if (!dataURL) return null\r\n\r\n // there was only one image that failed in firefox completely randomly! so let's double check things\r\n if (!(/^data:image\\/(png|jpe?g|gif|svg);base64,[0-9A-Za-z+/=]+$/.test(dataURL))) dataURL = null\r\n if (!dataURL) return null\r\n\r\n return { src: dataURL, previewWidth: previewWidth, previewHeight: previewHeight, width: imgWidth, height: imgHeight }\r\n }\r\n\r\n _processFiles (tmpFileList, dropped) {\r\n let ret = this._checkFileList(tmpFileList, dropped)\r\n if (ret === -1) {\r\n this.resetInput()\r\n return false\r\n }\r\n if (!ret || ret.length === 0) {\r\n if (this.fileList.length === 0) this.resetInput()\r\n // if nothing selected before, reset because of the newly unacceptable (ret=false||length=0) selection\r\n // otherwise leave the previous selection intact?!!!\r\n return false\r\n }\r\n if (ret instanceof Array || (this._hasFileList && ret instanceof window.FileList)) tmpFileList = ret\r\n\r\n ret = true\r\n\r\n if (this.settings.beforeChange) ret = this.settings.beforeChange.call(this.element, tmpFileList, dropped)\r\n if (ret === -1) {\r\n this.resetInput()\r\n return false\r\n }\r\n if (!ret || ret.length === 0) {\r\n if (this.fileList.length === 0) this.resetInput()\r\n return false\r\n }\r\n\r\n // inside beforeChange you can return a modified File Array as result\r\n if (ret instanceof Array || (this._hasFileList && ret instanceof window.FileList)) tmpFileList = ret\r\n\r\n return tmpFileList\r\n }\r\n\r\n /// ///////\r\n\r\n _checkFileList (files, dropped) {\r\n const allowExt = this._getExtRegex(this.settings.allowExt)\r\n\r\n const denyExt = this._getExtRegex(this.settings.denyExt)\r\n\r\n const allowMime = this._getMimeRegex(this.settings.allowMime)\r\n\r\n const denyMime = this._getMimeRegex(this.settings.denyMime)\r\n\r\n const maxSize = this.settings.maxSize || false\r\n\r\n if (!(allowExt || denyExt || allowMime || denyMime || maxSize)) return true// no checking required\r\n\r\n const safeFiles = []\r\n const errorList = {}\r\n // for (const file of files) {\r\n for (let i = 0; i < files.length; i++) {\r\n const file = files[i]\r\n // file is either a string(file name) or a File object\r\n const filename = !this._hasFile ? file : file.name\r\n if (allowExt && !allowExt.test(filename)) {\r\n // extension not matching whitelist, so drop it\r\n if (!('ext' in errorList)) errorList.ext = []\r\n errorList.ext.push(filename)\r\n\r\n continue\r\n } else if (denyExt && denyExt.test(filename)) {\r\n // extension is matching blacklist, so drop it\r\n if (!('ext' in errorList)) errorList.ext = []\r\n errorList.ext.push(filename)\r\n\r\n continue\r\n }\r\n\r\n let type\r\n if (!this._hasFile) {\r\n // in browsers that don't support FileReader API\r\n safeFiles.push(file)\r\n continue\r\n } else if ((type = file.type.trim()).length > 0) {\r\n // there is a mimetype for file so let's check against are rules\r\n if (allowMime && !allowMime.test(type)) {\r\n // mimeType is not matching whitelist, so drop it\r\n if (!('mime' in errorList)) errorList.mime = []\r\n errorList.mime.push(filename)\r\n continue\r\n } else if (denyMime && denyMime.test(type)) {\r\n // mimeType is matching blacklist, so drop it\r\n if (!('mime' in errorList)) errorList.mime = []\r\n errorList.mime.push(filename)\r\n continue\r\n }\r\n }\r\n\r\n if (maxSize && file.size > maxSize) {\r\n // file size is not acceptable\r\n if (!('size' in errorList)) errorList.size = []\r\n errorList.size.push(filename)\r\n continue\r\n }\r\n\r\n safeFiles.push(file)\r\n }\r\n\r\n if (safeFiles.length === files.length) return files// return original file list if all are valid\r\n\r\n /// //////\r\n const errorCount = { ext: 0, mime: 0, size: 0 }\r\n if ('ext' in errorList) errorCount.ext = errorList.ext.length\r\n if ('mime' in errorList) errorCount.mime = errorList.mime.length\r\n if ('size' in errorList) errorCount.size = errorList.size.length\r\n\r\n const event = EventHandler.trigger(this.element, Event.INVALID,\r\n {\r\n $_fileErrors: {\r\n fileCount: files.length,\r\n invalidCount: files.length - safeFiles.length,\r\n errorList: errorList,\r\n errorCount: errorCount,\r\n dropped: dropped\r\n }\r\n }\r\n )\r\n if (event.defaultPrevented) return -1// it will reset input\r\n /// ///////\r\n\r\n return safeFiles// return safeFiles\r\n }\r\n\r\n _setAcceptAttr (ext = '', mime = '') {\r\n if (ext) {\r\n if (Array.isArray(ext)) ext = ext.join(',.')\r\n else ext = ext.replace(/\\|/g, ',.')\r\n ext = '.' + ext\r\n }\r\n\r\n if (mime) {\r\n if (Array.isArray(mime)) mime = mime.join(',')\r\n // replace `/\\w+` with `/*` ... for example, `image/\\w+` becomes `image/*`\r\n else mime = mime.replace(/\\|/g, ',').replace(/\\/\\\\w+/g, '/*')\r\n }\r\n\r\n let accept = (ext || '') + (ext && mime ? ',' : '') + (mime || '')\r\n accept = accept.replace(/\\s/g, '')\r\n if (accept) this.element.setAttribute('accept', accept)\r\n }\r\n\r\n _getExtRegex (ext) {\r\n if (!ext) return null\r\n if (Array.isArray(ext)) ext = ext.join('|')\r\n if (ext.length === 0) return null\r\n return new RegExp('\\\\.(?:' + ext + ')$', 'i')\r\n }\r\n\r\n _getMimeRegex (mime) {\r\n if (!mime) return null\r\n if (Array.isArray(mime)) mime = mime.join('|')\r\n if (mime.length === 0) return null\r\n // replace `/*` with `/\\w+` ... for example, `image/*` becomes `image/\\w+`\r\n return new RegExp('^(?:' + mime.replace(/\\/\\*/g, '/\\\\w+').replace(/\\//g, '\\\\/') + ')$', 'i')\r\n }\r\n\r\n // Static methods\r\n static getInstance (element, config = null) {\r\n if (!element) throw new Error('element for Fileinput is null')\r\n\r\n const name = `__${NAME}__`\r\n if (typeof element[name] !== 'undefined') return element[name]\r\n\r\n element[name] = new FileInput(element, config)\r\n return element[name]\r\n }\r\n\r\n static _jQueryInterface (config, value) {\r\n let retval\r\n const reteach = this.each(function () {\r\n if (!Util.matches(this, 'input[type=file]')) return\r\n\r\n const $this = window.jQuery(this)\r\n let data = $this.data(DATA_KEY)\r\n const _config = {\r\n ...Default,\r\n ...$this.data(),\r\n ...typeof config === 'object' && config ? config : {}\r\n }\r\n\r\n if (!data) {\r\n data = FileInput.getInstance(this, _config)\r\n $this.data(DATA_KEY, data)\r\n }\r\n\r\n if (typeof config === 'string') {\r\n if (typeof data[config] === 'undefined') {\r\n throw new TypeError(`No method named \"${config}\"`)\r\n }\r\n retval = data[config](value)\r\n }\r\n })\r\n\r\n return (typeof retval !== 'undefined') ? retval : reteach\r\n }\r\n}\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * jQuery\r\n * ------------------------------------------------------------------------\r\n*/\r\n\r\nif (typeof jQuery !== 'undefined') {\r\n const $ = window.jQuery\r\n const JQUERY_NO_CONFLICT = $.fn[NAME]\r\n $.fn[NAME] = FileInput._jQueryInterface\r\n $.fn[NAME].Constructor = FileInput\r\n $.fn[NAME].noConflict = () => {\r\n $.fn[NAME] = JQUERY_NO_CONFLICT\r\n return FileInput._jQueryInterface\r\n }\r\n}\r\n\r\nexport default FileInput\r\n","/**\r\n * --------------------------------------------------------------------------\r\n * Ace (v4.0.0): wysiwyg.js\r\n Wrapper for Bootstrap wyswiwyg plugin\r\n*/\r\n\r\nimport $ from 'jquery'\r\nimport bootstrap from 'bootstrap'\r\n\r\n/**\r\n * ------------------------------------------------------------------------\r\n * Constants\r\n * ------------------------------------------------------------------------\r\n */\r\n\r\nconst NAME = 'aceWysiwyg'\r\nconst VERSION = '4.0.0'\r\nconst DATA_KEY = 'ace.wysiwyg'\r\n\r\nconst DefaultType = {\r\n wysiwyg: 'object',\r\n colors: 'array',\r\n // speech: 'boolean',\r\n toolbar: 'array',\r\n toolbarPlacement: '(function|null)',\r\n toolbarStyle: '(string|number)'\r\n}\r\n\r\nconst Default = {\r\n wysiwyg: {},\r\n // speech: true,\r\n toolbarPlacement: null,\r\n toolbarStyle: '',\r\n\r\n colors: ['#000000', '#424242', '#636363', '#9c9c94', '#cec6ce', '#efefef', '#f7f7f7', '#ffffff',\r\n '#ff0000', '#ff9c00', '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#9c00ff', '#ff00ff',\r\n '#f7c6ce', '#ffe7ce', '#ffefc6', '#d6efd6', '#cedee7', '#cee7f7', '#d6d6e7', '#e7d6de',\r\n '#e79c9c', '#ffc69c', '#ffe79c', '#b5d6a5', '#a5c6ce', '#9cc6ef', '#b5a5d6', '#d6a5bd',\r\n '#e76363', '#f7ad6b', '#ffd663', '#94bd7b', '#73a5ad', '#6badde', '#8c7bc6', '#c67ba5',\r\n '#ce0000', '#e79439', '#efc631', '#6ba54a', '#4a7b8c', '#3984c6', '#634aa5', '#a54a7b',\r\n '#9c0000', '#b56308', '#bd9400', '#397b21', '#104a5a', '#085294', '#311873', '#731842',\r\n '#630000', '#7b3900', '#846300', '#295218', '#083139', '#003163', '#21104a', '#4a1031'],\r\n\r\n toolbar: ['font', null, 'fontSize', null, 'bold', 'italic', 'strikethrough', 'underline', null, 'insertunorderedlist', 'insertorderedlist',\r\n 'outdent', 'indent', null, 'justifyleft', 'justifycenter', 'justifyright', 'justifyfull', null, 'createLink', 'unlink', null,\r\n 'insertImage', null, 'foreColor', null, 'undo', 'redo', null, 'viewSource']\r\n}\r\n\r\nclass Wysiwyg {\r\n constructor (element, config) {\r\n this._element\t= element\r\n this._config = this._getConfig(config)\r\n\r\n this.initEditor()\r\n }\r\n\r\n static get VERSION () {\r\n return VERSION\r\n }\r\n\r\n static get DefaultType () {\r\n return DefaultType\r\n }\r\n\r\n static get Default () {\r\n return Default\r\n }\r\n\r\n initEditor () {\r\n const toolbarHtml = this._createToolbarHtml()\r\n let toolbar\r\n // if we have a function to decide where to put the toolbar, then call that\r\n if (this._config.toolbarPlacement) toolbar = this._config.toolbarPlacement.call(this._element, toolbarHtml)\r\n else toolbar = $(this._element).before(toolbarHtml).prev()// otherwise put it just before our DIV\r\n\r\n if (this._config.toolbarStyle) toolbar.addClass('bsw-toolbar-style-' + this._config.toolbarStyle)\r\n\r\n // enable tooltips\r\n if ($.fn.tooltip) toolbar.find('a[title]').tooltip({ animation: false, container: 'body' })\r\n\r\n toolbar.find('.dropdown-menu input[type=text]').on('click', function () { return false })\r\n .on('change', function () { $(this).closest('.dropdown-menu').siblings('.dropdown-toggle').dropdown('toggle') })\r\n .on('keydown', function (e) {\r\n if (e.which === 27) {\r\n this.value = ''\r\n // $(this).change()\r\n } else if (e.which === 13) {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n // $(this).change()\r\n }\r\n })\r\n\r\n toolbar.find('input[type=file]').prev().on('click', function (e) {\r\n // $(this).next().click()\r\n })\r\n\r\n const self = $(this._element)\r\n // view source\r\n let viewSource = false\r\n toolbar.find('a[data-toggle=source]').on('click', function (e) {\r\n e.preventDefault()\r\n\r\n if (!viewSource) {\r\n $('