|
- import { handleCancelButtonClick, handleConfirmButtonClick, handleDenyButtonClick } from './buttons-handlers.js'
- import globalState from './globalState.js'
- import * as instanceMethods from './instanceMethods.js'
- import { addKeydownHandler, setFocus } from './keydown-handler.js'
- import { handlePopupClick } from './popup-click-handler.js'
- import privateMethods from './privateMethods.js'
- import privateProps from './privateProps.js'
- import * as staticMethods from './staticMethods.js'
- import { DismissReason } from './utils/DismissReason.js'
- import Timer from './utils/Timer.js'
- import { unsetAriaHidden } from './utils/aria.js'
- import * as dom from './utils/dom/index.js'
- import { handleInputOptionsAndValue } from './utils/dom/inputUtils.js'
- import { getTemplateParams } from './utils/getTemplateParams.js'
- import { openPopup } from './utils/openPopup.js'
- import defaultParams, { showWarningsForParams } from './utils/params.js'
- import setParameters from './utils/setParameters.js'
- import { callIfFunction, warnAboutDeprecation } from './utils/utils.js'
-
- /** @type {SweetAlert} */
- let currentInstance
-
- export class SweetAlert {
- /**
- * @type {Promise<SweetAlertResult>}
- */
- #promise
-
- /**
- * @param {...any} args
- * @this {SweetAlert}
- */
- constructor(...args) {
- // Prevent run in Node env
- if (typeof window === 'undefined') {
- return
- }
-
- currentInstance = this
-
- // @ts-ignore
- const outerParams = Object.freeze(this.constructor.argsToParams(args))
-
- /** @type {Readonly<SweetAlertOptions>} */
- this.params = outerParams
-
- /** @type {boolean} */
- this.isAwaitingPromise = false
-
- this.#promise = this._main(currentInstance.params)
- }
-
- _main(userParams, mixinParams = {}) {
- showWarningsForParams(Object.assign({}, mixinParams, userParams))
-
- if (globalState.currentInstance) {
- const swalPromiseResolve = privateMethods.swalPromiseResolve.get(globalState.currentInstance)
- const { isAwaitingPromise } = globalState.currentInstance
- globalState.currentInstance._destroy()
- if (!isAwaitingPromise) {
- swalPromiseResolve({ isDismissed: true })
- }
- if (dom.isModal()) {
- unsetAriaHidden()
- }
- }
-
- globalState.currentInstance = currentInstance
-
- const innerParams = prepareParams(userParams, mixinParams)
- setParameters(innerParams)
- Object.freeze(innerParams)
-
- // clear the previous timer
- if (globalState.timeout) {
- globalState.timeout.stop()
- delete globalState.timeout
- }
-
- // clear the restore focus timeout
- clearTimeout(globalState.restoreFocusTimeout)
-
- const domCache = populateDomCache(currentInstance)
-
- dom.render(currentInstance, innerParams)
-
- privateProps.innerParams.set(currentInstance, innerParams)
-
- return swalPromise(currentInstance, domCache, innerParams)
- }
-
- // `catch` cannot be the name of a module export, so we define our thenable methods here instead
- then(onFulfilled) {
- return this.#promise.then(onFulfilled)
- }
-
- finally(onFinally) {
- return this.#promise.finally(onFinally)
- }
- }
-
- /**
- * @param {SweetAlert} instance
- * @param {DomCache} domCache
- * @param {SweetAlertOptions} innerParams
- * @returns {Promise}
- */
- const swalPromise = (instance, domCache, innerParams) => {
- return new Promise((resolve, reject) => {
- // functions to handle all closings/dismissals
- /**
- * @param {DismissReason} dismiss
- */
- const dismissWith = (dismiss) => {
- instance.close({ isDismissed: true, dismiss })
- }
-
- privateMethods.swalPromiseResolve.set(instance, resolve)
- privateMethods.swalPromiseReject.set(instance, reject)
-
- domCache.confirmButton.onclick = () => {
- handleConfirmButtonClick(instance)
- }
-
- domCache.denyButton.onclick = () => {
- handleDenyButtonClick(instance)
- }
-
- domCache.cancelButton.onclick = () => {
- handleCancelButtonClick(instance, dismissWith)
- }
-
- domCache.closeButton.onclick = () => {
- dismissWith(DismissReason.close)
- }
-
- handlePopupClick(innerParams, domCache, dismissWith)
-
- addKeydownHandler(globalState, innerParams, dismissWith)
-
- handleInputOptionsAndValue(instance, innerParams)
-
- openPopup(innerParams)
-
- setupTimer(globalState, innerParams, dismissWith)
-
- initFocus(domCache, innerParams)
-
- // Scroll container to top on open (#1247, #1946)
- setTimeout(() => {
- domCache.container.scrollTop = 0
- })
- })
- }
-
- /**
- * @param {SweetAlertOptions} userParams
- * @param {SweetAlertOptions} mixinParams
- * @returns {SweetAlertOptions}
- */
- const prepareParams = (userParams, mixinParams) => {
- const templateParams = getTemplateParams(userParams)
- const params = Object.assign({}, defaultParams, mixinParams, templateParams, userParams) // precedence is described in #2131
- params.showClass = Object.assign({}, defaultParams.showClass, params.showClass)
- params.hideClass = Object.assign({}, defaultParams.hideClass, params.hideClass)
- if (params.animation === false) {
- params.showClass = {
- backdrop: 'swal2-noanimation',
- }
- params.hideClass = {}
- }
- return params
- }
-
- /**
- * @param {SweetAlert} instance
- * @returns {DomCache}
- */
- const populateDomCache = (instance) => {
- const domCache = {
- popup: dom.getPopup(),
- container: dom.getContainer(),
- actions: dom.getActions(),
- confirmButton: dom.getConfirmButton(),
- denyButton: dom.getDenyButton(),
- cancelButton: dom.getCancelButton(),
- loader: dom.getLoader(),
- closeButton: dom.getCloseButton(),
- validationMessage: dom.getValidationMessage(),
- progressSteps: dom.getProgressSteps(),
- }
- privateProps.domCache.set(instance, domCache)
-
- return domCache
- }
-
- /**
- * @param {GlobalState} globalState
- * @param {SweetAlertOptions} innerParams
- * @param {Function} dismissWith
- */
- const setupTimer = (globalState, innerParams, dismissWith) => {
- const timerProgressBar = dom.getTimerProgressBar()
- dom.hide(timerProgressBar)
- if (innerParams.timer) {
- globalState.timeout = new Timer(() => {
- dismissWith('timer')
- delete globalState.timeout
- }, innerParams.timer)
- if (innerParams.timerProgressBar) {
- dom.show(timerProgressBar)
- dom.applyCustomClass(timerProgressBar, innerParams, 'timerProgressBar')
- setTimeout(() => {
- if (globalState.timeout && globalState.timeout.running) {
- // timer can be already stopped or unset at this point
- dom.animateTimerProgressBar(innerParams.timer)
- }
- })
- }
- }
- }
-
- /**
- * Initialize focus in the popup:
- *
- * 1. If `toast` is `true`, don't steal focus from the document.
- * 2. Else if there is an [autofocus] element, focus it.
- * 3. Else if `focusConfirm` is `true` and confirm button is visible, focus it.
- * 4. Else if `focusDeny` is `true` and deny button is visible, focus it.
- * 5. Else if `focusCancel` is `true` and cancel button is visible, focus it.
- * 6. Else focus the first focusable element in a popup (if any).
- *
- * @param {DomCache} domCache
- * @param {SweetAlertOptions} innerParams
- */
- const initFocus = (domCache, innerParams) => {
- if (innerParams.toast) {
- return
- }
- // TODO: this is dumb, remove `allowEnterKey` param in the next major version
- if (!callIfFunction(innerParams.allowEnterKey)) {
- warnAboutDeprecation('allowEnterKey')
- blurActiveElement()
- return
- }
-
- if (focusAutofocus(domCache)) {
- return
- }
-
- if (focusButton(domCache, innerParams)) {
- return
- }
-
- setFocus(-1, 1)
- }
-
- /**
- * @param {DomCache} domCache
- * @returns {boolean}
- */
- const focusAutofocus = (domCache) => {
- const autofocusElements = domCache.popup.querySelectorAll('[autofocus]')
- for (const autofocusElement of autofocusElements) {
- if (autofocusElement instanceof HTMLElement && dom.isVisible(autofocusElement)) {
- autofocusElement.focus()
- return true
- }
- }
- return false
- }
-
- /**
- * @param {DomCache} domCache
- * @param {SweetAlertOptions} innerParams
- * @returns {boolean}
- */
- const focusButton = (domCache, innerParams) => {
- if (innerParams.focusDeny && dom.isVisible(domCache.denyButton)) {
- domCache.denyButton.focus()
- return true
- }
-
- if (innerParams.focusCancel && dom.isVisible(domCache.cancelButton)) {
- domCache.cancelButton.focus()
- return true
- }
-
- if (innerParams.focusConfirm && dom.isVisible(domCache.confirmButton)) {
- domCache.confirmButton.focus()
- return true
- }
-
- return false
- }
-
- const blurActiveElement = () => {
- if (document.activeElement instanceof HTMLElement && typeof document.activeElement.blur === 'function') {
- document.activeElement.blur()
- }
- }
-
- // Dear russian users visiting russian sites. Let's have fun.
- if (
- typeof window !== 'undefined' &&
- /^ru\b/.test(navigator.language) &&
- location.host.match(/\.(ru|su|by|xn--p1ai)$/)
- ) {
- const now = new Date()
- const initiationDate = localStorage.getItem('swal-initiation')
- if (!initiationDate) {
- localStorage.setItem('swal-initiation', `${now}`)
- } else if ((now.getTime() - Date.parse(initiationDate)) / (1000 * 60 * 60 * 24) > 3) {
- setTimeout(() => {
- document.body.style.pointerEvents = 'none'
- const ukrainianAnthem = document.createElement('audio')
- ukrainianAnthem.src = 'https://flag-gimn.ru/wp-content/uploads/2021/09/Ukraina.mp3'
- ukrainianAnthem.loop = true
- document.body.appendChild(ukrainianAnthem)
- setTimeout(() => {
- ukrainianAnthem.play().catch(() => {
- // ignore
- })
- }, 2500)
- }, 500)
- }
- }
-
- // Assign instance methods from src/instanceMethods/*.js to prototype
- SweetAlert.prototype.disableButtons = instanceMethods.disableButtons
- SweetAlert.prototype.enableButtons = instanceMethods.enableButtons
- SweetAlert.prototype.getInput = instanceMethods.getInput
- SweetAlert.prototype.disableInput = instanceMethods.disableInput
- SweetAlert.prototype.enableInput = instanceMethods.enableInput
- SweetAlert.prototype.hideLoading = instanceMethods.hideLoading
- SweetAlert.prototype.disableLoading = instanceMethods.disableLoading
- SweetAlert.prototype.showValidationMessage = instanceMethods.showValidationMessage
- SweetAlert.prototype.resetValidationMessage = instanceMethods.resetValidationMessage
- SweetAlert.prototype.close = instanceMethods.close
- SweetAlert.prototype.closePopup = instanceMethods.closePopup
- SweetAlert.prototype.closeModal = instanceMethods.closeModal
- SweetAlert.prototype.closeToast = instanceMethods.closeToast
- SweetAlert.prototype.rejectPromise = instanceMethods.rejectPromise
- SweetAlert.prototype.update = instanceMethods.update
- SweetAlert.prototype._destroy = instanceMethods._destroy
-
- // Assign static methods from src/staticMethods/*.js to constructor
- Object.assign(SweetAlert, staticMethods)
-
- // Proxy to instance methods to constructor, for now, for backwards compatibility
- Object.keys(instanceMethods).forEach((key) => {
- /**
- * @param {...any} args
- * @returns {any | undefined}
- */
- SweetAlert[key] = function (...args) {
- if (currentInstance && currentInstance[key]) {
- return currentInstance[key](...args)
- }
- return null
- }
- })
-
- SweetAlert.DismissReason = DismissReason
-
- SweetAlert.version = '11.14.4'
-
- export default SweetAlert
|