doc-fui-ds
Version:
Doc
1,607 lines (1,340 loc) • 120 kB
JavaScript
/*!
* sweetalert2 v11.4.17
* 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 = global || self, global.Sweetalert2 = factory());
}(this, function () { 'use strict';
const consolePrefix = 'SweetAlert2:';
/**
* Filter the unique values into a new array
* @param arr
*/
const uniqueArray = arr => {
const result = [];
for (let i = 0; i < arr.length; i++) {
if (result.indexOf(arr[i]) === -1) {
result.push(arr[i]);
}
}
return result;
};
/**
* Capitalize the first letter of a string
* @param {string} str
* @returns {string}
*/
const capitalizeFirstLetter = str => str.charAt(0).toUpperCase() + str.slice(1);
/**
* @param {NodeList | HTMLCollection | NamedNodeMap | DOMTokenList} nodeList
* @returns {array}
*/
const toArray = nodeList => Array.prototype.slice.call(nodeList);
/**
* Standardize console warnings
* @param {string | array} 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 {Array}
* @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
*/
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 arg
*/
const callIfFunction = arg => typeof arg === 'function' ? arg() : arg;
const hasToPromiseFn = arg => arg && typeof arg.toPromise === 'function';
const asPromise = arg => hasToPromiseFn(arg) ? arg.toPromise() : Promise.resolve(arg);
const isPromise = arg => arg && Promise.resolve(arg) === arg;
const getRandomElement = arr => arr[Math.floor(Math.random() * arr.length)];
const defaultParams = {
title: '',
titleText: '',
text: '',
html: '',
footer: '',
icon: undefined,
iconColor: undefined,
iconHtml: undefined,
template: undefined,
toast: false,
showClass: {
popup: 'swal2-show',
backdrop: 'swal2-backdrop-show',
icon: 'swal2-icon-show'
},
hideClass: {
popup: 'swal2-hide',
backdrop: 'swal2-backdrop-hide',
icon: 'swal2-icon-hide'
},
customClass: {},
target: 'body',
color: undefined,
backdrop: true,
heightAuto: true,
allowOutsideClick: true,
allowEscapeKey: true,
allowEnterKey: true,
stopKeydownPropagation: true,
keydownListenerCapture: false,
showConfirmButton: true,
showDenyButton: false,
showCancelButton: false,
preConfirm: undefined,
preDeny: undefined,
confirmButtonText: 'OK',
confirmButtonAriaLabel: '',
confirmButtonColor: undefined,
denyButtonText: 'No',
denyButtonAriaLabel: '',
denyButtonColor: undefined,
cancelButtonText: 'Cancel',
cancelButtonAriaLabel: '',
cancelButtonColor: undefined,
buttonsStyling: true,
reverseButtons: false,
focusConfirm: true,
focusDeny: false,
focusCancel: false,
returnFocus: true,
showCloseButton: false,
closeButtonHtml: '×',
closeButtonAriaLabel: 'Close this dialog',
loaderHtml: '',
showLoaderOnConfirm: false,
showLoaderOnDeny: false,
imageUrl: undefined,
imageWidth: undefined,
imageHeight: undefined,
imageAlt: '',
timer: undefined,
timerProgressBar: false,
width: undefined,
padding: undefined,
background: undefined,
input: undefined,
inputPlaceholder: '',
inputLabel: '',
inputValue: '',
inputOptions: {},
inputAutoTrim: true,
inputAttributes: {},
inputValidator: undefined,
returnInputValueOnDeny: false,
validationMessage: undefined,
grow: false,
position: 'center',
progressSteps: [],
currentProgressStep: undefined,
progressStepsDistance: undefined,
willOpen: undefined,
didOpen: undefined,
didRender: undefined,
willClose: undefined,
didClose: undefined,
didDestroy: undefined,
scrollbarPadding: true
};
const updatableParams = ['allowEscapeKey', 'allowOutsideClick', 'background', 'buttonsStyling', 'cancelButtonAriaLabel', 'cancelButtonColor', 'cancelButtonText', 'closeButtonAriaLabel', 'closeButtonHtml', 'color', 'confirmButtonAriaLabel', 'confirmButtonColor', 'confirmButtonText', 'currentProgressStep', 'customClass', 'denyButtonAriaLabel', 'denyButtonColor', 'denyButtonText', 'didClose', 'didDestroy', 'footer', 'hideClass', 'html', 'icon', 'iconColor', 'iconHtml', 'imageAlt', 'imageHeight', 'imageUrl', 'imageWidth', 'preConfirm', 'preDeny', 'progressSteps', 'returnFocus', 'reverseButtons', 'showCancelButton', 'showCloseButton', 'showConfirmButton', 'showDenyButton', 'text', 'title', 'titleText', 'willClose'];
const deprecatedParams = {};
const toastIncompatibleParams = ['allowOutsideClick', 'allowEnterKey', 'backdrop', 'focusConfirm', 'focusDeny', 'focusCancel', 'returnFocus', 'heightAuto', 'keydownListenerCapture'];
/**
* Is valid parameter
* @param {string} paramName
*/
const isValidParameter = paramName => {
return Object.prototype.hasOwnProperty.call(defaultParams, paramName);
};
/**
* Is valid parameter for Swal.update() method
* @param {string} paramName
*/
const isUpdatableParameter = paramName => {
return updatableParams.indexOf(paramName) !== -1;
};
/**
* Is deprecated parameter
* @param {string} paramName
*/
const isDeprecatedParameter = paramName => {
return deprecatedParams[paramName];
};
const checkIfParamIsValid = param => {
if (!isValidParameter(param)) {
warn("Unknown parameter \"".concat(param, "\""));
}
};
const checkIfToastParamIsValid = param => {
if (toastIncompatibleParams.includes(param)) {
warn("The parameter \"".concat(param, "\" is incompatible with toasts"));
}
};
const checkIfParamIsDeprecated = param => {
if (isDeprecatedParameter(param)) {
warnAboutDeprecation(param, isDeprecatedParameter(param));
}
};
/**
* Show relevant warnings for given params
*
* @param params
*/
const showWarningsForParams = params => {
if (!params.backdrop && params.allowOutsideClick) {
warn('"allowOutsideClick" parameter requires `backdrop` parameter to be set to `true`');
}
for (const param in params) {
checkIfParamIsValid(param);
if (params.toast) {
checkIfToastParamIsValid(param);
}
checkIfParamIsDeprecated(param);
}
};
const swalPrefix = 'swal2-';
/**
* @param {string[]} items
* @returns {object}
*/
const prefix = items => {
const result = {};
for (const i in items) {
result[items[i]] = swalPrefix + items[i];
}
return result;
};
const swalClasses = prefix(['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', 'no-war']);
const iconTypes = prefix(['success', 'warning', 'info', 'question', 'error']);
/**
* 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 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 {HTMLElement | null}
*/
const getConfirmButton = () => elementBySelector(".".concat(swalClasses.actions, " .").concat(swalClasses.confirm));
/**
* @returns {HTMLElement | null}
*/
const getDenyButton = () => 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 getCancelButton = () => elementBySelector(".".concat(swalClasses.actions, " .").concat(swalClasses.cancel));
/**
* @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 focusableElementsWithTabindex = toArray(getPopup().querySelectorAll('[tabindex]:not([tabindex="-1"]):not([tabindex="0"])')) // sort according to tabindex
.sort((a, b) => {
const tabindexA = parseInt(a.getAttribute('tabindex'));
const tabindexB = parseInt(b.getAttribute('tabindex'));
if (tabindexA > tabindexB) {
return 1;
} else if (tabindexA < tabindexB) {
return -1;
}
return 0;
});
const otherFocusableElements = toArray(getPopup().querySelectorAll(focusable)).filter(el => el.getAttribute('tabindex') !== '-1');
return uniqueArray(focusableElementsWithTabindex.concat(otherFocusableElements)).filter(el => isVisible(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 = () => {
return getPopup() && hasClass(getPopup(), swalClasses.toast);
};
/**
* @returns {boolean}
*/
const isLoading = () => {
return getPopup().hasAttribute('data-loading');
};
const states = {
previousBodyPadding: null
};
/**
* 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");
toArray(parsed.querySelector('head').childNodes).forEach(child => {
elem.appendChild(child);
});
toArray(parsed.querySelector('body').childNodes).forEach(child => {
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) => {
toArray(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) {
return warn("Invalid type of customClass.".concat(className, "! Expected string or iterable object, got \"").concat(typeof params.customClass[className], "\""));
}
addClass(elem, params.customClass[className]);
}
};
/**
* @param {HTMLElement} popup
* @param {import('./renderers/renderInput').InputClass} inputClass
* @returns {HTMLInputElement | null}
*/
const getInput = (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[]} 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[]} classList
*/
const addClass = (target, classList) => {
toggleClass(target, classList, true);
};
/**
* @param {HTMLElement | HTMLElement[] | null} target
* @param {string | string[] | readonly string[]} 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 | null}
*/
const getDirectChildByClass = (elem, className) => {
const childNodes = toArray(elem.childNodes);
for (let i = 0; i < childNodes.length; i++) {
if (hasClass(childNodes[i], className)) {
return childNodes[i];
}
}
};
/**
* @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} elem
* @param {string} display
*/
const show = function (elem) {
let display = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'flex';
elem.style.display = display;
};
/**
* @param {HTMLElement} elem
*/
const hide = elem => {
elem.style.display = 'none';
};
/**
* @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} elem
* @returns {boolean}
*/
const isVisible = elem => !!(elem && (elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length));
/**
* @returns {boolean}
*/
const allButtonsAreHidden = () => !isVisible(getConfirmButton()) && !isVisible(getDenyButton()) && !isVisible(getCancelButton());
/**
* @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 (isVisible(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();
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.removeProperty('transition');
timerProgressBar.style.width = "".concat(timerProgressBarPercent, "%");
};
/**
* Detect Node env
*
* @returns {boolean}
*/
const isNodeEnv = () => typeof window === 'undefined' || typeof document === 'undefined';
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 sweetHTML = "\n <div aria-labelledby=\"".concat(swalClasses.title, "\" aria-describedby=\"").concat(swalClasses['html-container'], "\" class=\"").concat(swalClasses.popup, "\" tabindex=\"-1\">\n <button type=\"button\" class=\"").concat(swalClasses.close, "\"></button>\n <ul class=\"").concat(swalClasses['progress-steps'], "\"></ul>\n <div class=\"").concat(swalClasses.icon, "\"></div>\n <img class=\"").concat(swalClasses.image, "\" />\n <h2 class=\"").concat(swalClasses.title, "\" id=\"").concat(swalClasses.title, "\"></h2>\n <div class=\"").concat(swalClasses['html-container'], "\" id=\"").concat(swalClasses['html-container'], "\"></div>\n <input class=\"").concat(swalClasses.input, "\" />\n <input type=\"file\" class=\"").concat(swalClasses.file, "\" />\n <div class=\"").concat(swalClasses.range, "\">\n <input type=\"range\" />\n <output></output>\n </div>\n <select class=\"").concat(swalClasses.select, "\"></select>\n <div class=\"").concat(swalClasses.radio, "\"></div>\n <label for=\"").concat(swalClasses.checkbox, "\" class=\"").concat(swalClasses.checkbox, "\">\n <input type=\"checkbox\" />\n <span class=\"").concat(swalClasses.label, "\"></span>\n </label>\n <textarea class=\"").concat(swalClasses.textarea, "\"></textarea>\n <div class=\"").concat(swalClasses['validation-message'], "\" id=\"").concat(swalClasses['validation-message'], "\"></div>\n <div class=\"").concat(swalClasses.actions, "\">\n <div class=\"").concat(swalClasses.loader, "\"></div>\n <button type=\"button\" class=\"").concat(swalClasses.confirm, "\"></button>\n <button type=\"button\" class=\"").concat(swalClasses.deny, "\"></button>\n <button type=\"button\" class=\"").concat(swalClasses.cancel, "\"></button>\n </div>\n <div class=\"").concat(swalClasses.footer, "\"></div>\n <div class=\"").concat(swalClasses['timer-progress-bar-container'], "\">\n <div class=\"").concat(swalClasses['timer-progress-bar'], "\"></div>\n </div>\n </div>\n").replace(/(^|\n)\s*/g, '');
/**
* @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 = () => {
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;
file.onchange = resetValidationMessage;
select.onchange = resetValidationMessage;
checkbox.onchange = resetValidationMessage;
textarea.oninput = resetValidationMessage;
range.oninput = () => {
resetValidationMessage();
rangeOutput.value = range.value;
};
range.onchange = () => {
resetValidationMessage();
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);
}
};
/**
* Add modal + backdrop + no-war message for Russians to DOM
*
* @param {SweetAlertOptions} params
*/
const init = params => {
// Clean up the old popup container if it exists
const oldContainerExisted = resetOldContainer();
/* istanbul ignore if */
if (isNodeEnv()) {
error('SweetAlert2 requires document to initialize');
return;
}
const container = document.createElement('div');
container.className = swalClasses.container;
if (oldContainerExisted) {
addClass(container, swalClasses['no-transition']);
}
setInnerHtml(container, sweetHTML);
const targetElement = getTarget(params.target);
targetElement.appendChild(container);
setupAccessibility(params);
setupRTL(targetElement);
addInputChangeListeners();
noWarMessageForRussians(container, params);
};
/**
* @param {HTMLElement} container
* @param {SweetAlertOptions} params
*/
const noWarMessageForRussians = (container, params) => {
if (params.toast) {
return;
} // This message is targeted at people who are corrupted by propaganda, everybody else
// is already against war either silently or actively.
//
// The point is to wrap the truth-bomb into a patriotic title so they will actually click it
// and listen to the uncomfortable truth about the war from the people they love or respect.
const message = getRandomElement([{
text: 'ШВАРЦЕНЕГГЕР обратился <br> к РУССКОМУ НАРОДУ о войне',
// Arnold is loved in Russia by all people including those who are for this war
// His speech might change the mind of those who are brainwashed by propaganda
youtubeId: 'fWClXZd9c78'
}, {
text: 'РУССКИЙ ПАТРИОТ <br> открыл главную тайну спецоперации',
// In this video one of the most famous Russian nationalist leaders, Dmitry Demushkin,
// explains that this war has no sense and produces the exact opposite result of what
// it was intended to do.
youtubeId: '_RjBNkn88yA'
}, {
text: 'ГЕРОЙ НОВОРОССИИ СТРЕЛКОВ <br> дал оценку ходу спецоперации',
// In this video Igor Girkin, who played a key role in the annexation of Crimea,
// explains that this war has failed already and all possible outcomes are bad for Russia.
youtubeId: 'yUmzQT4C8JY'
}, {
text: 'ФИНСКИЙ ДРУГ РОССИИ <br> говорит ПО-РУССКИ о спецоперации',
youtubeId: 'hkCYb6edUrQ'
}, {
text: 'ЮРИЙ ПОДОЛЯКА честно <br> о генералах РУССКОЙ АРМИИ',
youtubeId: 'w4-_8BJKfpk'
}, {
text: 'Полковник ФСБ СТРЕЛКОВ <br> об успехах РОССИИ в спецоперации',
youtubeId: 'saK5UTKroDA'
}]); // The message will only be shown to Russian users visiting Russian sites
if (navigator.language === 'ru' && location.host.match(/\.(ru|su|xn--p1ai)$/)) {
const noWar = document.createElement('div');
noWar.className = swalClasses['no-war'];
setInnerHtml(noWar, "<a href=\"https://www.youtube.com/watch?v=".concat(message.youtubeId, "\" target=\"_blank\">").concat(message.text, "</a>"));
container.appendChild(noWar);
container.style.paddingTop = '4em';
}
};
/**
* @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 {object} 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 {HTMLElement} 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
/* istanbul ignore if */
if (isNodeEnv()) {
return false;
}
const testEl = document.createElement('div');
const transEndEventNames = {
WebkitAnimation: 'webkitAnimationEnd',
// Chrome, Safari and Opera
animation: 'animationend' // Standard syntax
};
for (const i in transEndEventNames) {
if (Object.prototype.hasOwnProperty.call(transEndEventNames, i) && typeof testEl.style[i] !== 'undefined') {
return transEndEventNames[i];
}
}
return false;
})();
/**
* 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;
};
/**
* @param {SweetAlert2} instance
* @param {SweetAlertOptions} params
*/
const renderActions = (instance, params) => {
const actions = getActions();
const loader = getLoader(); // 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(); // 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) {
return removeClass([confirmButton, denyButton, cancelButton], swalClasses.styled);
}
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) {
toggle(button, params["show".concat(capitalizeFirstLetter(buttonType), "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"));
addClass(button, params["".concat(buttonType, "ButtonClass")]);
}
/**
* @param {SweetAlert2} 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 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 && typeof grow === 'string') {
const growClass = "grow-".concat(grow);
if (growClass in swalClasses) {
addClass(container, swalClasses[growClass]);
}
}
}
/**
* 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 = {
awaitingPromise: new WeakMap(),
promise: new WeakMap(),
innerParams: new WeakMap(),
domCache: new WeakMap()
};
/// <reference path="../../../../sweetalert2.d.ts"/>
/** @type {InputClass[]} */
const inputClasses = ['input', 'file', 'range', 'select', 'radio', 'checkbox', 'textarea'];
/**
* @param {SweetAlert2} instance
* @param {SweetAlertOptions} params
*/
const renderInput = (instance, params) => {
const popup = getPopup();
const innerParams = privateProps.innerParams.get(instance);
const rerender = !innerParams || params.input !== innerParams.input;
inputClasses.forEach(inputClass => {
const inputContainer = getDirectChildByClass(popup, swalClasses[inputClass]); // 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 (!renderInputType[params.input]) {
return error("Unexpected type of input! Expected \"text\", \"email\", \"password\", \"number\", \"tel\", \"select\", \"radio\", \"checkbox\", \"textarea\", \"file\" or \"url\", got \"".concat(params.input, "\""));
}
const inputContainer = getInputContainer(params.input);
const input = renderInputType[params.input](inputContainer, params);
show(inputContainer); // input autofocus
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 (!['type', 'value', 'style'].includes(attrName)) {
input.removeAttribute(attrName);
}
}
};
/**
* @param {InputClass} inputClass
* @param {SweetAlertOptions['inputAttributes']} inputAttributes
*/
const setAttributes = (inputClass, inputAttributes) => {
const input = getInput(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) {
input.id = swalClasses.input;
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<string, (input: Input | HTMLElement, params: SweetAlertOptions) => Input> */
const renderInputType = {};
/**
* @param {HTMLInputElement} input
* @param {SweetAlertOptions} params
* @returns {HTMLInputElement}
*/
renderInputType.text = renderInputType.email = renderInputType.password = renderInputType.number = renderInputType.tel = renderInputType.url = (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(getPopup(), 'checkbox');
checkbox.value = '1';
checkbox.id = swalClasses.checkbox;
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 = () => {
const textareaWidth = textarea.offsetWidth + getMargin(textarea);
if (textareaWidth > initialPopupWidth) {
getPopup().style.width = "".concat(textareaWidth, "px");
} else {
getPopup().style.width = null;
}
};
new MutationObserver(textareaResizeHandler).observe(textarea, {
attributes: true,
attributeFilter: ['style']
});
}
});
return textarea;
};
/**
* @param {SweetAlert2} instance
* @param {SweetAlertOptions} params
*/
const renderContent = (instance, params) => {
const htmlContainer = getHtmlContainer();
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 {SweetAlert2} instance
* @param {SweetAlertOptions} params
*/
const renderFooter = (instance, params) => {
const footer = getFooter();
toggle(footer, params.footer);
if (params.footer) {
parseHtmlToContainer(params.footer, footer);
} // Custom class
applyCustomClass(footer, params, 'footer');
};
/**
* @param {SweetAlert2} instance
* @param {SweetAlertOptions} params
*/
const renderCloseButton = (instance, params) => {
const closeButton = getCloseButton();
setInnerHtml(closeButton, params.closeButtonHtml); // Custom class
applyCustomClass(closeButton, params, 'closeButton');
toggle(closeButton, params.showCloseButton);
closeButton.setAttribute('aria-label', params.closeButtonAriaLabel);
};
/**
* @param {SweetAlert2} instance
* @param {SweetAlertOptions} params
*/
const renderIcon = (instance, params) => {
const innerParams = privateProps.innerParams.get(instance);
const icon = getIcon(); // 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.icon);
};
/**
* @param {HTMLElement} icon
* @param {SweetAlertOptions} params
*/
const applyStyles = (icon, params) => {
for (const iconType in iconTypes) {
if (params.icon !== iconType) {
removeClass(icon, iconTypes[iconType]);
}
}
addClass(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();
const popupBackgroundColor = window.getComputedStyle(popup).getPropertyValue('background-color');
/** @type {NodeListOf<HTMLElement>} */
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;