From 6ed2453380542f0f93bd15f91a6a9452dd49cc7c Mon Sep 17 00:00:00 2001 From: "Jonny_Bro (Nikita)" Date: Mon, 30 Oct 2023 22:05:49 +0500 Subject: [PATCH] remove anti-war thingy --- theme/dbd-soft-ui/views/partials/scripts.ejs | 2 +- .../views/src/js/plugins/sweetalert2.js | 4252 +++++++++++++++++ 2 files changed, 4253 insertions(+), 1 deletion(-) create mode 100644 theme/dbd-soft-ui/views/src/js/plugins/sweetalert2.js diff --git a/theme/dbd-soft-ui/views/partials/scripts.ejs b/theme/dbd-soft-ui/views/partials/scripts.ejs index cb63bec..dc30e88 100644 --- a/theme/dbd-soft-ui/views/partials/scripts.ejs +++ b/theme/dbd-soft-ui/views/partials/scripts.ejs @@ -157,6 +157,7 @@ + @@ -167,6 +168,5 @@ - \ No newline at end of file diff --git a/theme/dbd-soft-ui/views/src/js/plugins/sweetalert2.js b/theme/dbd-soft-ui/views/src/js/plugins/sweetalert2.js new file mode 100644 index 0000000..b34e3c8 --- /dev/null +++ b/theme/dbd-soft-ui/views/src/js/plugins/sweetalert2.js @@ -0,0 +1,4252 @@ +/*! +* sweetalert2 v11.9.0 +* Released under the MIT License. +*/ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Sweetalert2 = factory()); +})(this, (function () { 'use strict'; + + function _classPrivateFieldGet(receiver, privateMap) { + var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); + return _classApplyDescriptorGet(receiver, descriptor); + } + function _classPrivateFieldSet(receiver, privateMap, value) { + var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); + _classApplyDescriptorSet(receiver, descriptor, value); + return value; + } + function _classExtractFieldDescriptor(receiver, privateMap, action) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to " + action + " private field on non-instance"); + } + return privateMap.get(receiver); + } + function _classApplyDescriptorGet(receiver, descriptor) { + if (descriptor.get) { + return descriptor.get.call(receiver); + } + return descriptor.value; + } + function _classApplyDescriptorSet(receiver, descriptor, value) { + if (descriptor.set) { + descriptor.set.call(receiver, value); + } else { + if (!descriptor.writable) { + throw new TypeError("attempted to set read only private field"); + } + descriptor.value = value; + } + } + function _checkPrivateRedeclaration(obj, privateCollection) { + if (privateCollection.has(obj)) { + throw new TypeError("Cannot initialize the same private elements twice on an object"); + } + } + function _classPrivateFieldInitSpec(obj, privateMap, value) { + _checkPrivateRedeclaration(obj, privateMap); + privateMap.set(obj, value); + } + + const RESTORE_FOCUS_TIMEOUT = 100; + + /** @type {GlobalState} */ + const globalState = {}; + const focusPreviousActiveElement = () => { + if (globalState.previousActiveElement instanceof HTMLElement) { + globalState.previousActiveElement.focus(); + globalState.previousActiveElement = null; + } else if (document.body) { + document.body.focus(); + } + }; + + /** + * Restore previous active (focused) element + * + * @param {boolean} returnFocus + * @returns {Promise} + */ + const restoreActiveElement = returnFocus => { + return new Promise(resolve => { + if (!returnFocus) { + return resolve(); + } + const x = window.scrollX; + const y = window.scrollY; + globalState.restoreFocusTimeout = setTimeout(() => { + focusPreviousActiveElement(); + resolve(); + }, RESTORE_FOCUS_TIMEOUT); // issues/900 + + window.scrollTo(x, y); + }); + }; + + const swalPrefix = 'swal2-'; + + /** + * @typedef + * { | 'container' + * | 'shown' + * | 'height-auto' + * | 'iosfix' + * | 'popup' + * | 'modal' + * | 'no-backdrop' + * | 'no-transition' + * | 'toast' + * | 'toast-shown' + * | 'show' + * | 'hide' + * | 'close' + * | 'title' + * | 'html-container' + * | 'actions' + * | 'confirm' + * | 'deny' + * | 'cancel' + * | 'default-outline' + * | 'footer' + * | 'icon' + * | 'icon-content' + * | 'image' + * | 'input' + * | 'file' + * | 'range' + * | 'select' + * | 'radio' + * | 'checkbox' + * | 'label' + * | 'textarea' + * | 'inputerror' + * | 'input-label' + * | 'validation-message' + * | 'progress-steps' + * | 'active-progress-step' + * | 'progress-step' + * | 'progress-step-line' + * | 'loader' + * | 'loading' + * | 'styled' + * | 'top' + * | 'top-start' + * | 'top-end' + * | 'top-left' + * | 'top-right' + * | 'center' + * | 'center-start' + * | 'center-end' + * | 'center-left' + * | 'center-right' + * | 'bottom' + * | 'bottom-start' + * | 'bottom-end' + * | 'bottom-left' + * | 'bottom-right' + * | 'grow-row' + * | 'grow-column' + * | 'grow-fullscreen' + * | 'rtl' + * | 'timer-progress-bar' + * | 'timer-progress-bar-container' + * | 'scrollbar-measure' + * | 'icon-success' + * | 'icon-warning' + * | 'icon-info' + * | 'icon-question' + * | 'icon-error' + * } SwalClass + * @typedef {Record} SwalClasses + */ + + /** + * @typedef {'success' | 'warning' | 'info' | 'question' | 'error'} SwalIcon + * @typedef {Record} SwalIcons + */ + + /** @type {SwalClass[]} */ + const classNames = ['container', 'shown', 'height-auto', 'iosfix', 'popup', 'modal', 'no-backdrop', 'no-transition', 'toast', 'toast-shown', 'show', 'hide', 'close', 'title', 'html-container', 'actions', 'confirm', 'deny', 'cancel', 'default-outline', 'footer', 'icon', 'icon-content', 'image', 'input', 'file', 'range', 'select', 'radio', 'checkbox', 'label', 'textarea', 'inputerror', 'input-label', 'validation-message', 'progress-steps', 'active-progress-step', 'progress-step', 'progress-step-line', 'loader', 'loading', 'styled', 'top', 'top-start', 'top-end', 'top-left', 'top-right', 'center', 'center-start', 'center-end', 'center-left', 'center-right', 'bottom', 'bottom-start', 'bottom-end', 'bottom-left', 'bottom-right', 'grow-row', 'grow-column', 'grow-fullscreen', 'rtl', 'timer-progress-bar', 'timer-progress-bar-container', 'scrollbar-measure', 'icon-success', 'icon-warning', 'icon-info', 'icon-question', 'icon-error']; + const swalClasses = classNames.reduce((acc, className) => { + acc[className] = swalPrefix + className; + return acc; + }, /** @type {SwalClasses} */{}); + + /** @type {SwalIcon[]} */ + const icons = ['success', 'warning', 'info', 'question', 'error']; + const iconTypes = icons.reduce((acc, icon) => { + acc[icon] = swalPrefix + icon; + return acc; + }, /** @type {SwalIcons} */{}); + + const consolePrefix = 'SweetAlert2:'; + + /** + * Capitalize the first letter of a string + * + * @param {string} str + * @returns {string} + */ + const capitalizeFirstLetter = str => str.charAt(0).toUpperCase() + str.slice(1); + + /** + * Standardize console warnings + * + * @param {string | string[]} message + */ + const warn = message => { + console.warn("".concat(consolePrefix, " ").concat(typeof message === 'object' ? message.join(' ') : message)); + }; + + /** + * Standardize console errors + * + * @param {string} message + */ + const error = message => { + console.error("".concat(consolePrefix, " ").concat(message)); + }; + + /** + * Private global state for `warnOnce` + * + * @type {string[]} + * @private + */ + const previousWarnOnceMessages = []; + + /** + * Show a console warning, but only if it hasn't already been shown + * + * @param {string} message + */ + const warnOnce = message => { + if (!previousWarnOnceMessages.includes(message)) { + previousWarnOnceMessages.push(message); + warn(message); + } + }; + + /** + * Show a one-time console warning about deprecated params/methods + * + * @param {string} deprecatedParam + * @param {string} useInstead + */ + const warnAboutDeprecation = (deprecatedParam, useInstead) => { + warnOnce("\"".concat(deprecatedParam, "\" is deprecated and will be removed in the next major release. Please use \"").concat(useInstead, "\" instead.")); + }; + + /** + * If `arg` is a function, call it (with no arguments or context) and return the result. + * Otherwise, just pass the value through + * + * @param {Function | any} arg + * @returns {any} + */ + const callIfFunction = arg => typeof arg === 'function' ? arg() : arg; + + /** + * @param {any} arg + * @returns {boolean} + */ + const hasToPromiseFn = arg => arg && typeof arg.toPromise === 'function'; + + /** + * @param {any} arg + * @returns {Promise} + */ + const asPromise = arg => hasToPromiseFn(arg) ? arg.toPromise() : Promise.resolve(arg); + + /** + * @param {any} arg + * @returns {boolean} + */ + const isPromise = arg => arg && Promise.resolve(arg) === arg; + + /** + * Gets the popup container which contains the backdrop and the popup itself. + * + * @returns {HTMLElement | null} + */ + const getContainer = () => document.body.querySelector(".".concat(swalClasses.container)); + + /** + * @param {string} selectorString + * @returns {HTMLElement | null} + */ + const elementBySelector = selectorString => { + const container = getContainer(); + return container ? container.querySelector(selectorString) : null; + }; + + /** + * @param {string} className + * @returns {HTMLElement | null} + */ + const elementByClass = className => { + return elementBySelector(".".concat(className)); + }; + + /** + * @returns {HTMLElement | null} + */ + const getPopup = () => elementByClass(swalClasses.popup); + + /** + * @returns {HTMLElement | null} + */ + const getIcon = () => elementByClass(swalClasses.icon); + + /** + * @returns {HTMLElement | null} + */ + const getIconContent = () => elementByClass(swalClasses['icon-content']); + + /** + * @returns {HTMLElement | null} + */ + const getTitle = () => elementByClass(swalClasses.title); + + /** + * @returns {HTMLElement | null} + */ + const getHtmlContainer = () => elementByClass(swalClasses['html-container']); + + /** + * @returns {HTMLElement | null} + */ + const getImage = () => elementByClass(swalClasses.image); + + /** + * @returns {HTMLElement | null} + */ + const getProgressSteps = () => elementByClass(swalClasses['progress-steps']); + + /** + * @returns {HTMLElement | null} + */ + const getValidationMessage = () => elementByClass(swalClasses['validation-message']); + + /** + * @returns {HTMLButtonElement | null} + */ + const getConfirmButton = () => /** @type {HTMLButtonElement} */elementBySelector(".".concat(swalClasses.actions, " .").concat(swalClasses.confirm)); + + /** + * @returns {HTMLButtonElement | null} + */ + const getCancelButton = () => /** @type {HTMLButtonElement} */elementBySelector(".".concat(swalClasses.actions, " .").concat(swalClasses.cancel)); + + /** + * @returns {HTMLButtonElement | null} + */ + const getDenyButton = () => /** @type {HTMLButtonElement} */elementBySelector(".".concat(swalClasses.actions, " .").concat(swalClasses.deny)); + + /** + * @returns {HTMLElement | null} + */ + const getInputLabel = () => elementByClass(swalClasses['input-label']); + + /** + * @returns {HTMLElement | null} + */ + const getLoader = () => elementBySelector(".".concat(swalClasses.loader)); + + /** + * @returns {HTMLElement | null} + */ + const getActions = () => elementByClass(swalClasses.actions); + + /** + * @returns {HTMLElement | null} + */ + const getFooter = () => elementByClass(swalClasses.footer); + + /** + * @returns {HTMLElement | null} + */ + const getTimerProgressBar = () => elementByClass(swalClasses['timer-progress-bar']); + + /** + * @returns {HTMLElement | null} + */ + const getCloseButton = () => elementByClass(swalClasses.close); + + // https://github.com/jkup/focusable/blob/master/index.js + const focusable = "\n a[href],\n area[href],\n input:not([disabled]),\n select:not([disabled]),\n textarea:not([disabled]),\n button:not([disabled]),\n iframe,\n object,\n embed,\n [tabindex=\"0\"],\n [contenteditable],\n audio[controls],\n video[controls],\n summary\n"; + /** + * @returns {HTMLElement[]} + */ + const getFocusableElements = () => { + const popup = getPopup(); + if (!popup) { + return []; + } + /** @type {NodeListOf} */ + const focusableElementsWithTabindex = popup.querySelectorAll('[tabindex]:not([tabindex="-1"]):not([tabindex="0"])'); + const focusableElementsWithTabindexSorted = Array.from(focusableElementsWithTabindex) + // sort according to tabindex + .sort((a, b) => { + const tabindexA = parseInt(a.getAttribute('tabindex') || '0'); + const tabindexB = parseInt(b.getAttribute('tabindex') || '0'); + if (tabindexA > tabindexB) { + return 1; + } else if (tabindexA < tabindexB) { + return -1; + } + return 0; + }); + + /** @type {NodeListOf} */ + const otherFocusableElements = popup.querySelectorAll(focusable); + const otherFocusableElementsFiltered = Array.from(otherFocusableElements).filter(el => el.getAttribute('tabindex') !== '-1'); + return [...new Set(focusableElementsWithTabindexSorted.concat(otherFocusableElementsFiltered))].filter(el => isVisible$1(el)); + }; + + /** + * @returns {boolean} + */ + const isModal = () => { + return hasClass(document.body, swalClasses.shown) && !hasClass(document.body, swalClasses['toast-shown']) && !hasClass(document.body, swalClasses['no-backdrop']); + }; + + /** + * @returns {boolean} + */ + const isToast = () => { + const popup = getPopup(); + if (!popup) { + return false; + } + return hasClass(popup, swalClasses.toast); + }; + + /** + * @returns {boolean} + */ + const isLoading = () => { + const popup = getPopup(); + if (!popup) { + return false; + } + return popup.hasAttribute('data-loading'); + }; + + /** + * Securely set innerHTML of an element + * https://github.com/sweetalert2/sweetalert2/issues/1926 + * + * @param {HTMLElement} elem + * @param {string} html + */ + const setInnerHtml = (elem, html) => { + elem.textContent = ''; + if (html) { + const parser = new DOMParser(); + const parsed = parser.parseFromString(html, "text/html"); + const head = parsed.querySelector('head'); + head && Array.from(head.childNodes).forEach(child => { + elem.appendChild(child); + }); + const body = parsed.querySelector('body'); + body && Array.from(body.childNodes).forEach(child => { + if (child instanceof HTMLVideoElement || child instanceof HTMLAudioElement) { + elem.appendChild(child.cloneNode(true)); // https://github.com/sweetalert2/sweetalert2/issues/2507 + } else { + elem.appendChild(child); + } + }); + } + }; + + /** + * @param {HTMLElement} elem + * @param {string} className + * @returns {boolean} + */ + const hasClass = (elem, className) => { + if (!className) { + return false; + } + const classList = className.split(/\s+/); + for (let i = 0; i < classList.length; i++) { + if (!elem.classList.contains(classList[i])) { + return false; + } + } + return true; + }; + + /** + * @param {HTMLElement} elem + * @param {SweetAlertOptions} params + */ + const removeCustomClasses = (elem, params) => { + Array.from(elem.classList).forEach(className => { + if (!Object.values(swalClasses).includes(className) && !Object.values(iconTypes).includes(className) && !Object.values(params.showClass || {}).includes(className)) { + elem.classList.remove(className); + } + }); + }; + + /** + * @param {HTMLElement} elem + * @param {SweetAlertOptions} params + * @param {string} className + */ + const applyCustomClass = (elem, params, className) => { + removeCustomClasses(elem, params); + if (params.customClass && params.customClass[className]) { + if (typeof params.customClass[className] !== 'string' && !params.customClass[className].forEach) { + warn("Invalid type of customClass.".concat(className, "! Expected string or iterable object, got \"").concat(typeof params.customClass[className], "\"")); + return; + } + addClass(elem, params.customClass[className]); + } + }; + + /** + * @param {HTMLElement} popup + * @param {import('./renderers/renderInput').InputClass | SweetAlertInput} inputClass + * @returns {HTMLInputElement | null} + */ + const getInput$1 = (popup, inputClass) => { + if (!inputClass) { + return null; + } + switch (inputClass) { + case 'select': + case 'textarea': + case 'file': + return popup.querySelector(".".concat(swalClasses.popup, " > .").concat(swalClasses[inputClass])); + case 'checkbox': + return popup.querySelector(".".concat(swalClasses.popup, " > .").concat(swalClasses.checkbox, " input")); + case 'radio': + return popup.querySelector(".".concat(swalClasses.popup, " > .").concat(swalClasses.radio, " input:checked")) || popup.querySelector(".".concat(swalClasses.popup, " > .").concat(swalClasses.radio, " input:first-child")); + case 'range': + return popup.querySelector(".".concat(swalClasses.popup, " > .").concat(swalClasses.range, " input")); + default: + return popup.querySelector(".".concat(swalClasses.popup, " > .").concat(swalClasses.input)); + } + }; + + /** + * @param {HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement} input + */ + const focusInput = input => { + input.focus(); + + // place cursor at end of text in text input + if (input.type !== 'file') { + // http://stackoverflow.com/a/2345915 + const val = input.value; + input.value = ''; + input.value = val; + } + }; + + /** + * @param {HTMLElement | HTMLElement[] | null} target + * @param {string | string[] | readonly string[] | undefined} classList + * @param {boolean} condition + */ + const toggleClass = (target, classList, condition) => { + if (!target || !classList) { + return; + } + if (typeof classList === 'string') { + classList = classList.split(/\s+/).filter(Boolean); + } + classList.forEach(className => { + if (Array.isArray(target)) { + target.forEach(elem => { + condition ? elem.classList.add(className) : elem.classList.remove(className); + }); + } else { + condition ? target.classList.add(className) : target.classList.remove(className); + } + }); + }; + + /** + * @param {HTMLElement | HTMLElement[] | null} target + * @param {string | string[] | readonly string[] | undefined} classList + */ + const addClass = (target, classList) => { + toggleClass(target, classList, true); + }; + + /** + * @param {HTMLElement | HTMLElement[] | null} target + * @param {string | string[] | readonly string[] | undefined} classList + */ + const removeClass = (target, classList) => { + toggleClass(target, classList, false); + }; + + /** + * Get direct child of an element by class name + * + * @param {HTMLElement} elem + * @param {string} className + * @returns {HTMLElement | undefined} + */ + const getDirectChildByClass = (elem, className) => { + const children = Array.from(elem.children); + for (let i = 0; i < children.length; i++) { + const child = children[i]; + if (child instanceof HTMLElement && hasClass(child, className)) { + return child; + } + } + }; + + /** + * @param {HTMLElement} elem + * @param {string} property + * @param {*} value + */ + const applyNumericalStyle = (elem, property, value) => { + if (value === "".concat(parseInt(value))) { + value = parseInt(value); + } + if (value || parseInt(value) === 0) { + elem.style[property] = typeof value === 'number' ? "".concat(value, "px") : value; + } else { + elem.style.removeProperty(property); + } + }; + + /** + * @param {HTMLElement | null} elem + * @param {string} display + */ + const show = function (elem) { + let display = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'flex'; + elem && (elem.style.display = display); + }; + + /** + * @param {HTMLElement | null} elem + */ + const hide = elem => { + elem && (elem.style.display = 'none'); + }; + + /** + * @param {HTMLElement | null} elem + * @param {string} display + */ + const showWhenInnerHtmlPresent = function (elem) { + let display = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'block'; + if (!elem) { + return; + } + new MutationObserver(() => { + toggle(elem, elem.innerHTML, display); + }).observe(elem, { + childList: true, + subtree: true + }); + }; + + /** + * @param {HTMLElement} parent + * @param {string} selector + * @param {string} property + * @param {string} value + */ + const setStyle = (parent, selector, property, value) => { + /** @type {HTMLElement} */ + const el = parent.querySelector(selector); + if (el) { + el.style[property] = value; + } + }; + + /** + * @param {HTMLElement} elem + * @param {any} condition + * @param {string} display + */ + const toggle = function (elem, condition) { + let display = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'flex'; + condition ? show(elem, display) : hide(elem); + }; + + /** + * borrowed from jquery $(elem).is(':visible') implementation + * + * @param {HTMLElement | null} elem + * @returns {boolean} + */ + const isVisible$1 = elem => !!(elem && (elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length)); + + /** + * @returns {boolean} + */ + const allButtonsAreHidden = () => !isVisible$1(getConfirmButton()) && !isVisible$1(getDenyButton()) && !isVisible$1(getCancelButton()); + + /** + * @param {HTMLElement} elem + * @returns {boolean} + */ + const isScrollable = elem => !!(elem.scrollHeight > elem.clientHeight); + + /** + * borrowed from https://stackoverflow.com/a/46352119 + * + * @param {HTMLElement} elem + * @returns {boolean} + */ + const hasCssAnimation = elem => { + const style = window.getComputedStyle(elem); + const animDuration = parseFloat(style.getPropertyValue('animation-duration') || '0'); + const transDuration = parseFloat(style.getPropertyValue('transition-duration') || '0'); + return animDuration > 0 || transDuration > 0; + }; + + /** + * @param {number} timer + * @param {boolean} reset + */ + const animateTimerProgressBar = function (timer) { + let reset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + const timerProgressBar = getTimerProgressBar(); + if (!timerProgressBar) { + return; + } + if (isVisible$1(timerProgressBar)) { + if (reset) { + timerProgressBar.style.transition = 'none'; + timerProgressBar.style.width = '100%'; + } + setTimeout(() => { + timerProgressBar.style.transition = "width ".concat(timer / 1000, "s linear"); + timerProgressBar.style.width = '0%'; + }, 10); + } + }; + const stopTimerProgressBar = () => { + const timerProgressBar = getTimerProgressBar(); + if (!timerProgressBar) { + return; + } + const timerProgressBarWidth = parseInt(window.getComputedStyle(timerProgressBar).width); + timerProgressBar.style.removeProperty('transition'); + timerProgressBar.style.width = '100%'; + const timerProgressBarFullWidth = parseInt(window.getComputedStyle(timerProgressBar).width); + const timerProgressBarPercent = timerProgressBarWidth / timerProgressBarFullWidth * 100; + timerProgressBar.style.width = "".concat(timerProgressBarPercent, "%"); + }; + + /** + * Detect Node env + * + * @returns {boolean} + */ + const isNodeEnv = () => typeof window === 'undefined' || typeof document === 'undefined'; + + /** + * @returns {boolean} + */ + const resetOldContainer = () => { + const oldContainer = getContainer(); + if (!oldContainer) { + return false; + } + oldContainer.remove(); + removeClass([document.documentElement, document.body], [swalClasses['no-backdrop'], swalClasses['toast-shown'], swalClasses['has-column']]); + return true; + }; + const resetValidationMessage$1 = () => { + globalState.currentInstance.resetValidationMessage(); + }; + const addInputChangeListeners = () => { + const popup = getPopup(); + const input = getDirectChildByClass(popup, swalClasses.input); + const file = getDirectChildByClass(popup, swalClasses.file); + /** @type {HTMLInputElement} */ + const range = popup.querySelector(".".concat(swalClasses.range, " input")); + /** @type {HTMLOutputElement} */ + const rangeOutput = popup.querySelector(".".concat(swalClasses.range, " output")); + const select = getDirectChildByClass(popup, swalClasses.select); + /** @type {HTMLInputElement} */ + const checkbox = popup.querySelector(".".concat(swalClasses.checkbox, " input")); + const textarea = getDirectChildByClass(popup, swalClasses.textarea); + input.oninput = resetValidationMessage$1; + file.onchange = resetValidationMessage$1; + select.onchange = resetValidationMessage$1; + checkbox.onchange = resetValidationMessage$1; + textarea.oninput = resetValidationMessage$1; + range.oninput = () => { + resetValidationMessage$1(); + rangeOutput.value = range.value; + }; + range.onchange = () => { + resetValidationMessage$1(); + rangeOutput.value = range.value; + }; + }; + + /** + * @param {string | HTMLElement} target + * @returns {HTMLElement} + */ + const getTarget = target => typeof target === 'string' ? document.querySelector(target) : target; + + /** + * @param {SweetAlertOptions} params + */ + const setupAccessibility = params => { + const popup = getPopup(); + popup.setAttribute('role', params.toast ? 'alert' : 'dialog'); + popup.setAttribute('aria-live', params.toast ? 'polite' : 'assertive'); + if (!params.toast) { + popup.setAttribute('aria-modal', 'true'); + } + }; + + /** + * @param {HTMLElement} targetElement + */ + const setupRTL = targetElement => { + if (window.getComputedStyle(targetElement).direction === 'rtl') { + addClass(getContainer(), swalClasses.rtl); + } + }; + + /** + * @param {HTMLElement | object | string} param + * @param {HTMLElement} target + */ + const parseHtmlToContainer = (param, target) => { + // DOM element + if (param instanceof HTMLElement) { + target.appendChild(param); + } + + // Object + else if (typeof param === 'object') { + handleObject(param, target); + } + + // Plain string + else if (param) { + setInnerHtml(target, param); + } + }; + + /** + * @param {any} param + * @param {HTMLElement} target + */ + const handleObject = (param, target) => { + // JQuery element(s) + if (param.jquery) { + handleJqueryElem(target, param); + } + + // For other objects use their string representation + else { + setInnerHtml(target, param.toString()); + } + }; + + /** + * @param {HTMLElement} target + * @param {any} elem + */ + const handleJqueryElem = (target, elem) => { + target.textContent = ''; + if (0 in elem) { + for (let i = 0; (i in elem); i++) { + target.appendChild(elem[i].cloneNode(true)); + } + } else { + target.appendChild(elem.cloneNode(true)); + } + }; + + /** + * @returns {'webkitAnimationEnd' | 'animationend' | false} + */ + const animationEndEvent = (() => { + // Prevent run in Node env + if (isNodeEnv()) { + return false; + } + const testEl = document.createElement('div'); + + // Chrome, Safari and Opera + if (typeof testEl.style.webkitAnimation !== 'undefined') { + return 'webkitAnimationEnd'; + } + + // Standard syntax + if (typeof testEl.style.animation !== 'undefined') { + return 'animationend'; + } + return false; + })(); + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const renderActions = (instance, params) => { + const actions = getActions(); + const loader = getLoader(); + if (!actions || !loader) { + return; + } + + // Actions (buttons) wrapper + if (!params.showConfirmButton && !params.showDenyButton && !params.showCancelButton) { + hide(actions); + } else { + show(actions); + } + + // Custom class + applyCustomClass(actions, params, 'actions'); + + // Render all the buttons + renderButtons(actions, loader, params); + + // Loader + setInnerHtml(loader, params.loaderHtml || ''); + applyCustomClass(loader, params, 'loader'); + }; + + /** + * @param {HTMLElement} actions + * @param {HTMLElement} loader + * @param {SweetAlertOptions} params + */ + function renderButtons(actions, loader, params) { + const confirmButton = getConfirmButton(); + const denyButton = getDenyButton(); + const cancelButton = getCancelButton(); + if (!confirmButton || !denyButton || !cancelButton) { + return; + } + + // Render buttons + renderButton(confirmButton, 'confirm', params); + renderButton(denyButton, 'deny', params); + renderButton(cancelButton, 'cancel', params); + handleButtonsStyling(confirmButton, denyButton, cancelButton, params); + if (params.reverseButtons) { + if (params.toast) { + actions.insertBefore(cancelButton, confirmButton); + actions.insertBefore(denyButton, confirmButton); + } else { + actions.insertBefore(cancelButton, loader); + actions.insertBefore(denyButton, loader); + actions.insertBefore(confirmButton, loader); + } + } + } + + /** + * @param {HTMLElement} confirmButton + * @param {HTMLElement} denyButton + * @param {HTMLElement} cancelButton + * @param {SweetAlertOptions} params + */ + function handleButtonsStyling(confirmButton, denyButton, cancelButton, params) { + if (!params.buttonsStyling) { + removeClass([confirmButton, denyButton, cancelButton], swalClasses.styled); + return; + } + addClass([confirmButton, denyButton, cancelButton], swalClasses.styled); + + // Buttons background colors + if (params.confirmButtonColor) { + confirmButton.style.backgroundColor = params.confirmButtonColor; + addClass(confirmButton, swalClasses['default-outline']); + } + if (params.denyButtonColor) { + denyButton.style.backgroundColor = params.denyButtonColor; + addClass(denyButton, swalClasses['default-outline']); + } + if (params.cancelButtonColor) { + cancelButton.style.backgroundColor = params.cancelButtonColor; + addClass(cancelButton, swalClasses['default-outline']); + } + } + + /** + * @param {HTMLElement} button + * @param {'confirm' | 'deny' | 'cancel'} buttonType + * @param {SweetAlertOptions} params + */ + function renderButton(button, buttonType, params) { + const buttonName = /** @type {'Confirm' | 'Deny' | 'Cancel'} */capitalizeFirstLetter(buttonType); + toggle(button, params["show".concat(buttonName, "Button")], 'inline-block'); + setInnerHtml(button, params["".concat(buttonType, "ButtonText")] || ''); // Set caption text + button.setAttribute('aria-label', params["".concat(buttonType, "ButtonAriaLabel")] || ''); // ARIA label + + // Add buttons custom classes + button.className = swalClasses[buttonType]; + applyCustomClass(button, params, "".concat(buttonType, "Button")); + } + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const renderCloseButton = (instance, params) => { + const closeButton = getCloseButton(); + if (!closeButton) { + return; + } + setInnerHtml(closeButton, params.closeButtonHtml || ''); + + // Custom class + applyCustomClass(closeButton, params, 'closeButton'); + toggle(closeButton, params.showCloseButton); + closeButton.setAttribute('aria-label', params.closeButtonAriaLabel || ''); + }; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const renderContainer = (instance, params) => { + const container = getContainer(); + if (!container) { + return; + } + handleBackdropParam(container, params.backdrop); + handlePositionParam(container, params.position); + handleGrowParam(container, params.grow); + + // Custom class + applyCustomClass(container, params, 'container'); + }; + + /** + * @param {HTMLElement} container + * @param {SweetAlertOptions['backdrop']} backdrop + */ + function handleBackdropParam(container, backdrop) { + if (typeof backdrop === 'string') { + container.style.background = backdrop; + } else if (!backdrop) { + addClass([document.documentElement, document.body], swalClasses['no-backdrop']); + } + } + + /** + * @param {HTMLElement} container + * @param {SweetAlertOptions['position']} position + */ + function handlePositionParam(container, position) { + if (!position) { + return; + } + if (position in swalClasses) { + addClass(container, swalClasses[position]); + } else { + warn('The "position" parameter is not valid, defaulting to "center"'); + addClass(container, swalClasses.center); + } + } + + /** + * @param {HTMLElement} container + * @param {SweetAlertOptions['grow']} grow + */ + function handleGrowParam(container, grow) { + if (!grow) { + return; + } + addClass(container, swalClasses["grow-".concat(grow)]); + } + + /** + * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has. + * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')` + * This is the approach that Babel will probably take to implement private methods/fields + * https://github.com/tc39/proposal-private-methods + * https://github.com/babel/babel/pull/7555 + * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module* + * then we can use that language feature. + */ + + var privateProps = { + innerParams: new WeakMap(), + domCache: new WeakMap() + }; + + /// + + + /** @type {InputClass[]} */ + const inputClasses = ['input', 'file', 'range', 'select', 'radio', 'checkbox', 'textarea']; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const renderInput = (instance, params) => { + const popup = getPopup(); + if (!popup) { + return; + } + const innerParams = privateProps.innerParams.get(instance); + const rerender = !innerParams || params.input !== innerParams.input; + inputClasses.forEach(inputClass => { + const inputContainer = getDirectChildByClass(popup, swalClasses[inputClass]); + if (!inputContainer) { + return; + } + + // set attributes + setAttributes(inputClass, params.inputAttributes); + + // set class + inputContainer.className = swalClasses[inputClass]; + if (rerender) { + hide(inputContainer); + } + }); + if (params.input) { + if (rerender) { + showInput(params); + } + // set custom class + setCustomClass(params); + } + }; + + /** + * @param {SweetAlertOptions} params + */ + const showInput = params => { + if (!params.input) { + return; + } + if (!renderInputType[params.input]) { + error("Unexpected type of input! Expected ".concat(Object.keys(renderInputType).join(' | '), ", got \"").concat(params.input, "\"")); + return; + } + const inputContainer = getInputContainer(params.input); + const input = renderInputType[params.input](inputContainer, params); + show(inputContainer); + + // input autofocus + if (params.inputAutoFocus) { + setTimeout(() => { + focusInput(input); + }); + } + }; + + /** + * @param {HTMLInputElement} input + */ + const removeAttributes = input => { + for (let i = 0; i < input.attributes.length; i++) { + const attrName = input.attributes[i].name; + if (!['id', 'type', 'value', 'style'].includes(attrName)) { + input.removeAttribute(attrName); + } + } + }; + + /** + * @param {InputClass} inputClass + * @param {SweetAlertOptions['inputAttributes']} inputAttributes + */ + const setAttributes = (inputClass, inputAttributes) => { + const input = getInput$1(getPopup(), inputClass); + if (!input) { + return; + } + removeAttributes(input); + for (const attr in inputAttributes) { + input.setAttribute(attr, inputAttributes[attr]); + } + }; + + /** + * @param {SweetAlertOptions} params + */ + const setCustomClass = params => { + const inputContainer = getInputContainer(params.input); + if (typeof params.customClass === 'object') { + addClass(inputContainer, params.customClass.input); + } + }; + + /** + * @param {HTMLInputElement | HTMLTextAreaElement} input + * @param {SweetAlertOptions} params + */ + const setInputPlaceholder = (input, params) => { + if (!input.placeholder || params.inputPlaceholder) { + input.placeholder = params.inputPlaceholder; + } + }; + + /** + * @param {Input} input + * @param {Input} prependTo + * @param {SweetAlertOptions} params + */ + const setInputLabel = (input, prependTo, params) => { + if (params.inputLabel) { + const label = document.createElement('label'); + const labelClass = swalClasses['input-label']; + label.setAttribute('for', input.id); + label.className = labelClass; + if (typeof params.customClass === 'object') { + addClass(label, params.customClass.inputLabel); + } + label.innerText = params.inputLabel; + prependTo.insertAdjacentElement('beforebegin', label); + } + }; + + /** + * @param {SweetAlertOptions['input']} inputType + * @returns {HTMLElement} + */ + const getInputContainer = inputType => { + return getDirectChildByClass(getPopup(), swalClasses[inputType] || swalClasses.input); + }; + + /** + * @param {HTMLInputElement | HTMLOutputElement | HTMLTextAreaElement} input + * @param {SweetAlertOptions['inputValue']} inputValue + */ + const checkAndSetInputValue = (input, inputValue) => { + if (['string', 'number'].includes(typeof inputValue)) { + input.value = "".concat(inputValue); + } else if (!isPromise(inputValue)) { + warn("Unexpected type of inputValue! Expected \"string\", \"number\" or \"Promise\", got \"".concat(typeof inputValue, "\"")); + } + }; + + /** @type {Record Input>} */ + const renderInputType = {}; + + /** + * @param {HTMLInputElement} input + * @param {SweetAlertOptions} params + * @returns {HTMLInputElement} + */ + renderInputType.text = renderInputType.email = renderInputType.password = renderInputType.number = renderInputType.tel = renderInputType.url = renderInputType.search = renderInputType.date = renderInputType['datetime-local'] = renderInputType.time = renderInputType.week = renderInputType.month = (input, params) => { + checkAndSetInputValue(input, params.inputValue); + setInputLabel(input, input, params); + setInputPlaceholder(input, params); + input.type = params.input; + return input; + }; + + /** + * @param {HTMLInputElement} input + * @param {SweetAlertOptions} params + * @returns {HTMLInputElement} + */ + renderInputType.file = (input, params) => { + setInputLabel(input, input, params); + setInputPlaceholder(input, params); + return input; + }; + + /** + * @param {HTMLInputElement} range + * @param {SweetAlertOptions} params + * @returns {HTMLInputElement} + */ + renderInputType.range = (range, params) => { + const rangeInput = range.querySelector('input'); + const rangeOutput = range.querySelector('output'); + checkAndSetInputValue(rangeInput, params.inputValue); + rangeInput.type = params.input; + checkAndSetInputValue(rangeOutput, params.inputValue); + setInputLabel(rangeInput, range, params); + return range; + }; + + /** + * @param {HTMLSelectElement} select + * @param {SweetAlertOptions} params + * @returns {HTMLSelectElement} + */ + renderInputType.select = (select, params) => { + select.textContent = ''; + if (params.inputPlaceholder) { + const placeholder = document.createElement('option'); + setInnerHtml(placeholder, params.inputPlaceholder); + placeholder.value = ''; + placeholder.disabled = true; + placeholder.selected = true; + select.appendChild(placeholder); + } + setInputLabel(select, select, params); + return select; + }; + + /** + * @param {HTMLInputElement} radio + * @returns {HTMLInputElement} + */ + renderInputType.radio = radio => { + radio.textContent = ''; + return radio; + }; + + /** + * @param {HTMLLabelElement} checkboxContainer + * @param {SweetAlertOptions} params + * @returns {HTMLInputElement} + */ + renderInputType.checkbox = (checkboxContainer, params) => { + const checkbox = getInput$1(getPopup(), 'checkbox'); + checkbox.value = '1'; + checkbox.checked = Boolean(params.inputValue); + const label = checkboxContainer.querySelector('span'); + setInnerHtml(label, params.inputPlaceholder); + return checkbox; + }; + + /** + * @param {HTMLTextAreaElement} textarea + * @param {SweetAlertOptions} params + * @returns {HTMLTextAreaElement} + */ + renderInputType.textarea = (textarea, params) => { + checkAndSetInputValue(textarea, params.inputValue); + setInputPlaceholder(textarea, params); + setInputLabel(textarea, textarea, params); + + /** + * @param {HTMLElement} el + * @returns {number} + */ + const getMargin = el => parseInt(window.getComputedStyle(el).marginLeft) + parseInt(window.getComputedStyle(el).marginRight); + + // https://github.com/sweetalert2/sweetalert2/issues/2291 + setTimeout(() => { + // https://github.com/sweetalert2/sweetalert2/issues/1699 + if ('MutationObserver' in window) { + const initialPopupWidth = parseInt(window.getComputedStyle(getPopup()).width); + const textareaResizeHandler = () => { + // check if texarea is still in document (i.e. popup wasn't closed in the meantime) + if (!document.body.contains(textarea)) { + return; + } + const textareaWidth = textarea.offsetWidth + getMargin(textarea); + if (textareaWidth > initialPopupWidth) { + getPopup().style.width = "".concat(textareaWidth, "px"); + } else { + applyNumericalStyle(getPopup(), 'width', params.width); + } + }; + new MutationObserver(textareaResizeHandler).observe(textarea, { + attributes: true, + attributeFilter: ['style'] + }); + } + }); + return textarea; + }; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const renderContent = (instance, params) => { + const htmlContainer = getHtmlContainer(); + if (!htmlContainer) { + return; + } + showWhenInnerHtmlPresent(htmlContainer); + applyCustomClass(htmlContainer, params, 'htmlContainer'); + + // Content as HTML + if (params.html) { + parseHtmlToContainer(params.html, htmlContainer); + show(htmlContainer, 'block'); + } + + // Content as plain text + else if (params.text) { + htmlContainer.textContent = params.text; + show(htmlContainer, 'block'); + } + + // No content + else { + hide(htmlContainer); + } + renderInput(instance, params); + }; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const renderFooter = (instance, params) => { + const footer = getFooter(); + if (!footer) { + return; + } + showWhenInnerHtmlPresent(footer); + toggle(footer, params.footer, 'block'); + if (params.footer) { + parseHtmlToContainer(params.footer, footer); + } + + // Custom class + applyCustomClass(footer, params, 'footer'); + }; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const renderIcon = (instance, params) => { + const innerParams = privateProps.innerParams.get(instance); + const icon = getIcon(); + if (!icon) { + return; + } + + // if the given icon already rendered, apply the styling without re-rendering the icon + if (innerParams && params.icon === innerParams.icon) { + // Custom or default content + setContent(icon, params); + applyStyles(icon, params); + return; + } + if (!params.icon && !params.iconHtml) { + hide(icon); + return; + } + if (params.icon && Object.keys(iconTypes).indexOf(params.icon) === -1) { + error("Unknown icon! Expected \"success\", \"error\", \"warning\", \"info\" or \"question\", got \"".concat(params.icon, "\"")); + hide(icon); + return; + } + show(icon); + + // Custom or default content + setContent(icon, params); + applyStyles(icon, params); + + // Animate icon + addClass(icon, params.showClass && params.showClass.icon); + }; + + /** + * @param {HTMLElement} icon + * @param {SweetAlertOptions} params + */ + const applyStyles = (icon, params) => { + for (const [iconType, iconClassName] of Object.entries(iconTypes)) { + if (params.icon !== iconType) { + removeClass(icon, iconClassName); + } + } + addClass(icon, params.icon && iconTypes[params.icon]); + + // Icon color + setColor(icon, params); + + // Success icon background color + adjustSuccessIconBackgroundColor(); + + // Custom class + applyCustomClass(icon, params, 'icon'); + }; + + // Adjust success icon background color to match the popup background color + const adjustSuccessIconBackgroundColor = () => { + const popup = getPopup(); + if (!popup) { + return; + } + const popupBackgroundColor = window.getComputedStyle(popup).getPropertyValue('background-color'); + /** @type {NodeListOf} */ + const successIconParts = popup.querySelectorAll('[class^=swal2-success-circular-line], .swal2-success-fix'); + for (let i = 0; i < successIconParts.length; i++) { + successIconParts[i].style.backgroundColor = popupBackgroundColor; + } + }; + const successIconHtml = "\n
\n \n
\n
\n"; + const errorIconHtml = "\n \n \n \n \n"; + + /** + * @param {HTMLElement} icon + * @param {SweetAlertOptions} params + */ + const setContent = (icon, params) => { + if (!params.icon && !params.iconHtml) { + return; + } + let oldContent = icon.innerHTML; + let newContent = ''; + if (params.iconHtml) { + newContent = iconContent(params.iconHtml); + } else if (params.icon === 'success') { + newContent = successIconHtml; + oldContent = oldContent.replace(/ style=".*?"/g, ''); // undo adjustSuccessIconBackgroundColor() + } else if (params.icon === 'error') { + newContent = errorIconHtml; + } else if (params.icon) { + const defaultIconHtml = { + question: '?', + warning: '!', + info: 'i' + }; + newContent = iconContent(defaultIconHtml[params.icon]); + } + if (oldContent.trim() !== newContent.trim()) { + setInnerHtml(icon, newContent); + } + }; + + /** + * @param {HTMLElement} icon + * @param {SweetAlertOptions} params + */ + const setColor = (icon, params) => { + if (!params.iconColor) { + return; + } + icon.style.color = params.iconColor; + icon.style.borderColor = params.iconColor; + for (const sel of ['.swal2-success-line-tip', '.swal2-success-line-long', '.swal2-x-mark-line-left', '.swal2-x-mark-line-right']) { + setStyle(icon, sel, 'backgroundColor', params.iconColor); + } + setStyle(icon, '.swal2-success-ring', 'borderColor', params.iconColor); + }; + + /** + * @param {string} content + * @returns {string} + */ + const iconContent = content => "
").concat(content, "
"); + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const renderImage = (instance, params) => { + const image = getImage(); + if (!image) { + return; + } + if (!params.imageUrl) { + hide(image); + return; + } + show(image, ''); + + // Src, alt + image.setAttribute('src', params.imageUrl); + image.setAttribute('alt', params.imageAlt || ''); + + // Width, height + applyNumericalStyle(image, 'width', params.imageWidth); + applyNumericalStyle(image, 'height', params.imageHeight); + + // Class + image.className = swalClasses.image; + applyCustomClass(image, params, 'image'); + }; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const renderPopup = (instance, params) => { + const container = getContainer(); + const popup = getPopup(); + if (!container || !popup) { + return; + } + + // Width + // https://github.com/sweetalert2/sweetalert2/issues/2170 + if (params.toast) { + applyNumericalStyle(container, 'width', params.width); + popup.style.width = '100%'; + const loader = getLoader(); + loader && popup.insertBefore(loader, getIcon()); + } else { + applyNumericalStyle(popup, 'width', params.width); + } + + // Padding + applyNumericalStyle(popup, 'padding', params.padding); + + // Color + if (params.color) { + popup.style.color = params.color; + } + + // Background + if (params.background) { + popup.style.background = params.background; + } + hide(getValidationMessage()); + + // Classes + addClasses$1(popup, params); + }; + + /** + * @param {HTMLElement} popup + * @param {SweetAlertOptions} params + */ + const addClasses$1 = (popup, params) => { + const showClass = params.showClass || {}; + // Default Class + showClass when updating Swal.update({}) + popup.className = "".concat(swalClasses.popup, " ").concat(isVisible$1(popup) ? showClass.popup : ''); + if (params.toast) { + addClass([document.documentElement, document.body], swalClasses['toast-shown']); + addClass(popup, swalClasses.toast); + } else { + addClass(popup, swalClasses.modal); + } + + // Custom class + applyCustomClass(popup, params, 'popup'); + if (typeof params.customClass === 'string') { + addClass(popup, params.customClass); + } + + // Icon class (#1842) + if (params.icon) { + addClass(popup, swalClasses["icon-".concat(params.icon)]); + } + }; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const renderProgressSteps = (instance, params) => { + const progressStepsContainer = getProgressSteps(); + if (!progressStepsContainer) { + return; + } + const { + progressSteps, + currentProgressStep + } = params; + if (!progressSteps || progressSteps.length === 0 || currentProgressStep === undefined) { + hide(progressStepsContainer); + return; + } + show(progressStepsContainer); + progressStepsContainer.textContent = ''; + if (currentProgressStep >= progressSteps.length) { + warn('Invalid currentProgressStep parameter, it should be less than progressSteps.length ' + '(currentProgressStep like JS arrays starts from 0)'); + } + progressSteps.forEach((step, index) => { + const stepEl = createStepElement(step); + progressStepsContainer.appendChild(stepEl); + if (index === currentProgressStep) { + addClass(stepEl, swalClasses['active-progress-step']); + } + if (index !== progressSteps.length - 1) { + const lineEl = createLineElement(params); + progressStepsContainer.appendChild(lineEl); + } + }); + }; + + /** + * @param {string} step + * @returns {HTMLLIElement} + */ + const createStepElement = step => { + const stepEl = document.createElement('li'); + addClass(stepEl, swalClasses['progress-step']); + setInnerHtml(stepEl, step); + return stepEl; + }; + + /** + * @param {SweetAlertOptions} params + * @returns {HTMLLIElement} + */ + const createLineElement = params => { + const lineEl = document.createElement('li'); + addClass(lineEl, swalClasses['progress-step-line']); + if (params.progressStepsDistance) { + applyNumericalStyle(lineEl, 'width', params.progressStepsDistance); + } + return lineEl; + }; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const renderTitle = (instance, params) => { + const title = getTitle(); + if (!title) { + return; + } + showWhenInnerHtmlPresent(title); + toggle(title, params.title || params.titleText, 'block'); + if (params.title) { + parseHtmlToContainer(params.title, title); + } + if (params.titleText) { + title.innerText = params.titleText; + } + + // Custom class + applyCustomClass(title, params, 'title'); + }; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const render = (instance, params) => { + renderPopup(instance, params); + renderContainer(instance, params); + renderProgressSteps(instance, params); + renderIcon(instance, params); + renderImage(instance, params); + renderTitle(instance, params); + renderCloseButton(instance, params); + renderContent(instance, params); + renderActions(instance, params); + renderFooter(instance, params); + const popup = getPopup(); + if (typeof params.didRender === 'function' && popup) { + params.didRender(popup); + } + }; + + /* + * Global function to determine if SweetAlert2 popup is shown + */ + const isVisible = () => { + return isVisible$1(getPopup()); + }; + + /* + * Global function to click 'Confirm' button + */ + const clickConfirm = () => { + var _dom$getConfirmButton; + return (_dom$getConfirmButton = getConfirmButton()) === null || _dom$getConfirmButton === void 0 ? void 0 : _dom$getConfirmButton.click(); + }; + + /* + * Global function to click 'Deny' button + */ + const clickDeny = () => { + var _dom$getDenyButton; + return (_dom$getDenyButton = getDenyButton()) === null || _dom$getDenyButton === void 0 ? void 0 : _dom$getDenyButton.click(); + }; + + /* + * Global function to click 'Cancel' button + */ + const clickCancel = () => { + var _dom$getCancelButton; + return (_dom$getCancelButton = getCancelButton()) === null || _dom$getCancelButton === void 0 ? void 0 : _dom$getCancelButton.click(); + }; + + /** @typedef {'cancel' | 'backdrop' | 'close' | 'esc' | 'timer'} DismissReason */ + + /** @type {Record} */ + const DismissReason = Object.freeze({ + cancel: 'cancel', + backdrop: 'backdrop', + close: 'close', + esc: 'esc', + timer: 'timer' + }); + + /** + * @param {GlobalState} globalState + */ + const removeKeydownHandler = globalState => { + if (globalState.keydownTarget && globalState.keydownHandlerAdded) { + globalState.keydownTarget.removeEventListener('keydown', globalState.keydownHandler, { + capture: globalState.keydownListenerCapture + }); + globalState.keydownHandlerAdded = false; + } + }; + + /** + * @param {GlobalState} globalState + * @param {SweetAlertOptions} innerParams + * @param {*} dismissWith + */ + const addKeydownHandler = (globalState, innerParams, dismissWith) => { + removeKeydownHandler(globalState); + if (!innerParams.toast) { + globalState.keydownHandler = e => keydownHandler(innerParams, e, dismissWith); + globalState.keydownTarget = innerParams.keydownListenerCapture ? window : getPopup(); + globalState.keydownListenerCapture = innerParams.keydownListenerCapture; + globalState.keydownTarget.addEventListener('keydown', globalState.keydownHandler, { + capture: globalState.keydownListenerCapture + }); + globalState.keydownHandlerAdded = true; + } + }; + + /** + * @param {number} index + * @param {number} increment + */ + const setFocus = (index, increment) => { + var _dom$getPopup; + const focusableElements = getFocusableElements(); + // search for visible elements and select the next possible match + if (focusableElements.length) { + index = index + increment; + + // rollover to first item + if (index === focusableElements.length) { + index = 0; + + // go to last item + } else if (index === -1) { + index = focusableElements.length - 1; + } + focusableElements[index].focus(); + return; + } + // no visible focusable elements, focus the popup + (_dom$getPopup = getPopup()) === null || _dom$getPopup === void 0 || _dom$getPopup.focus(); + }; + const arrowKeysNextButton = ['ArrowRight', 'ArrowDown']; + const arrowKeysPreviousButton = ['ArrowLeft', 'ArrowUp']; + + /** + * @param {SweetAlertOptions} innerParams + * @param {KeyboardEvent} event + * @param {Function} dismissWith + */ + const keydownHandler = (innerParams, event, dismissWith) => { + if (!innerParams) { + return; // This instance has already been destroyed + } + + // Ignore keydown during IME composition + // https://developer.mozilla.org/en-US/docs/Web/API/Document/keydown_event#ignoring_keydown_during_ime_composition + // https://github.com/sweetalert2/sweetalert2/issues/720 + // https://github.com/sweetalert2/sweetalert2/issues/2406 + if (event.isComposing || event.keyCode === 229) { + return; + } + if (innerParams.stopKeydownPropagation) { + event.stopPropagation(); + } + + // ENTER + if (event.key === 'Enter') { + handleEnter(event, innerParams); + } + + // TAB + else if (event.key === 'Tab') { + handleTab(event); + } + + // ARROWS - switch focus between buttons + else if ([...arrowKeysNextButton, ...arrowKeysPreviousButton].includes(event.key)) { + handleArrows(event.key); + } + + // ESC + else if (event.key === 'Escape') { + handleEsc(event, innerParams, dismissWith); + } + }; + + /** + * @param {KeyboardEvent} event + * @param {SweetAlertOptions} innerParams + */ + const handleEnter = (event, innerParams) => { + // https://github.com/sweetalert2/sweetalert2/issues/2386 + if (!callIfFunction(innerParams.allowEnterKey)) { + return; + } + const input = getInput$1(getPopup(), innerParams.input); + if (event.target && input && event.target instanceof HTMLElement && event.target.outerHTML === input.outerHTML) { + if (['textarea', 'file'].includes(innerParams.input)) { + return; // do not submit + } + + clickConfirm(); + event.preventDefault(); + } + }; + + /** + * @param {KeyboardEvent} event + */ + const handleTab = event => { + const targetElement = event.target; + const focusableElements = getFocusableElements(); + let btnIndex = -1; + for (let i = 0; i < focusableElements.length; i++) { + if (targetElement === focusableElements[i]) { + btnIndex = i; + break; + } + } + + // Cycle to the next button + if (!event.shiftKey) { + setFocus(btnIndex, 1); + } + + // Cycle to the prev button + else { + setFocus(btnIndex, -1); + } + event.stopPropagation(); + event.preventDefault(); + }; + + /** + * @param {string} key + */ + const handleArrows = key => { + const actions = getActions(); + const confirmButton = getConfirmButton(); + const denyButton = getDenyButton(); + const cancelButton = getCancelButton(); + if (!actions || !confirmButton || !denyButton || !cancelButton) { + return; + } + /** @type HTMLElement[] */ + const buttons = [confirmButton, denyButton, cancelButton]; + if (document.activeElement instanceof HTMLElement && !buttons.includes(document.activeElement)) { + return; + } + const sibling = arrowKeysNextButton.includes(key) ? 'nextElementSibling' : 'previousElementSibling'; + let buttonToFocus = document.activeElement; + if (!buttonToFocus) { + return; + } + for (let i = 0; i < actions.children.length; i++) { + buttonToFocus = buttonToFocus[sibling]; + if (!buttonToFocus) { + return; + } + if (buttonToFocus instanceof HTMLButtonElement && isVisible$1(buttonToFocus)) { + break; + } + } + if (buttonToFocus instanceof HTMLButtonElement) { + buttonToFocus.focus(); + } + }; + + /** + * @param {KeyboardEvent} event + * @param {SweetAlertOptions} innerParams + * @param {Function} dismissWith + */ + const handleEsc = (event, innerParams, dismissWith) => { + if (callIfFunction(innerParams.allowEscapeKey)) { + event.preventDefault(); + dismissWith(DismissReason.esc); + } + }; + + /** + * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has. + * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')` + * This is the approach that Babel will probably take to implement private methods/fields + * https://github.com/tc39/proposal-private-methods + * https://github.com/babel/babel/pull/7555 + * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module* + * then we can use that language feature. + */ + + var privateMethods = { + swalPromiseResolve: new WeakMap(), + swalPromiseReject: new WeakMap() + }; + + // From https://developer.paciellogroup.com/blog/2018/06/the-current-state-of-modal-dialog-accessibility/ + // Adding aria-hidden="true" to elements outside of the active modal dialog ensures that + // elements not within the active modal dialog will not be surfaced if a user opens a screen + // reader’s list of elements (headings, form controls, landmarks, etc.) in the document. + + const setAriaHidden = () => { + const bodyChildren = Array.from(document.body.children); + bodyChildren.forEach(el => { + if (el === getContainer() || el.contains(getContainer())) { + return; + } + if (el.hasAttribute('aria-hidden')) { + el.setAttribute('data-previous-aria-hidden', el.getAttribute('aria-hidden') || ''); + } + el.setAttribute('aria-hidden', 'true'); + }); + }; + const unsetAriaHidden = () => { + const bodyChildren = Array.from(document.body.children); + bodyChildren.forEach(el => { + if (el.hasAttribute('data-previous-aria-hidden')) { + el.setAttribute('aria-hidden', el.getAttribute('data-previous-aria-hidden') || ''); + el.removeAttribute('data-previous-aria-hidden'); + } else { + el.removeAttribute('aria-hidden'); + } + }); + }; + + // @ts-ignore + const isSafariOrIOS = typeof window !== 'undefined' && !!window.GestureEvent; // true for Safari desktop + all iOS browsers https://stackoverflow.com/a/70585394 + + /** + * Fix iOS scrolling + * http://stackoverflow.com/q/39626302 + */ + const iOSfix = () => { + if (isSafariOrIOS && !hasClass(document.body, swalClasses.iosfix)) { + const offset = document.body.scrollTop; + document.body.style.top = "".concat(offset * -1, "px"); + addClass(document.body, swalClasses.iosfix); + lockBodyScroll(); + } + }; + + /** + * https://github.com/sweetalert2/sweetalert2/issues/1246 + */ + const lockBodyScroll = () => { + const container = getContainer(); + if (!container) { + return; + } + /** @type {boolean} */ + let preventTouchMove; + /** + * @param {TouchEvent} event + */ + container.ontouchstart = event => { + preventTouchMove = shouldPreventTouchMove(event); + }; + /** + * @param {TouchEvent} event + */ + container.ontouchmove = event => { + if (preventTouchMove) { + event.preventDefault(); + event.stopPropagation(); + } + }; + }; + + /** + * @param {TouchEvent} event + * @returns {boolean} + */ + const shouldPreventTouchMove = event => { + const target = event.target; + const container = getContainer(); + const htmlContainer = getHtmlContainer(); + if (!container || !htmlContainer) { + return false; + } + if (isStylus(event) || isZoom(event)) { + return false; + } + if (target === container) { + return true; + } + if (!isScrollable(container) && target instanceof HTMLElement && target.tagName !== 'INPUT' && + // #1603 + target.tagName !== 'TEXTAREA' && + // #2266 + !(isScrollable(htmlContainer) && + // #1944 + htmlContainer.contains(target))) { + return true; + } + return false; + }; + + /** + * https://github.com/sweetalert2/sweetalert2/issues/1786 + * + * @param {*} event + * @returns {boolean} + */ + const isStylus = event => { + return event.touches && event.touches.length && event.touches[0].touchType === 'stylus'; + }; + + /** + * https://github.com/sweetalert2/sweetalert2/issues/1891 + * + * @param {TouchEvent} event + * @returns {boolean} + */ + const isZoom = event => { + return event.touches && event.touches.length > 1; + }; + const undoIOSfix = () => { + if (hasClass(document.body, swalClasses.iosfix)) { + const offset = parseInt(document.body.style.top, 10); + removeClass(document.body, swalClasses.iosfix); + document.body.style.top = ''; + document.body.scrollTop = offset * -1; + } + }; + + /** + * Measure scrollbar width for padding body during modal show/hide + * https://github.com/twbs/bootstrap/blob/master/js/src/modal.js + * + * @returns {number} + */ + const measureScrollbar = () => { + const scrollDiv = document.createElement('div'); + scrollDiv.className = swalClasses['scrollbar-measure']; + document.body.appendChild(scrollDiv); + const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth; + document.body.removeChild(scrollDiv); + return scrollbarWidth; + }; + + /** + * Remember state in cases where opening and handling a modal will fiddle with it. + * @type {number | null} + */ + let previousBodyPadding = null; + + /** + * @param {string} initialBodyOverflow + */ + const replaceScrollbarWithPadding = initialBodyOverflow => { + // for queues, do not do this more than once + if (previousBodyPadding !== null) { + return; + } + // if the body has overflow + if (document.body.scrollHeight > window.innerHeight || initialBodyOverflow === 'scroll' // https://github.com/sweetalert2/sweetalert2/issues/2663 + ) { + // add padding so the content doesn't shift after removal of scrollbar + previousBodyPadding = parseInt(window.getComputedStyle(document.body).getPropertyValue('padding-right')); + document.body.style.paddingRight = "".concat(previousBodyPadding + measureScrollbar(), "px"); + } + }; + const undoReplaceScrollbarWithPadding = () => { + if (previousBodyPadding !== null) { + document.body.style.paddingRight = "".concat(previousBodyPadding, "px"); + previousBodyPadding = null; + } + }; + + /** + * @param {SweetAlert} instance + * @param {HTMLElement} container + * @param {boolean} returnFocus + * @param {Function} didClose + */ + function removePopupAndResetState(instance, container, returnFocus, didClose) { + if (isToast()) { + triggerDidCloseAndDispose(instance, didClose); + } else { + restoreActiveElement(returnFocus).then(() => triggerDidCloseAndDispose(instance, didClose)); + removeKeydownHandler(globalState); + } + + // workaround for https://github.com/sweetalert2/sweetalert2/issues/2088 + // for some reason removing the container in Safari will scroll the document to bottom + if (isSafariOrIOS) { + container.setAttribute('style', 'display:none !important'); + container.removeAttribute('class'); + container.innerHTML = ''; + } else { + container.remove(); + } + if (isModal()) { + undoReplaceScrollbarWithPadding(); + undoIOSfix(); + unsetAriaHidden(); + } + removeBodyClasses(); + } + + /** + * Remove SweetAlert2 classes from body + */ + function removeBodyClasses() { + removeClass([document.documentElement, document.body], [swalClasses.shown, swalClasses['height-auto'], swalClasses['no-backdrop'], swalClasses['toast-shown']]); + } + + /** + * Instance method to close sweetAlert + * + * @param {any} resolveValue + */ + function close(resolveValue) { + resolveValue = prepareResolveValue(resolveValue); + const swalPromiseResolve = privateMethods.swalPromiseResolve.get(this); + const didClose = triggerClosePopup(this); + if (this.isAwaitingPromise) { + // A swal awaiting for a promise (after a click on Confirm or Deny) cannot be dismissed anymore #2335 + if (!resolveValue.isDismissed) { + handleAwaitingPromise(this); + swalPromiseResolve(resolveValue); + } + } else if (didClose) { + // Resolve Swal promise + swalPromiseResolve(resolveValue); + } + } + const triggerClosePopup = instance => { + const popup = getPopup(); + if (!popup) { + return false; + } + const innerParams = privateProps.innerParams.get(instance); + if (!innerParams || hasClass(popup, innerParams.hideClass.popup)) { + return false; + } + removeClass(popup, innerParams.showClass.popup); + addClass(popup, innerParams.hideClass.popup); + const backdrop = getContainer(); + removeClass(backdrop, innerParams.showClass.backdrop); + addClass(backdrop, innerParams.hideClass.backdrop); + handlePopupAnimation(instance, popup, innerParams); + return true; + }; + + /** + * @param {any} error + */ + function rejectPromise(error) { + const rejectPromise = privateMethods.swalPromiseReject.get(this); + handleAwaitingPromise(this); + if (rejectPromise) { + // Reject Swal promise + rejectPromise(error); + } + } + + /** + * @param {SweetAlert} instance + */ + const handleAwaitingPromise = instance => { + if (instance.isAwaitingPromise) { + delete instance.isAwaitingPromise; + // The instance might have been previously partly destroyed, we must resume the destroy process in this case #2335 + if (!privateProps.innerParams.get(instance)) { + instance._destroy(); + } + } + }; + + /** + * @param {any} resolveValue + * @returns {SweetAlertResult} + */ + const prepareResolveValue = resolveValue => { + // When user calls Swal.close() + if (typeof resolveValue === 'undefined') { + return { + isConfirmed: false, + isDenied: false, + isDismissed: true + }; + } + return Object.assign({ + isConfirmed: false, + isDenied: false, + isDismissed: false + }, resolveValue); + }; + + /** + * @param {SweetAlert} instance + * @param {HTMLElement} popup + * @param {SweetAlertOptions} innerParams + */ + const handlePopupAnimation = (instance, popup, innerParams) => { + const container = getContainer(); + // If animation is supported, animate + const animationIsSupported = animationEndEvent && hasCssAnimation(popup); + if (typeof innerParams.willClose === 'function') { + innerParams.willClose(popup); + } + if (animationIsSupported) { + animatePopup(instance, popup, container, innerParams.returnFocus, innerParams.didClose); + } else { + // Otherwise, remove immediately + removePopupAndResetState(instance, container, innerParams.returnFocus, innerParams.didClose); + } + }; + + /** + * @param {SweetAlert} instance + * @param {HTMLElement} popup + * @param {HTMLElement} container + * @param {boolean} returnFocus + * @param {Function} didClose + */ + const animatePopup = (instance, popup, container, returnFocus, didClose) => { + if (!animationEndEvent) { + return; + } + globalState.swalCloseEventFinishedCallback = removePopupAndResetState.bind(null, instance, container, returnFocus, didClose); + popup.addEventListener(animationEndEvent, function (e) { + if (e.target === popup) { + globalState.swalCloseEventFinishedCallback(); + delete globalState.swalCloseEventFinishedCallback; + } + }); + }; + + /** + * @param {SweetAlert} instance + * @param {Function} didClose + */ + const triggerDidCloseAndDispose = (instance, didClose) => { + setTimeout(() => { + if (typeof didClose === 'function') { + didClose.bind(instance.params)(); + } + // instance might have been destroyed already + if (instance._destroy) { + instance._destroy(); + } + }); + }; + + /** + * Shows loader (spinner), this is useful with AJAX requests. + * By default the loader be shown instead of the "Confirm" button. + * + * @param {HTMLButtonElement | null} [buttonToReplace] + */ + const showLoading = buttonToReplace => { + let popup = getPopup(); + if (!popup) { + new Swal(); // eslint-disable-line no-new + } + + popup = getPopup(); + if (!popup) { + return; + } + const loader = getLoader(); + if (isToast()) { + hide(getIcon()); + } else { + replaceButton(popup, buttonToReplace); + } + show(loader); + popup.setAttribute('data-loading', 'true'); + popup.setAttribute('aria-busy', 'true'); + popup.focus(); + }; + + /** + * @param {HTMLElement} popup + * @param {HTMLButtonElement | null} [buttonToReplace] + */ + const replaceButton = (popup, buttonToReplace) => { + const actions = getActions(); + const loader = getLoader(); + if (!actions || !loader) { + return; + } + if (!buttonToReplace && isVisible$1(getConfirmButton())) { + buttonToReplace = getConfirmButton(); + } + show(actions); + if (buttonToReplace) { + hide(buttonToReplace); + loader.setAttribute('data-button-to-replace', buttonToReplace.className); + actions.insertBefore(loader, buttonToReplace); + } + addClass([popup, actions], swalClasses.loading); + }; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const handleInputOptionsAndValue = (instance, params) => { + if (params.input === 'select' || params.input === 'radio') { + handleInputOptions(instance, params); + } else if (['text', 'email', 'number', 'tel', 'textarea'].some(i => i === params.input) && (hasToPromiseFn(params.inputValue) || isPromise(params.inputValue))) { + showLoading(getConfirmButton()); + handleInputValue(instance, params); + } + }; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} innerParams + * @returns {SweetAlertInputValue} + */ + const getInputValue = (instance, innerParams) => { + const input = instance.getInput(); + if (!input) { + return null; + } + switch (innerParams.input) { + case 'checkbox': + return getCheckboxValue(input); + case 'radio': + return getRadioValue(input); + case 'file': + return getFileValue(input); + default: + return innerParams.inputAutoTrim ? input.value.trim() : input.value; + } + }; + + /** + * @param {HTMLInputElement} input + * @returns {number} + */ + const getCheckboxValue = input => input.checked ? 1 : 0; + + /** + * @param {HTMLInputElement} input + * @returns {string | null} + */ + const getRadioValue = input => input.checked ? input.value : null; + + /** + * @param {HTMLInputElement} input + * @returns {FileList | File | null} + */ + const getFileValue = input => input.files && input.files.length ? input.getAttribute('multiple') !== null ? input.files : input.files[0] : null; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const handleInputOptions = (instance, params) => { + const popup = getPopup(); + if (!popup) { + return; + } + /** + * @param {Record} inputOptions + */ + const processInputOptions = inputOptions => { + if (params.input === 'select') { + populateSelectOptions(popup, formatInputOptions(inputOptions), params); + } else if (params.input === 'radio') { + populateRadioOptions(popup, formatInputOptions(inputOptions), params); + } + }; + if (hasToPromiseFn(params.inputOptions) || isPromise(params.inputOptions)) { + showLoading(getConfirmButton()); + asPromise(params.inputOptions).then(inputOptions => { + instance.hideLoading(); + processInputOptions(inputOptions); + }); + } else if (typeof params.inputOptions === 'object') { + processInputOptions(params.inputOptions); + } else { + error("Unexpected type of inputOptions! Expected object, Map or Promise, got ".concat(typeof params.inputOptions)); + } + }; + + /** + * @param {SweetAlert} instance + * @param {SweetAlertOptions} params + */ + const handleInputValue = (instance, params) => { + const input = instance.getInput(); + if (!input) { + return; + } + hide(input); + asPromise(params.inputValue).then(inputValue => { + input.value = params.input === 'number' ? "".concat(parseFloat(inputValue) || 0) : "".concat(inputValue); + show(input); + input.focus(); + instance.hideLoading(); + }).catch(err => { + error("Error in inputValue promise: ".concat(err)); + input.value = ''; + show(input); + input.focus(); + instance.hideLoading(); + }); + }; + + /** + * @param {HTMLElement} popup + * @param {InputOptionFlattened[]} inputOptions + * @param {SweetAlertOptions} params + */ + function populateSelectOptions(popup, inputOptions, params) { + const select = getDirectChildByClass(popup, swalClasses.select); + if (!select) { + return; + } + /** + * @param {HTMLElement} parent + * @param {string} optionLabel + * @param {string} optionValue + */ + const renderOption = (parent, optionLabel, optionValue) => { + const option = document.createElement('option'); + option.value = optionValue; + setInnerHtml(option, optionLabel); + option.selected = isSelected(optionValue, params.inputValue); + parent.appendChild(option); + }; + inputOptions.forEach(inputOption => { + const optionValue = inputOption[0]; + const optionLabel = inputOption[1]; + // spec: + // https://www.w3.org/TR/html401/interact/forms.html#h-17.6 + // "...all OPTGROUP elements must be specified directly within a SELECT element (i.e., groups may not be nested)..." + // check whether this is a + if (Array.isArray(optionLabel)) { + // if it is an array, then it is an + const optgroup = document.createElement('optgroup'); + optgroup.label = optionValue; + optgroup.disabled = false; // not configurable for now + select.appendChild(optgroup); + optionLabel.forEach(o => renderOption(optgroup, o[1], o[0])); + } else { + // case of