sweetalert2 11.4.29 → 11.4.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sweetalert2 v11.4.29
2
+ * sweetalert2 v11.4.32
3
3
  * Released under the MIT License.
4
4
  */
5
5
  (function (global, factory) {
@@ -8,6 +8,40 @@
8
8
  (global = global || self, global.Sweetalert2 = factory());
9
9
  }(this, function () { 'use strict';
10
10
 
11
+ /**
12
+ * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has.
13
+ * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')`
14
+ * This is the approach that Babel will probably take to implement private methods/fields
15
+ * https://github.com/tc39/proposal-private-methods
16
+ * https://github.com/babel/babel/pull/7555
17
+ * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module*
18
+ * then we can use that language feature.
19
+ */
20
+ var privateProps = {
21
+ awaitingPromise: new WeakMap(),
22
+ promise: new WeakMap(),
23
+ innerParams: new WeakMap(),
24
+ domCache: new WeakMap()
25
+ };
26
+
27
+ const swalPrefix = 'swal2-';
28
+ /**
29
+ * @param {string[]} items
30
+ * @returns {object}
31
+ */
32
+
33
+ const prefix = items => {
34
+ const result = {};
35
+
36
+ for (const i in items) {
37
+ result[items[i]] = swalPrefix + items[i];
38
+ }
39
+
40
+ return result;
41
+ };
42
+ 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']);
43
+ const iconTypes = prefix(['success', 'warning', 'info', 'question', 'error']);
44
+
11
45
  const consolePrefix = 'SweetAlert2:';
12
46
  /**
13
47
  * Filter the unique values into a new array
@@ -117,198 +151,6 @@
117
151
 
118
152
  const getRandomElement = arr => arr[Math.floor(Math.random() * arr.length)];
119
153
 
120
- const defaultParams = {
121
- title: '',
122
- titleText: '',
123
- text: '',
124
- html: '',
125
- footer: '',
126
- icon: undefined,
127
- iconColor: undefined,
128
- iconHtml: undefined,
129
- template: undefined,
130
- toast: false,
131
- showClass: {
132
- popup: 'swal2-show',
133
- backdrop: 'swal2-backdrop-show',
134
- icon: 'swal2-icon-show'
135
- },
136
- hideClass: {
137
- popup: 'swal2-hide',
138
- backdrop: 'swal2-backdrop-hide',
139
- icon: 'swal2-icon-hide'
140
- },
141
- customClass: {},
142
- target: 'body',
143
- color: undefined,
144
- backdrop: true,
145
- heightAuto: true,
146
- allowOutsideClick: true,
147
- allowEscapeKey: true,
148
- allowEnterKey: true,
149
- stopKeydownPropagation: true,
150
- keydownListenerCapture: false,
151
- showConfirmButton: true,
152
- showDenyButton: false,
153
- showCancelButton: false,
154
- preConfirm: undefined,
155
- preDeny: undefined,
156
- confirmButtonText: 'OK',
157
- confirmButtonAriaLabel: '',
158
- confirmButtonColor: undefined,
159
- denyButtonText: 'No',
160
- denyButtonAriaLabel: '',
161
- denyButtonColor: undefined,
162
- cancelButtonText: 'Cancel',
163
- cancelButtonAriaLabel: '',
164
- cancelButtonColor: undefined,
165
- buttonsStyling: true,
166
- reverseButtons: false,
167
- focusConfirm: true,
168
- focusDeny: false,
169
- focusCancel: false,
170
- returnFocus: true,
171
- showCloseButton: false,
172
- closeButtonHtml: '×',
173
- closeButtonAriaLabel: 'Close this dialog',
174
- loaderHtml: '',
175
- showLoaderOnConfirm: false,
176
- showLoaderOnDeny: false,
177
- imageUrl: undefined,
178
- imageWidth: undefined,
179
- imageHeight: undefined,
180
- imageAlt: '',
181
- timer: undefined,
182
- timerProgressBar: false,
183
- width: undefined,
184
- padding: undefined,
185
- background: undefined,
186
- input: undefined,
187
- inputPlaceholder: '',
188
- inputLabel: '',
189
- inputValue: '',
190
- inputOptions: {},
191
- inputAutoTrim: true,
192
- inputAttributes: {},
193
- inputValidator: undefined,
194
- returnInputValueOnDeny: false,
195
- validationMessage: undefined,
196
- grow: false,
197
- position: 'center',
198
- progressSteps: [],
199
- currentProgressStep: undefined,
200
- progressStepsDistance: undefined,
201
- willOpen: undefined,
202
- didOpen: undefined,
203
- didRender: undefined,
204
- willClose: undefined,
205
- didClose: undefined,
206
- didDestroy: undefined,
207
- scrollbarPadding: true
208
- };
209
- 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'];
210
- const deprecatedParams = {};
211
- const toastIncompatibleParams = ['allowOutsideClick', 'allowEnterKey', 'backdrop', 'focusConfirm', 'focusDeny', 'focusCancel', 'returnFocus', 'heightAuto', 'keydownListenerCapture'];
212
- /**
213
- * Is valid parameter
214
- *
215
- * @param {string} paramName
216
- * @returns {boolean}
217
- */
218
-
219
- const isValidParameter = paramName => {
220
- return Object.prototype.hasOwnProperty.call(defaultParams, paramName);
221
- };
222
- /**
223
- * Is valid parameter for Swal.update() method
224
- *
225
- * @param {string} paramName
226
- * @returns {boolean}
227
- */
228
-
229
- const isUpdatableParameter = paramName => {
230
- return updatableParams.indexOf(paramName) !== -1;
231
- };
232
- /**
233
- * Is deprecated parameter
234
- *
235
- * @param {string} paramName
236
- * @returns {string | undefined}
237
- */
238
-
239
- const isDeprecatedParameter = paramName => {
240
- return deprecatedParams[paramName];
241
- };
242
- /**
243
- * @param {string} param
244
- */
245
-
246
- const checkIfParamIsValid = param => {
247
- if (!isValidParameter(param)) {
248
- warn("Unknown parameter \"".concat(param, "\""));
249
- }
250
- };
251
- /**
252
- * @param {string} param
253
- */
254
-
255
-
256
- const checkIfToastParamIsValid = param => {
257
- if (toastIncompatibleParams.includes(param)) {
258
- warn("The parameter \"".concat(param, "\" is incompatible with toasts"));
259
- }
260
- };
261
- /**
262
- * @param {string} param
263
- */
264
-
265
-
266
- const checkIfParamIsDeprecated = param => {
267
- if (isDeprecatedParameter(param)) {
268
- warnAboutDeprecation(param, isDeprecatedParameter(param));
269
- }
270
- };
271
- /**
272
- * Show relevant warnings for given params
273
- *
274
- * @param {SweetAlertOptions} params
275
- */
276
-
277
-
278
- const showWarningsForParams = params => {
279
- if (!params.backdrop && params.allowOutsideClick) {
280
- warn('"allowOutsideClick" parameter requires `backdrop` parameter to be set to `true`');
281
- }
282
-
283
- for (const param in params) {
284
- checkIfParamIsValid(param);
285
-
286
- if (params.toast) {
287
- checkIfToastParamIsValid(param);
288
- }
289
-
290
- checkIfParamIsDeprecated(param);
291
- }
292
- };
293
-
294
- const swalPrefix = 'swal2-';
295
- /**
296
- * @param {string[]} items
297
- * @returns {object}
298
- */
299
-
300
- const prefix = items => {
301
- const result = {};
302
-
303
- for (const i in items) {
304
- result[items[i]] = swalPrefix + items[i];
305
- }
306
-
307
- return result;
308
- };
309
- 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']);
310
- const iconTypes = prefix(['success', 'warning', 'info', 'question', 'error']);
311
-
312
154
  /**
313
155
  * Gets the popup container which contains the backdrop and the popup itself.
314
156
  *
@@ -760,13 +602,6 @@
760
602
  timerProgressBar.style.width = "".concat(timerProgressBarPercent, "%");
761
603
  };
762
604
 
763
- /**
764
- * Detect Node env
765
- *
766
- * @returns {boolean}
767
- */
768
- const isNodeEnv = () => typeof window === 'undefined' || typeof document === 'undefined';
769
-
770
605
  const RESTORE_FOCUS_TIMEOUT = 100;
771
606
 
772
607
  /** @type {GlobalState} */
@@ -806,6 +641,13 @@
806
641
  });
807
642
  };
808
643
 
644
+ /**
645
+ * Detect Node env
646
+ *
647
+ * @returns {boolean}
648
+ */
649
+ const isNodeEnv = () => typeof window === 'undefined' || typeof document === 'undefined';
650
+
809
651
  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, '');
810
652
  /**
811
653
  * @returns {boolean}
@@ -1114,6 +956,20 @@
1114
956
  addClass(button, params["".concat(buttonType, "ButtonClass")]);
1115
957
  }
1116
958
 
959
+ /**
960
+ * @param {SweetAlert2} instance
961
+ * @param {SweetAlertOptions} params
962
+ */
963
+
964
+ const renderCloseButton = (instance, params) => {
965
+ const closeButton = getCloseButton();
966
+ setInnerHtml(closeButton, params.closeButtonHtml); // Custom class
967
+
968
+ applyCustomClass(closeButton, params, 'closeButton');
969
+ toggle(closeButton, params.showCloseButton);
970
+ closeButton.setAttribute('aria-label', params.closeButtonAriaLabel);
971
+ };
972
+
1117
973
  /**
1118
974
  * @param {SweetAlert2} instance
1119
975
  * @param {SweetAlertOptions} params
@@ -1174,22 +1030,6 @@
1174
1030
  }
1175
1031
  }
1176
1032
 
1177
- /**
1178
- * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has.
1179
- * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')`
1180
- * This is the approach that Babel will probably take to implement private methods/fields
1181
- * https://github.com/tc39/proposal-private-methods
1182
- * https://github.com/babel/babel/pull/7555
1183
- * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module*
1184
- * then we can use that language feature.
1185
- */
1186
- var privateProps = {
1187
- awaitingPromise: new WeakMap(),
1188
- promise: new WeakMap(),
1189
- innerParams: new WeakMap(),
1190
- domCache: new WeakMap()
1191
- };
1192
-
1193
1033
  /// <reference path="../../../../sweetalert2.d.ts"/>
1194
1034
  /** @type {InputClass[]} */
1195
1035
 
@@ -1519,20 +1359,6 @@
1519
1359
  applyCustomClass(footer, params, 'footer');
1520
1360
  };
1521
1361
 
1522
- /**
1523
- * @param {SweetAlert2} instance
1524
- * @param {SweetAlertOptions} params
1525
- */
1526
-
1527
- const renderCloseButton = (instance, params) => {
1528
- const closeButton = getCloseButton();
1529
- setInnerHtml(closeButton, params.closeButtonHtml); // Custom class
1530
-
1531
- applyCustomClass(closeButton, params, 'closeButton');
1532
- toggle(closeButton, params.showCloseButton);
1533
- closeButton.setAttribute('aria-label', params.closeButtonAriaLabel);
1534
- };
1535
-
1536
1362
  /**
1537
1363
  * @param {SweetAlert2} instance
1538
1364
  * @param {SweetAlertOptions} params
@@ -1684,6 +1510,69 @@
1684
1510
  applyCustomClass(image, params, 'image');
1685
1511
  };
1686
1512
 
1513
+ /**
1514
+ * @param {SweetAlert2} instance
1515
+ * @param {SweetAlertOptions} params
1516
+ */
1517
+
1518
+ const renderPopup = (instance, params) => {
1519
+ const container = getContainer();
1520
+ const popup = getPopup(); // Width
1521
+ // https://github.com/sweetalert2/sweetalert2/issues/2170
1522
+
1523
+ if (params.toast) {
1524
+ applyNumericalStyle(container, 'width', params.width);
1525
+ popup.style.width = '100%';
1526
+ popup.insertBefore(getLoader(), getIcon());
1527
+ } else {
1528
+ applyNumericalStyle(popup, 'width', params.width);
1529
+ } // Padding
1530
+
1531
+
1532
+ applyNumericalStyle(popup, 'padding', params.padding); // Color
1533
+
1534
+ if (params.color) {
1535
+ popup.style.color = params.color;
1536
+ } // Background
1537
+
1538
+
1539
+ if (params.background) {
1540
+ popup.style.background = params.background;
1541
+ }
1542
+
1543
+ hide(getValidationMessage()); // Classes
1544
+
1545
+ addClasses(popup, params);
1546
+ };
1547
+ /**
1548
+ * @param {HTMLElement} popup
1549
+ * @param {SweetAlertOptions} params
1550
+ */
1551
+
1552
+ const addClasses = (popup, params) => {
1553
+ // Default Class + showClass when updating Swal.update({})
1554
+ popup.className = "".concat(swalClasses.popup, " ").concat(isVisible(popup) ? params.showClass.popup : '');
1555
+
1556
+ if (params.toast) {
1557
+ addClass([document.documentElement, document.body], swalClasses['toast-shown']);
1558
+ addClass(popup, swalClasses.toast);
1559
+ } else {
1560
+ addClass(popup, swalClasses.modal);
1561
+ } // Custom class
1562
+
1563
+
1564
+ applyCustomClass(popup, params, 'popup');
1565
+
1566
+ if (typeof params.customClass === 'string') {
1567
+ addClass(popup, params.customClass);
1568
+ } // Icon class (#1842)
1569
+
1570
+
1571
+ if (params.icon) {
1572
+ addClass(popup, swalClasses["icon-".concat(params.icon)]);
1573
+ }
1574
+ };
1575
+
1687
1576
  /**
1688
1577
  * @param {SweetAlert2} instance
1689
1578
  * @param {SweetAlertOptions} params
@@ -1771,85 +1660,102 @@
1771
1660
  * @param {SweetAlertOptions} params
1772
1661
  */
1773
1662
 
1774
- const renderPopup = (instance, params) => {
1775
- const container = getContainer();
1776
- const popup = getPopup(); // Width
1777
- // https://github.com/sweetalert2/sweetalert2/issues/2170
1663
+ const render = (instance, params) => {
1664
+ renderPopup(instance, params);
1665
+ renderContainer(instance, params);
1666
+ renderProgressSteps(instance, params);
1667
+ renderIcon(instance, params);
1668
+ renderImage(instance, params);
1669
+ renderTitle(instance, params);
1670
+ renderCloseButton(instance, params);
1671
+ renderContent(instance, params);
1672
+ renderActions(instance, params);
1673
+ renderFooter(instance, params);
1778
1674
 
1779
- if (params.toast) {
1780
- applyNumericalStyle(container, 'width', params.width);
1781
- popup.style.width = '100%';
1782
- popup.insertBefore(getLoader(), getIcon());
1783
- } else {
1784
- applyNumericalStyle(popup, 'width', params.width);
1785
- } // Padding
1675
+ if (typeof params.didRender === 'function') {
1676
+ params.didRender(getPopup());
1677
+ }
1678
+ };
1786
1679
 
1680
+ /**
1681
+ * Hides loader and shows back the button which was hidden by .showLoading()
1682
+ */
1787
1683
 
1788
- applyNumericalStyle(popup, 'padding', params.padding); // Color
1684
+ function hideLoading() {
1685
+ // do nothing if popup is closed
1686
+ const innerParams = privateProps.innerParams.get(this);
1789
1687
 
1790
- if (params.color) {
1791
- popup.style.color = params.color;
1792
- } // Background
1688
+ if (!innerParams) {
1689
+ return;
1690
+ }
1793
1691
 
1692
+ const domCache = privateProps.domCache.get(this);
1693
+ hide(domCache.loader);
1794
1694
 
1795
- if (params.background) {
1796
- popup.style.background = params.background;
1695
+ if (isToast()) {
1696
+ if (innerParams.icon) {
1697
+ show(getIcon());
1698
+ }
1699
+ } else {
1700
+ showRelatedButton(domCache);
1797
1701
  }
1798
1702
 
1799
- hide(getValidationMessage()); // Classes
1703
+ removeClass([domCache.popup, domCache.actions], swalClasses.loading);
1704
+ domCache.popup.removeAttribute('aria-busy');
1705
+ domCache.popup.removeAttribute('data-loading');
1706
+ domCache.confirmButton.disabled = false;
1707
+ domCache.denyButton.disabled = false;
1708
+ domCache.cancelButton.disabled = false;
1709
+ }
1800
1710
 
1801
- addClasses(popup, params);
1711
+ const showRelatedButton = domCache => {
1712
+ const buttonToReplace = domCache.popup.getElementsByClassName(domCache.loader.getAttribute('data-button-to-replace'));
1713
+
1714
+ if (buttonToReplace.length) {
1715
+ show(buttonToReplace[0], 'inline-block');
1716
+ } else if (allButtonsAreHidden()) {
1717
+ hide(domCache.actions);
1718
+ }
1802
1719
  };
1720
+
1803
1721
  /**
1804
- * @param {HTMLElement} popup
1805
- * @param {SweetAlertOptions} params
1722
+ * Gets the input DOM node, this method works with input parameter.
1723
+ * @returns {HTMLElement | null}
1806
1724
  */
1807
1725
 
1808
- const addClasses = (popup, params) => {
1809
- // Default Class + showClass when updating Swal.update({})
1810
- popup.className = "".concat(swalClasses.popup, " ").concat(isVisible(popup) ? params.showClass.popup : '');
1811
-
1812
- if (params.toast) {
1813
- addClass([document.documentElement, document.body], swalClasses['toast-shown']);
1814
- addClass(popup, swalClasses.toast);
1815
- } else {
1816
- addClass(popup, swalClasses.modal);
1817
- } // Custom class
1818
-
1726
+ function getInput$1(instance) {
1727
+ const innerParams = privateProps.innerParams.get(instance || this);
1728
+ const domCache = privateProps.domCache.get(instance || this);
1819
1729
 
1820
- applyCustomClass(popup, params, 'popup');
1730
+ if (!domCache) {
1731
+ return null;
1732
+ }
1821
1733
 
1822
- if (typeof params.customClass === 'string') {
1823
- addClass(popup, params.customClass);
1824
- } // Icon class (#1842)
1734
+ return getInput(domCache.popup, innerParams.input);
1735
+ }
1825
1736
 
1737
+ /*
1738
+ * Global function to determine if SweetAlert2 popup is shown
1739
+ */
1826
1740
 
1827
- if (params.icon) {
1828
- addClass(popup, swalClasses["icon-".concat(params.icon)]);
1829
- }
1741
+ const isVisible$1 = () => {
1742
+ return isVisible(getPopup());
1830
1743
  };
1744
+ /*
1745
+ * Global function to click 'Confirm' button
1746
+ */
1831
1747
 
1832
- /**
1833
- * @param {SweetAlert2} instance
1834
- * @param {SweetAlertOptions} params
1748
+ const clickConfirm = () => getConfirmButton() && getConfirmButton().click();
1749
+ /*
1750
+ * Global function to click 'Deny' button
1835
1751
  */
1836
1752
 
1837
- const render = (instance, params) => {
1838
- renderPopup(instance, params);
1839
- renderContainer(instance, params);
1840
- renderProgressSteps(instance, params);
1841
- renderIcon(instance, params);
1842
- renderImage(instance, params);
1843
- renderTitle(instance, params);
1844
- renderCloseButton(instance, params);
1845
- renderContent(instance, params);
1846
- renderActions(instance, params);
1847
- renderFooter(instance, params);
1753
+ const clickDeny = () => getDenyButton() && getDenyButton().click();
1754
+ /*
1755
+ * Global function to click 'Cancel' button
1756
+ */
1848
1757
 
1849
- if (typeof params.didRender === 'function') {
1850
- params.didRender(getPopup());
1851
- }
1852
- };
1758
+ const clickCancel = () => getCancelButton() && getCancelButton().click();
1853
1759
 
1854
1760
  const DismissReason = Object.freeze({
1855
1761
  cancel: 'cancel',
@@ -1859,404 +1765,244 @@
1859
1765
  timer: 'timer'
1860
1766
  });
1861
1767
 
1862
- // Adding aria-hidden="true" to elements outside of the active modal dialog ensures that
1863
- // elements not within the active modal dialog will not be surfaced if a user opens a screen
1864
- // reader’s list of elements (headings, form controls, landmarks, etc.) in the document.
1768
+ /**
1769
+ * @param {GlobalState} globalState
1770
+ */
1865
1771
 
1866
- const setAriaHidden = () => {
1867
- const bodyChildren = Array.from(document.body.children);
1868
- bodyChildren.forEach(el => {
1869
- if (el === getContainer() || el.contains(getContainer())) {
1870
- return;
1871
- }
1772
+ const removeKeydownHandler = globalState => {
1773
+ if (globalState.keydownTarget && globalState.keydownHandlerAdded) {
1774
+ globalState.keydownTarget.removeEventListener('keydown', globalState.keydownHandler, {
1775
+ capture: globalState.keydownListenerCapture
1776
+ });
1777
+ globalState.keydownHandlerAdded = false;
1778
+ }
1779
+ };
1780
+ /**
1781
+ * @param {SweetAlert2} instance
1782
+ * @param {GlobalState} globalState
1783
+ * @param {SweetAlertOptions} innerParams
1784
+ * @param {*} dismissWith
1785
+ */
1872
1786
 
1873
- if (el.hasAttribute('aria-hidden')) {
1874
- el.setAttribute('data-previous-aria-hidden', el.getAttribute('aria-hidden'));
1875
- }
1787
+ const addKeydownHandler = (instance, globalState, innerParams, dismissWith) => {
1788
+ removeKeydownHandler(globalState);
1876
1789
 
1877
- el.setAttribute('aria-hidden', 'true');
1878
- });
1879
- };
1880
- const unsetAriaHidden = () => {
1881
- const bodyChildren = Array.from(document.body.children);
1882
- bodyChildren.forEach(el => {
1883
- if (el.hasAttribute('data-previous-aria-hidden')) {
1884
- el.setAttribute('aria-hidden', el.getAttribute('data-previous-aria-hidden'));
1885
- el.removeAttribute('data-previous-aria-hidden');
1886
- } else {
1887
- el.removeAttribute('aria-hidden');
1888
- }
1889
- });
1890
- };
1891
-
1892
- const swalStringParams = ['swal-title', 'swal-html', 'swal-footer'];
1893
- const getTemplateParams = params => {
1894
- const template = typeof params.template === 'string' ? document.querySelector(params.template) : params.template;
1790
+ if (!innerParams.toast) {
1791
+ globalState.keydownHandler = e => keydownHandler(instance, e, dismissWith);
1895
1792
 
1896
- if (!template) {
1897
- return {};
1793
+ globalState.keydownTarget = innerParams.keydownListenerCapture ? window : getPopup();
1794
+ globalState.keydownListenerCapture = innerParams.keydownListenerCapture;
1795
+ globalState.keydownTarget.addEventListener('keydown', globalState.keydownHandler, {
1796
+ capture: globalState.keydownListenerCapture
1797
+ });
1798
+ globalState.keydownHandlerAdded = true;
1898
1799
  }
1899
- /** @type {DocumentFragment} */
1900
-
1901
-
1902
- const templateContent = template.content;
1903
- showWarningsForElements(templateContent);
1904
- const result = Object.assign(getSwalParams(templateContent), getSwalButtons(templateContent), getSwalImage(templateContent), getSwalIcon(templateContent), getSwalInput(templateContent), getSwalStringParams(templateContent, swalStringParams));
1905
- return result;
1906
1800
  };
1907
1801
  /**
1908
- * @param {DocumentFragment} templateContent
1802
+ * @param {SweetAlertOptions} innerParams
1803
+ * @param {number} index
1804
+ * @param {number} increment
1909
1805
  */
1910
1806
 
1911
- const getSwalParams = templateContent => {
1912
- const result = {};
1913
- /** @type {HTMLElement[]} */
1807
+ const setFocus = (innerParams, index, increment) => {
1808
+ const focusableElements = getFocusableElements(); // search for visible elements and select the next possible match
1914
1809
 
1915
- const swalParams = Array.from(templateContent.querySelectorAll('swal-param'));
1916
- swalParams.forEach(param => {
1917
- showWarningsForAttributes(param, ['name', 'value']);
1918
- const paramName = param.getAttribute('name');
1919
- const value = param.getAttribute('value');
1810
+ if (focusableElements.length) {
1811
+ index = index + increment; // rollover to first item
1920
1812
 
1921
- if (typeof defaultParams[paramName] === 'boolean' && value === 'false') {
1922
- result[paramName] = false;
1813
+ if (index === focusableElements.length) {
1814
+ index = 0; // go to last item
1815
+ } else if (index === -1) {
1816
+ index = focusableElements.length - 1;
1923
1817
  }
1924
1818
 
1925
- if (typeof defaultParams[paramName] === 'object') {
1926
- result[paramName] = JSON.parse(value);
1927
- }
1928
- });
1929
- return result;
1819
+ return focusableElements[index].focus();
1820
+ } // no visible focusable elements, focus the popup
1821
+
1822
+
1823
+ getPopup().focus();
1930
1824
  };
1825
+ const arrowKeysNextButton = ['ArrowRight', 'ArrowDown'];
1826
+ const arrowKeysPreviousButton = ['ArrowLeft', 'ArrowUp'];
1931
1827
  /**
1932
- * @param {DocumentFragment} templateContent
1828
+ * @param {SweetAlert2} instance
1829
+ * @param {KeyboardEvent} e
1830
+ * @param {function} dismissWith
1933
1831
  */
1934
1832
 
1833
+ const keydownHandler = (instance, e, dismissWith) => {
1834
+ const innerParams = privateProps.innerParams.get(instance);
1935
1835
 
1936
- const getSwalButtons = templateContent => {
1937
- const result = {};
1938
- /** @type {HTMLElement[]} */
1836
+ if (!innerParams) {
1837
+ return; // This instance has already been destroyed
1838
+ } // Ignore keydown during IME composition
1839
+ // https://developer.mozilla.org/en-US/docs/Web/API/Document/keydown_event#ignoring_keydown_during_ime_composition
1840
+ // https://github.com/sweetalert2/sweetalert2/issues/720
1841
+ // https://github.com/sweetalert2/sweetalert2/issues/2406
1939
1842
 
1940
- const swalButtons = Array.from(templateContent.querySelectorAll('swal-button'));
1941
- swalButtons.forEach(button => {
1942
- showWarningsForAttributes(button, ['type', 'color', 'aria-label']);
1943
- const type = button.getAttribute('type');
1944
- result["".concat(type, "ButtonText")] = button.innerHTML;
1945
- result["show".concat(capitalizeFirstLetter(type), "Button")] = true;
1946
1843
 
1947
- if (button.hasAttribute('color')) {
1948
- result["".concat(type, "ButtonColor")] = button.getAttribute('color');
1949
- }
1844
+ if (e.isComposing || e.keyCode === 229) {
1845
+ return;
1846
+ }
1950
1847
 
1951
- if (button.hasAttribute('aria-label')) {
1952
- result["".concat(type, "ButtonAriaLabel")] = button.getAttribute('aria-label');
1953
- }
1954
- });
1955
- return result;
1848
+ if (innerParams.stopKeydownPropagation) {
1849
+ e.stopPropagation();
1850
+ } // ENTER
1851
+
1852
+
1853
+ if (e.key === 'Enter') {
1854
+ handleEnter(instance, e, innerParams);
1855
+ } // TAB
1856
+ else if (e.key === 'Tab') {
1857
+ handleTab(e, innerParams);
1858
+ } // ARROWS - switch focus between buttons
1859
+ else if ([...arrowKeysNextButton, ...arrowKeysPreviousButton].includes(e.key)) {
1860
+ handleArrows(e.key);
1861
+ } // ESC
1862
+ else if (e.key === 'Escape') {
1863
+ handleEsc(e, innerParams, dismissWith);
1864
+ }
1956
1865
  };
1957
1866
  /**
1958
- * @param {DocumentFragment} templateContent
1867
+ * @param {SweetAlert2} instance
1868
+ * @param {KeyboardEvent} e
1869
+ * @param {SweetAlertOptions} innerParams
1959
1870
  */
1960
1871
 
1961
1872
 
1962
- const getSwalImage = templateContent => {
1963
- const result = {};
1964
- /** @type {HTMLElement} */
1965
-
1966
- const image = templateContent.querySelector('swal-image');
1967
-
1968
- if (image) {
1969
- showWarningsForAttributes(image, ['src', 'width', 'height', 'alt']);
1970
-
1971
- if (image.hasAttribute('src')) {
1972
- result.imageUrl = image.getAttribute('src');
1973
- }
1974
-
1975
- if (image.hasAttribute('width')) {
1976
- result.imageWidth = image.getAttribute('width');
1977
- }
1873
+ const handleEnter = (instance, e, innerParams) => {
1874
+ // https://github.com/sweetalert2/sweetalert2/issues/2386
1875
+ if (!callIfFunction(innerParams.allowEnterKey)) {
1876
+ return;
1877
+ }
1978
1878
 
1979
- if (image.hasAttribute('height')) {
1980
- result.imageHeight = image.getAttribute('height');
1879
+ if (e.target && instance.getInput() && e.target instanceof HTMLElement && e.target.outerHTML === instance.getInput().outerHTML) {
1880
+ if (['textarea', 'file'].includes(innerParams.input)) {
1881
+ return; // do not submit
1981
1882
  }
1982
1883
 
1983
- if (image.hasAttribute('alt')) {
1984
- result.imageAlt = image.getAttribute('alt');
1985
- }
1884
+ clickConfirm();
1885
+ e.preventDefault();
1986
1886
  }
1987
-
1988
- return result;
1989
1887
  };
1990
1888
  /**
1991
- * @param {DocumentFragment} templateContent
1889
+ * @param {KeyboardEvent} e
1890
+ * @param {SweetAlertOptions} innerParams
1992
1891
  */
1993
1892
 
1994
1893
 
1995
- const getSwalIcon = templateContent => {
1996
- const result = {};
1997
- /** @type {HTMLElement} */
1998
-
1999
- const icon = templateContent.querySelector('swal-icon');
2000
-
2001
- if (icon) {
2002
- showWarningsForAttributes(icon, ['type', 'color']);
1894
+ const handleTab = (e, innerParams) => {
1895
+ const targetElement = e.target;
1896
+ const focusableElements = getFocusableElements();
1897
+ let btnIndex = -1;
2003
1898
 
2004
- if (icon.hasAttribute('type')) {
2005
- result.icon = icon.getAttribute('type');
1899
+ for (let i = 0; i < focusableElements.length; i++) {
1900
+ if (targetElement === focusableElements[i]) {
1901
+ btnIndex = i;
1902
+ break;
2006
1903
  }
1904
+ } // Cycle to the next button
2007
1905
 
2008
- if (icon.hasAttribute('color')) {
2009
- result.iconColor = icon.getAttribute('color');
2010
- }
2011
1906
 
2012
- result.iconHtml = icon.innerHTML;
1907
+ if (!e.shiftKey) {
1908
+ setFocus(innerParams, btnIndex, 1);
1909
+ } // Cycle to the prev button
1910
+ else {
1911
+ setFocus(innerParams, btnIndex, -1);
2013
1912
  }
2014
1913
 
2015
- return result;
1914
+ e.stopPropagation();
1915
+ e.preventDefault();
2016
1916
  };
2017
1917
  /**
2018
- * @param {DocumentFragment} templateContent
1918
+ * @param {string} key
2019
1919
  */
2020
1920
 
2021
1921
 
2022
- const getSwalInput = templateContent => {
2023
- const result = {};
2024
- /** @type {HTMLElement} */
1922
+ const handleArrows = key => {
1923
+ const confirmButton = getConfirmButton();
1924
+ const denyButton = getDenyButton();
1925
+ const cancelButton = getCancelButton();
2025
1926
 
2026
- const input = templateContent.querySelector('swal-input');
1927
+ if (document.activeElement instanceof HTMLElement && ![confirmButton, denyButton, cancelButton].includes(document.activeElement)) {
1928
+ return;
1929
+ }
2027
1930
 
2028
- if (input) {
2029
- showWarningsForAttributes(input, ['type', 'label', 'placeholder', 'value']);
2030
- result.input = input.getAttribute('type') || 'text';
1931
+ const sibling = arrowKeysNextButton.includes(key) ? 'nextElementSibling' : 'previousElementSibling';
1932
+ let buttonToFocus = document.activeElement;
2031
1933
 
2032
- if (input.hasAttribute('label')) {
2033
- result.inputLabel = input.getAttribute('label');
2034
- }
1934
+ for (let i = 0; i < getActions().children.length; i++) {
1935
+ buttonToFocus = buttonToFocus[sibling];
2035
1936
 
2036
- if (input.hasAttribute('placeholder')) {
2037
- result.inputPlaceholder = input.getAttribute('placeholder');
1937
+ if (!buttonToFocus) {
1938
+ return;
2038
1939
  }
2039
1940
 
2040
- if (input.hasAttribute('value')) {
2041
- result.inputValue = input.getAttribute('value');
1941
+ if (buttonToFocus instanceof HTMLButtonElement && isVisible(buttonToFocus)) {
1942
+ break;
2042
1943
  }
2043
1944
  }
2044
- /** @type {HTMLElement[]} */
2045
-
2046
-
2047
- const inputOptions = Array.from(templateContent.querySelectorAll('swal-input-option'));
2048
1945
 
2049
- if (inputOptions.length) {
2050
- result.inputOptions = {};
2051
- inputOptions.forEach(option => {
2052
- showWarningsForAttributes(option, ['value']);
2053
- const optionValue = option.getAttribute('value');
2054
- const optionName = option.innerHTML;
2055
- result.inputOptions[optionValue] = optionName;
2056
- });
1946
+ if (buttonToFocus instanceof HTMLButtonElement) {
1947
+ buttonToFocus.focus();
2057
1948
  }
2058
-
2059
- return result;
2060
1949
  };
2061
1950
  /**
2062
- * @param {DocumentFragment} templateContent
2063
- * @param {string[]} paramNames
1951
+ * @param {KeyboardEvent} e
1952
+ * @param {SweetAlertOptions} innerParams
1953
+ * @param {function} dismissWith
2064
1954
  */
2065
1955
 
2066
1956
 
2067
- const getSwalStringParams = (templateContent, paramNames) => {
2068
- const result = {};
2069
-
2070
- for (const i in paramNames) {
2071
- const paramName = paramNames[i];
2072
- /** @type {HTMLElement} */
2073
-
2074
- const tag = templateContent.querySelector(paramName);
2075
-
2076
- if (tag) {
2077
- showWarningsForAttributes(tag, []);
2078
- result[paramName.replace(/^swal-/, '')] = tag.innerHTML.trim();
2079
- }
1957
+ const handleEsc = (e, innerParams, dismissWith) => {
1958
+ if (callIfFunction(innerParams.allowEscapeKey)) {
1959
+ e.preventDefault();
1960
+ dismissWith(DismissReason.esc);
2080
1961
  }
1962
+ };
2081
1963
 
2082
- return result;
2083
- };
2084
- /**
2085
- * @param {DocumentFragment} templateContent
2086
- */
2087
-
2088
-
2089
- const showWarningsForElements = templateContent => {
2090
- const allowedElements = swalStringParams.concat(['swal-param', 'swal-button', 'swal-image', 'swal-icon', 'swal-input', 'swal-input-option']);
2091
- Array.from(templateContent.children).forEach(el => {
2092
- const tagName = el.tagName.toLowerCase();
2093
-
2094
- if (allowedElements.indexOf(tagName) === -1) {
2095
- warn("Unrecognized element <".concat(tagName, ">"));
2096
- }
2097
- });
2098
- };
2099
1964
  /**
2100
- * @param {HTMLElement} el
2101
- * @param {string[]} allowedAttributes
1965
+ * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has.
1966
+ * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')`
1967
+ * This is the approach that Babel will probably take to implement private methods/fields
1968
+ * https://github.com/tc39/proposal-private-methods
1969
+ * https://github.com/babel/babel/pull/7555
1970
+ * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module*
1971
+ * then we can use that language feature.
2102
1972
  */
2103
-
2104
-
2105
- const showWarningsForAttributes = (el, allowedAttributes) => {
2106
- Array.from(el.attributes).forEach(attribute => {
2107
- if (allowedAttributes.indexOf(attribute.name) === -1) {
2108
- warn(["Unrecognized attribute \"".concat(attribute.name, "\" on <").concat(el.tagName.toLowerCase(), ">."), "".concat(allowedAttributes.length ? "Allowed attributes are: ".concat(allowedAttributes.join(', ')) : 'To set the value, use HTML within the element.')]);
2109
- }
2110
- });
2111
- };
2112
-
2113
- var defaultInputValidators = {
2114
- /**
2115
- * @param {string} string
2116
- * @param {string} validationMessage
2117
- * @returns {Promise<void | string>}
2118
- */
2119
- email: (string, validationMessage) => {
2120
- return /^[a-zA-Z0-9.+_-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]{2,24}$/.test(string) ? Promise.resolve() : Promise.resolve(validationMessage || 'Invalid email address');
2121
- },
2122
-
2123
- /**
2124
- * @param {string} string
2125
- * @param {string} validationMessage
2126
- * @returns {Promise<void | string>}
2127
- */
2128
- url: (string, validationMessage) => {
2129
- // taken from https://stackoverflow.com/a/3809435 with a small change from #1306 and #2013
2130
- return /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-z]{2,63}\b([-a-zA-Z0-9@:%_+.~#?&/=]*)$/.test(string) ? Promise.resolve() : Promise.resolve(validationMessage || 'Invalid URL');
2131
- }
1973
+ var privateMethods = {
1974
+ swalPromiseResolve: new WeakMap(),
1975
+ swalPromiseReject: new WeakMap()
2132
1976
  };
2133
1977
 
2134
- /**
2135
- * @param {SweetAlertOptions} params
2136
- */
2137
-
2138
- function setDefaultInputValidators(params) {
2139
- // Use default `inputValidator` for supported input types if not provided
2140
- if (!params.inputValidator) {
2141
- Object.keys(defaultInputValidators).forEach(key => {
2142
- if (params.input === key) {
2143
- params.inputValidator = defaultInputValidators[key];
2144
- }
2145
- });
2146
- }
2147
- }
2148
- /**
2149
- * @param {SweetAlertOptions} params
2150
- */
2151
-
2152
-
2153
- function validateCustomTargetElement(params) {
2154
- // Determine if the custom target element is valid
2155
- if (!params.target || typeof params.target === 'string' && !document.querySelector(params.target) || typeof params.target !== 'string' && !params.target.appendChild) {
2156
- warn('Target parameter is not valid, defaulting to "body"');
2157
- params.target = 'body';
2158
- }
2159
- }
2160
- /**
2161
- * Set type, text and actions on popup
2162
- *
2163
- * @param {SweetAlertOptions} params
2164
- */
2165
-
2166
-
2167
- function setParameters(params) {
2168
- setDefaultInputValidators(params); // showLoaderOnConfirm && preConfirm
2169
-
2170
- if (params.showLoaderOnConfirm && !params.preConfirm) {
2171
- warn('showLoaderOnConfirm is set to true, but preConfirm is not defined.\n' + 'showLoaderOnConfirm should be used together with preConfirm, see usage example:\n' + 'https://sweetalert2.github.io/#ajax-request');
2172
- }
2173
-
2174
- validateCustomTargetElement(params); // Replace newlines with <br> in title
2175
-
2176
- if (typeof params.title === 'string') {
2177
- params.title = params.title.split('\n').join('<br />');
2178
- }
2179
-
2180
- init(params);
2181
- }
2182
-
2183
- class Timer {
2184
- constructor(callback, delay) {
2185
- this.callback = callback;
2186
- this.remaining = delay;
2187
- this.running = false;
2188
- this.start();
2189
- }
2190
-
2191
- start() {
2192
- if (!this.running) {
2193
- this.running = true;
2194
- this.started = new Date();
2195
- this.id = setTimeout(this.callback, this.remaining);
2196
- }
2197
-
2198
- return this.remaining;
2199
- }
2200
-
2201
- stop() {
2202
- if (this.running) {
2203
- this.running = false;
2204
- clearTimeout(this.id);
2205
- this.remaining -= new Date().getTime() - this.started.getTime();
2206
- }
2207
-
2208
- return this.remaining;
2209
- }
2210
-
2211
- increase(n) {
2212
- const running = this.running;
2213
-
2214
- if (running) {
2215
- this.stop();
2216
- }
2217
-
2218
- this.remaining += n;
1978
+ // Adding aria-hidden="true" to elements outside of the active modal dialog ensures that
1979
+ // elements not within the active modal dialog will not be surfaced if a user opens a screen
1980
+ // reader’s list of elements (headings, form controls, landmarks, etc.) in the document.
2219
1981
 
2220
- if (running) {
2221
- this.start();
1982
+ const setAriaHidden = () => {
1983
+ const bodyChildren = Array.from(document.body.children);
1984
+ bodyChildren.forEach(el => {
1985
+ if (el === getContainer() || el.contains(getContainer())) {
1986
+ return;
2222
1987
  }
2223
1988
 
2224
- return this.remaining;
2225
- }
2226
-
2227
- getTimerLeft() {
2228
- if (this.running) {
2229
- this.stop();
2230
- this.start();
1989
+ if (el.hasAttribute('aria-hidden')) {
1990
+ el.setAttribute('data-previous-aria-hidden', el.getAttribute('aria-hidden'));
2231
1991
  }
2232
1992
 
2233
- return this.remaining;
2234
- }
2235
-
2236
- isRunning() {
2237
- return this.running;
2238
- }
2239
-
2240
- }
2241
-
2242
- const fixScrollbar = () => {
2243
- // for queues, do not do this more than once
2244
- if (states.previousBodyPadding !== null) {
2245
- return;
2246
- } // if the body has overflow
2247
-
2248
-
2249
- if (document.body.scrollHeight > window.innerHeight) {
2250
- // add padding so the content doesn't shift after removal of scrollbar
2251
- states.previousBodyPadding = parseInt(window.getComputedStyle(document.body).getPropertyValue('padding-right'));
2252
- document.body.style.paddingRight = "".concat(states.previousBodyPadding + measureScrollbar(), "px");
2253
- }
1993
+ el.setAttribute('aria-hidden', 'true');
1994
+ });
2254
1995
  };
2255
- const undoScrollbar = () => {
2256
- if (states.previousBodyPadding !== null) {
2257
- document.body.style.paddingRight = "".concat(states.previousBodyPadding, "px");
2258
- states.previousBodyPadding = null;
2259
- }
1996
+ const unsetAriaHidden = () => {
1997
+ const bodyChildren = Array.from(document.body.children);
1998
+ bodyChildren.forEach(el => {
1999
+ if (el.hasAttribute('data-previous-aria-hidden')) {
2000
+ el.setAttribute('aria-hidden', el.getAttribute('data-previous-aria-hidden'));
2001
+ el.removeAttribute('data-previous-aria-hidden');
2002
+ } else {
2003
+ el.removeAttribute('aria-hidden');
2004
+ }
2005
+ });
2260
2006
  };
2261
2007
 
2262
2008
  /* istanbul ignore file */
@@ -2377,182 +2123,620 @@
2377
2123
  }
2378
2124
  };
2379
2125
 
2380
- const SHOW_CLASS_TIMEOUT = 10;
2381
- /**
2382
- * Open popup, add necessary classes and styles, fix scrollbar
2383
- *
2384
- * @param {SweetAlertOptions} params
2385
- */
2126
+ const fixScrollbar = () => {
2127
+ // for queues, do not do this more than once
2128
+ if (states.previousBodyPadding !== null) {
2129
+ return;
2130
+ } // if the body has overflow
2386
2131
 
2387
- const openPopup = params => {
2388
- const container = getContainer();
2389
- const popup = getPopup();
2390
2132
 
2391
- if (typeof params.willOpen === 'function') {
2392
- params.willOpen(popup);
2133
+ if (document.body.scrollHeight > window.innerHeight) {
2134
+ // add padding so the content doesn't shift after removal of scrollbar
2135
+ states.previousBodyPadding = parseInt(window.getComputedStyle(document.body).getPropertyValue('padding-right'));
2136
+ document.body.style.paddingRight = "".concat(states.previousBodyPadding + measureScrollbar(), "px");
2393
2137
  }
2138
+ };
2139
+ const undoScrollbar = () => {
2140
+ if (states.previousBodyPadding !== null) {
2141
+ document.body.style.paddingRight = "".concat(states.previousBodyPadding, "px");
2142
+ states.previousBodyPadding = null;
2143
+ }
2144
+ };
2394
2145
 
2395
- const bodyStyles = window.getComputedStyle(document.body);
2396
- const initialBodyOverflow = bodyStyles.overflowY;
2397
- addClasses$1(container, popup, params); // scrolling is 'hidden' until animation is done, after that 'auto'
2398
-
2399
- setTimeout(() => {
2400
- setScrollingVisibility(container, popup);
2401
- }, SHOW_CLASS_TIMEOUT);
2146
+ /*
2147
+ * Instance method to close sweetAlert
2148
+ */
2402
2149
 
2403
- if (isModal()) {
2404
- fixScrollContainer(container, params.scrollbarPadding, initialBodyOverflow);
2405
- setAriaHidden();
2150
+ function removePopupAndResetState(instance, container, returnFocus, didClose) {
2151
+ if (isToast()) {
2152
+ triggerDidCloseAndDispose(instance, didClose);
2153
+ } else {
2154
+ restoreActiveElement(returnFocus).then(() => triggerDidCloseAndDispose(instance, didClose));
2155
+ removeKeydownHandler(globalState);
2406
2156
  }
2407
2157
 
2408
- if (!isToast() && !globalState.previousActiveElement) {
2409
- globalState.previousActiveElement = document.activeElement;
2158
+ const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); // workaround for #2088
2159
+ // for some reason removing the container in Safari will scroll the document to bottom
2160
+
2161
+ if (isSafari) {
2162
+ container.setAttribute('style', 'display:none !important');
2163
+ container.removeAttribute('class');
2164
+ container.innerHTML = '';
2165
+ } else {
2166
+ container.remove();
2410
2167
  }
2411
2168
 
2412
- if (typeof params.didOpen === 'function') {
2413
- setTimeout(() => params.didOpen(popup));
2169
+ if (isModal()) {
2170
+ undoScrollbar();
2171
+ undoIOSfix();
2172
+ unsetAriaHidden();
2414
2173
  }
2415
2174
 
2416
- removeClass(container, swalClasses['no-transition']);
2417
- };
2418
- /**
2419
- * @param {AnimationEvent} event
2420
- */
2175
+ removeBodyClasses();
2176
+ }
2421
2177
 
2422
- const swalOpenAnimationFinished = event => {
2423
- const popup = getPopup();
2178
+ function removeBodyClasses() {
2179
+ removeClass([document.documentElement, document.body], [swalClasses.shown, swalClasses['height-auto'], swalClasses['no-backdrop'], swalClasses['toast-shown']]);
2180
+ }
2424
2181
 
2425
- if (event.target !== popup) {
2426
- return;
2427
- }
2182
+ function close(resolveValue) {
2183
+ resolveValue = prepareResolveValue(resolveValue);
2184
+ const swalPromiseResolve = privateMethods.swalPromiseResolve.get(this);
2185
+ const didClose = triggerClosePopup(this);
2428
2186
 
2429
- const container = getContainer();
2430
- popup.removeEventListener(animationEndEvent, swalOpenAnimationFinished);
2431
- container.style.overflowY = 'auto';
2432
- };
2433
- /**
2434
- * @param {HTMLElement} container
2435
- * @param {HTMLElement} popup
2436
- */
2187
+ if (this.isAwaitingPromise()) {
2188
+ // A swal awaiting for a promise (after a click on Confirm or Deny) cannot be dismissed anymore #2335
2189
+ if (!resolveValue.isDismissed) {
2190
+ handleAwaitingPromise(this);
2191
+ swalPromiseResolve(resolveValue);
2192
+ }
2193
+ } else if (didClose) {
2194
+ // Resolve Swal promise
2195
+ swalPromiseResolve(resolveValue);
2196
+ }
2197
+ }
2198
+ function isAwaitingPromise() {
2199
+ return !!privateProps.awaitingPromise.get(this);
2200
+ }
2437
2201
 
2202
+ const triggerClosePopup = instance => {
2203
+ const popup = getPopup();
2438
2204
 
2439
- const setScrollingVisibility = (container, popup) => {
2440
- if (animationEndEvent && hasCssAnimation(popup)) {
2441
- container.style.overflowY = 'hidden';
2442
- popup.addEventListener(animationEndEvent, swalOpenAnimationFinished);
2443
- } else {
2444
- container.style.overflowY = 'auto';
2205
+ if (!popup) {
2206
+ return false;
2445
2207
  }
2446
- };
2447
- /**
2448
- * @param {HTMLElement} container
2449
- * @param {boolean} scrollbarPadding
2450
- * @param {string} initialBodyOverflow
2451
- */
2452
2208
 
2209
+ const innerParams = privateProps.innerParams.get(instance);
2210
+
2211
+ if (!innerParams || hasClass(popup, innerParams.hideClass.popup)) {
2212
+ return false;
2213
+ }
2453
2214
 
2454
- const fixScrollContainer = (container, scrollbarPadding, initialBodyOverflow) => {
2455
- iOSfix();
2215
+ removeClass(popup, innerParams.showClass.popup);
2216
+ addClass(popup, innerParams.hideClass.popup);
2217
+ const backdrop = getContainer();
2218
+ removeClass(backdrop, innerParams.showClass.backdrop);
2219
+ addClass(backdrop, innerParams.hideClass.backdrop);
2220
+ handlePopupAnimation(instance, popup, innerParams);
2221
+ return true;
2222
+ };
2456
2223
 
2457
- if (scrollbarPadding && initialBodyOverflow !== 'hidden') {
2458
- fixScrollbar();
2459
- } // sweetalert2/issues/1247
2224
+ function rejectPromise(error) {
2225
+ const rejectPromise = privateMethods.swalPromiseReject.get(this);
2226
+ handleAwaitingPromise(this);
2460
2227
 
2228
+ if (rejectPromise) {
2229
+ // Reject Swal promise
2230
+ rejectPromise(error);
2231
+ }
2232
+ }
2233
+ const handleAwaitingPromise = instance => {
2234
+ if (instance.isAwaitingPromise()) {
2235
+ privateProps.awaitingPromise.delete(instance); // The instance might have been previously partly destroyed, we must resume the destroy process in this case #2335
2461
2236
 
2462
- setTimeout(() => {
2463
- container.scrollTop = 0;
2464
- });
2237
+ if (!privateProps.innerParams.get(instance)) {
2238
+ instance._destroy();
2239
+ }
2240
+ }
2465
2241
  };
2466
- /**
2467
- * @param {HTMLElement} container
2468
- * @param {HTMLElement} popup
2469
- * @param {SweetAlertOptions} params
2470
- */
2471
2242
 
2243
+ const prepareResolveValue = resolveValue => {
2244
+ // When user calls Swal.close()
2245
+ if (typeof resolveValue === 'undefined') {
2246
+ return {
2247
+ isConfirmed: false,
2248
+ isDenied: false,
2249
+ isDismissed: true
2250
+ };
2251
+ }
2472
2252
 
2473
- const addClasses$1 = (container, popup, params) => {
2474
- addClass(container, params.showClass.backdrop); // this workaround with opacity is needed for https://github.com/sweetalert2/sweetalert2/issues/2059
2253
+ return Object.assign({
2254
+ isConfirmed: false,
2255
+ isDenied: false,
2256
+ isDismissed: false
2257
+ }, resolveValue);
2258
+ };
2475
2259
 
2476
- popup.style.setProperty('opacity', '0', 'important');
2477
- show(popup, 'grid');
2478
- setTimeout(() => {
2479
- // Animate popup right after showing it
2480
- addClass(popup, params.showClass.popup); // and remove the opacity workaround
2260
+ const handlePopupAnimation = (instance, popup, innerParams) => {
2261
+ const container = getContainer(); // If animation is supported, animate
2481
2262
 
2482
- popup.style.removeProperty('opacity');
2483
- }, SHOW_CLASS_TIMEOUT); // 10ms in order to fix #2062
2263
+ const animationIsSupported = animationEndEvent && hasCssAnimation(popup);
2484
2264
 
2485
- addClass([document.documentElement, document.body], swalClasses.shown);
2265
+ if (typeof innerParams.willClose === 'function') {
2266
+ innerParams.willClose(popup);
2267
+ }
2486
2268
 
2487
- if (params.heightAuto && params.backdrop && !params.toast) {
2488
- addClass([document.documentElement, document.body], swalClasses['height-auto']);
2269
+ if (animationIsSupported) {
2270
+ animatePopup(instance, popup, container, innerParams.returnFocus, innerParams.didClose);
2271
+ } else {
2272
+ // Otherwise, remove immediately
2273
+ removePopupAndResetState(instance, container, innerParams.returnFocus, innerParams.didClose);
2489
2274
  }
2490
2275
  };
2491
2276
 
2492
- /**
2493
- * Shows loader (spinner), this is useful with AJAX requests.
2494
- * By default the loader be shown instead of the "Confirm" button.
2495
- */
2277
+ const animatePopup = (instance, popup, container, returnFocus, didClose) => {
2278
+ globalState.swalCloseEventFinishedCallback = removePopupAndResetState.bind(null, instance, container, returnFocus, didClose);
2279
+ popup.addEventListener(animationEndEvent, function (e) {
2280
+ if (e.target === popup) {
2281
+ globalState.swalCloseEventFinishedCallback();
2282
+ delete globalState.swalCloseEventFinishedCallback;
2283
+ }
2284
+ });
2285
+ };
2496
2286
 
2497
- const showLoading = buttonToReplace => {
2498
- let popup = getPopup();
2287
+ const triggerDidCloseAndDispose = (instance, didClose) => {
2288
+ setTimeout(() => {
2289
+ if (typeof didClose === 'function') {
2290
+ didClose.bind(instance.params)();
2291
+ }
2499
2292
 
2500
- if (!popup) {
2501
- new Swal(); // eslint-disable-line no-new
2293
+ instance._destroy();
2294
+ });
2295
+ };
2296
+
2297
+ function setButtonsDisabled(instance, buttons, disabled) {
2298
+ const domCache = privateProps.domCache.get(instance);
2299
+ buttons.forEach(button => {
2300
+ domCache[button].disabled = disabled;
2301
+ });
2302
+ }
2303
+
2304
+ function setInputDisabled(input, disabled) {
2305
+ if (!input) {
2306
+ return false;
2502
2307
  }
2503
2308
 
2504
- popup = getPopup();
2505
- const loader = getLoader();
2309
+ if (input.type === 'radio') {
2310
+ const radiosContainer = input.parentNode.parentNode;
2311
+ const radios = radiosContainer.querySelectorAll('input');
2506
2312
 
2507
- if (isToast()) {
2508
- hide(getIcon());
2313
+ for (let i = 0; i < radios.length; i++) {
2314
+ radios[i].disabled = disabled;
2315
+ }
2509
2316
  } else {
2510
- replaceButton(popup, buttonToReplace);
2317
+ input.disabled = disabled;
2511
2318
  }
2319
+ }
2512
2320
 
2513
- show(loader);
2514
- popup.setAttribute('data-loading', 'true');
2515
- popup.setAttribute('aria-busy', 'true');
2516
- popup.focus();
2517
- };
2321
+ function enableButtons() {
2322
+ setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], false);
2323
+ }
2324
+ function disableButtons() {
2325
+ setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], true);
2326
+ }
2327
+ function enableInput() {
2328
+ return setInputDisabled(this.getInput(), false);
2329
+ }
2330
+ function disableInput() {
2331
+ return setInputDisabled(this.getInput(), true);
2332
+ }
2518
2333
 
2519
- const replaceButton = (popup, buttonToReplace) => {
2520
- const actions = getActions();
2521
- const loader = getLoader();
2334
+ function showValidationMessage(error) {
2335
+ const domCache = privateProps.domCache.get(this);
2336
+ const params = privateProps.innerParams.get(this);
2337
+ setInnerHtml(domCache.validationMessage, error);
2338
+ domCache.validationMessage.className = swalClasses['validation-message'];
2522
2339
 
2523
- if (!buttonToReplace && isVisible(getConfirmButton())) {
2524
- buttonToReplace = getConfirmButton();
2340
+ if (params.customClass && params.customClass.validationMessage) {
2341
+ addClass(domCache.validationMessage, params.customClass.validationMessage);
2525
2342
  }
2526
2343
 
2527
- show(actions);
2344
+ show(domCache.validationMessage);
2345
+ const input = this.getInput();
2528
2346
 
2529
- if (buttonToReplace) {
2530
- hide(buttonToReplace);
2531
- loader.setAttribute('data-button-to-replace', buttonToReplace.className);
2347
+ if (input) {
2348
+ input.setAttribute('aria-invalid', true);
2349
+ input.setAttribute('aria-describedby', swalClasses['validation-message']);
2350
+ focusInput(input);
2351
+ addClass(input, swalClasses.inputerror);
2532
2352
  }
2353
+ } // Hide block with validation message
2533
2354
 
2534
- loader.parentNode.insertBefore(loader, buttonToReplace);
2535
- addClass([popup, actions], swalClasses.loading);
2536
- };
2537
-
2538
- const handleInputOptionsAndValue = (instance, params) => {
2539
- if (params.input === 'select' || params.input === 'radio') {
2540
- handleInputOptions(instance, params);
2541
- } else if (['text', 'email', 'number', 'tel', 'textarea'].includes(params.input) && (hasToPromiseFn(params.inputValue) || isPromise(params.inputValue))) {
2542
- showLoading(getConfirmButton());
2543
- handleInputValue(instance, params);
2544
- }
2545
- };
2546
- const getInputValue = (instance, innerParams) => {
2547
- const input = instance.getInput();
2355
+ function resetValidationMessage$1() {
2356
+ const domCache = privateProps.domCache.get(this);
2548
2357
 
2549
- if (!input) {
2550
- return null;
2358
+ if (domCache.validationMessage) {
2359
+ hide(domCache.validationMessage);
2551
2360
  }
2552
2361
 
2553
- switch (innerParams.input) {
2554
- case 'checkbox':
2555
- return getCheckboxValue(input);
2362
+ const input = this.getInput();
2363
+
2364
+ if (input) {
2365
+ input.removeAttribute('aria-invalid');
2366
+ input.removeAttribute('aria-describedby');
2367
+ removeClass(input, swalClasses.inputerror);
2368
+ }
2369
+ }
2370
+
2371
+ function getProgressSteps$1() {
2372
+ const domCache = privateProps.domCache.get(this);
2373
+ return domCache.progressSteps;
2374
+ }
2375
+
2376
+ const defaultParams = {
2377
+ title: '',
2378
+ titleText: '',
2379
+ text: '',
2380
+ html: '',
2381
+ footer: '',
2382
+ icon: undefined,
2383
+ iconColor: undefined,
2384
+ iconHtml: undefined,
2385
+ template: undefined,
2386
+ toast: false,
2387
+ showClass: {
2388
+ popup: 'swal2-show',
2389
+ backdrop: 'swal2-backdrop-show',
2390
+ icon: 'swal2-icon-show'
2391
+ },
2392
+ hideClass: {
2393
+ popup: 'swal2-hide',
2394
+ backdrop: 'swal2-backdrop-hide',
2395
+ icon: 'swal2-icon-hide'
2396
+ },
2397
+ customClass: {},
2398
+ target: 'body',
2399
+ color: undefined,
2400
+ backdrop: true,
2401
+ heightAuto: true,
2402
+ allowOutsideClick: true,
2403
+ allowEscapeKey: true,
2404
+ allowEnterKey: true,
2405
+ stopKeydownPropagation: true,
2406
+ keydownListenerCapture: false,
2407
+ showConfirmButton: true,
2408
+ showDenyButton: false,
2409
+ showCancelButton: false,
2410
+ preConfirm: undefined,
2411
+ preDeny: undefined,
2412
+ confirmButtonText: 'OK',
2413
+ confirmButtonAriaLabel: '',
2414
+ confirmButtonColor: undefined,
2415
+ denyButtonText: 'No',
2416
+ denyButtonAriaLabel: '',
2417
+ denyButtonColor: undefined,
2418
+ cancelButtonText: 'Cancel',
2419
+ cancelButtonAriaLabel: '',
2420
+ cancelButtonColor: undefined,
2421
+ buttonsStyling: true,
2422
+ reverseButtons: false,
2423
+ focusConfirm: true,
2424
+ focusDeny: false,
2425
+ focusCancel: false,
2426
+ returnFocus: true,
2427
+ showCloseButton: false,
2428
+ closeButtonHtml: '&times;',
2429
+ closeButtonAriaLabel: 'Close this dialog',
2430
+ loaderHtml: '',
2431
+ showLoaderOnConfirm: false,
2432
+ showLoaderOnDeny: false,
2433
+ imageUrl: undefined,
2434
+ imageWidth: undefined,
2435
+ imageHeight: undefined,
2436
+ imageAlt: '',
2437
+ timer: undefined,
2438
+ timerProgressBar: false,
2439
+ width: undefined,
2440
+ padding: undefined,
2441
+ background: undefined,
2442
+ input: undefined,
2443
+ inputPlaceholder: '',
2444
+ inputLabel: '',
2445
+ inputValue: '',
2446
+ inputOptions: {},
2447
+ inputAutoTrim: true,
2448
+ inputAttributes: {},
2449
+ inputValidator: undefined,
2450
+ returnInputValueOnDeny: false,
2451
+ validationMessage: undefined,
2452
+ grow: false,
2453
+ position: 'center',
2454
+ progressSteps: [],
2455
+ currentProgressStep: undefined,
2456
+ progressStepsDistance: undefined,
2457
+ willOpen: undefined,
2458
+ didOpen: undefined,
2459
+ didRender: undefined,
2460
+ willClose: undefined,
2461
+ didClose: undefined,
2462
+ didDestroy: undefined,
2463
+ scrollbarPadding: true
2464
+ };
2465
+ 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'];
2466
+ const deprecatedParams = {};
2467
+ const toastIncompatibleParams = ['allowOutsideClick', 'allowEnterKey', 'backdrop', 'focusConfirm', 'focusDeny', 'focusCancel', 'returnFocus', 'heightAuto', 'keydownListenerCapture'];
2468
+ /**
2469
+ * Is valid parameter
2470
+ *
2471
+ * @param {string} paramName
2472
+ * @returns {boolean}
2473
+ */
2474
+
2475
+ const isValidParameter = paramName => {
2476
+ return Object.prototype.hasOwnProperty.call(defaultParams, paramName);
2477
+ };
2478
+ /**
2479
+ * Is valid parameter for Swal.update() method
2480
+ *
2481
+ * @param {string} paramName
2482
+ * @returns {boolean}
2483
+ */
2484
+
2485
+ const isUpdatableParameter = paramName => {
2486
+ return updatableParams.indexOf(paramName) !== -1;
2487
+ };
2488
+ /**
2489
+ * Is deprecated parameter
2490
+ *
2491
+ * @param {string} paramName
2492
+ * @returns {string | undefined}
2493
+ */
2494
+
2495
+ const isDeprecatedParameter = paramName => {
2496
+ return deprecatedParams[paramName];
2497
+ };
2498
+ /**
2499
+ * @param {string} param
2500
+ */
2501
+
2502
+ const checkIfParamIsValid = param => {
2503
+ if (!isValidParameter(param)) {
2504
+ warn("Unknown parameter \"".concat(param, "\""));
2505
+ }
2506
+ };
2507
+ /**
2508
+ * @param {string} param
2509
+ */
2510
+
2511
+
2512
+ const checkIfToastParamIsValid = param => {
2513
+ if (toastIncompatibleParams.includes(param)) {
2514
+ warn("The parameter \"".concat(param, "\" is incompatible with toasts"));
2515
+ }
2516
+ };
2517
+ /**
2518
+ * @param {string} param
2519
+ */
2520
+
2521
+
2522
+ const checkIfParamIsDeprecated = param => {
2523
+ if (isDeprecatedParameter(param)) {
2524
+ warnAboutDeprecation(param, isDeprecatedParameter(param));
2525
+ }
2526
+ };
2527
+ /**
2528
+ * Show relevant warnings for given params
2529
+ *
2530
+ * @param {SweetAlertOptions} params
2531
+ */
2532
+
2533
+
2534
+ const showWarningsForParams = params => {
2535
+ if (!params.backdrop && params.allowOutsideClick) {
2536
+ warn('"allowOutsideClick" parameter requires `backdrop` parameter to be set to `true`');
2537
+ }
2538
+
2539
+ for (const param in params) {
2540
+ checkIfParamIsValid(param);
2541
+
2542
+ if (params.toast) {
2543
+ checkIfToastParamIsValid(param);
2544
+ }
2545
+
2546
+ checkIfParamIsDeprecated(param);
2547
+ }
2548
+ };
2549
+
2550
+ /**
2551
+ * Updates popup parameters.
2552
+ */
2553
+
2554
+ function update(params) {
2555
+ const popup = getPopup();
2556
+ const innerParams = privateProps.innerParams.get(this);
2557
+
2558
+ if (!popup || hasClass(popup, innerParams.hideClass.popup)) {
2559
+ return warn("You're trying to update the closed or closing popup, that won't work. Use the update() method in preConfirm parameter or show a new popup.");
2560
+ }
2561
+
2562
+ const validUpdatableParams = filterValidParams(params);
2563
+ const updatedParams = Object.assign({}, innerParams, validUpdatableParams);
2564
+ render(this, updatedParams);
2565
+ privateProps.innerParams.set(this, updatedParams);
2566
+ Object.defineProperties(this, {
2567
+ params: {
2568
+ value: Object.assign({}, this.params, params),
2569
+ writable: false,
2570
+ enumerable: true
2571
+ }
2572
+ });
2573
+ }
2574
+
2575
+ const filterValidParams = params => {
2576
+ const validUpdatableParams = {};
2577
+ Object.keys(params).forEach(param => {
2578
+ if (isUpdatableParameter(param)) {
2579
+ validUpdatableParams[param] = params[param];
2580
+ } else {
2581
+ warn("Invalid parameter to update: ".concat(param));
2582
+ }
2583
+ });
2584
+ return validUpdatableParams;
2585
+ };
2586
+
2587
+ function _destroy() {
2588
+ const domCache = privateProps.domCache.get(this);
2589
+ const innerParams = privateProps.innerParams.get(this);
2590
+
2591
+ if (!innerParams) {
2592
+ disposeWeakMaps(this); // The WeakMaps might have been partly destroyed, we must recall it to dispose any remaining WeakMaps #2335
2593
+
2594
+ return; // This instance has already been destroyed
2595
+ } // Check if there is another Swal closing
2596
+
2597
+
2598
+ if (domCache.popup && globalState.swalCloseEventFinishedCallback) {
2599
+ globalState.swalCloseEventFinishedCallback();
2600
+ delete globalState.swalCloseEventFinishedCallback;
2601
+ }
2602
+
2603
+ if (typeof innerParams.didDestroy === 'function') {
2604
+ innerParams.didDestroy();
2605
+ }
2606
+
2607
+ disposeSwal(this);
2608
+ }
2609
+ /**
2610
+ * @param {SweetAlert2} instance
2611
+ */
2612
+
2613
+ const disposeSwal = instance => {
2614
+ disposeWeakMaps(instance); // Unset this.params so GC will dispose it (#1569)
2615
+ // @ts-ignore
2616
+
2617
+ delete instance.params; // Unset globalState props so GC will dispose globalState (#1569)
2618
+
2619
+ delete globalState.keydownHandler;
2620
+ delete globalState.keydownTarget; // Unset currentInstance
2621
+
2622
+ delete globalState.currentInstance;
2623
+ };
2624
+ /**
2625
+ * @param {SweetAlert2} instance
2626
+ */
2627
+
2628
+
2629
+ const disposeWeakMaps = instance => {
2630
+ // If the current instance is awaiting a promise result, we keep the privateMethods to call them once the promise result is retrieved #2335
2631
+ // @ts-ignore
2632
+ if (instance.isAwaitingPromise()) {
2633
+ unsetWeakMaps(privateProps, instance);
2634
+ privateProps.awaitingPromise.set(instance, true);
2635
+ } else {
2636
+ unsetWeakMaps(privateMethods, instance);
2637
+ unsetWeakMaps(privateProps, instance);
2638
+ }
2639
+ };
2640
+ /**
2641
+ * @param {object} obj
2642
+ * @param {SweetAlert2} instance
2643
+ */
2644
+
2645
+
2646
+ const unsetWeakMaps = (obj, instance) => {
2647
+ for (const i in obj) {
2648
+ obj[i].delete(instance);
2649
+ }
2650
+ };
2651
+
2652
+
2653
+
2654
+ var instanceMethods = /*#__PURE__*/Object.freeze({
2655
+ hideLoading: hideLoading,
2656
+ disableLoading: hideLoading,
2657
+ getInput: getInput$1,
2658
+ close: close,
2659
+ isAwaitingPromise: isAwaitingPromise,
2660
+ rejectPromise: rejectPromise,
2661
+ handleAwaitingPromise: handleAwaitingPromise,
2662
+ closePopup: close,
2663
+ closeModal: close,
2664
+ closeToast: close,
2665
+ enableButtons: enableButtons,
2666
+ disableButtons: disableButtons,
2667
+ enableInput: enableInput,
2668
+ disableInput: disableInput,
2669
+ showValidationMessage: showValidationMessage,
2670
+ resetValidationMessage: resetValidationMessage$1,
2671
+ getProgressSteps: getProgressSteps$1,
2672
+ update: update,
2673
+ _destroy: _destroy
2674
+ });
2675
+
2676
+ /**
2677
+ * Shows loader (spinner), this is useful with AJAX requests.
2678
+ * By default the loader be shown instead of the "Confirm" button.
2679
+ */
2680
+
2681
+ const showLoading = buttonToReplace => {
2682
+ let popup = getPopup();
2683
+
2684
+ if (!popup) {
2685
+ new Swal(); // eslint-disable-line no-new
2686
+ }
2687
+
2688
+ popup = getPopup();
2689
+ const loader = getLoader();
2690
+
2691
+ if (isToast()) {
2692
+ hide(getIcon());
2693
+ } else {
2694
+ replaceButton(popup, buttonToReplace);
2695
+ }
2696
+
2697
+ show(loader);
2698
+ popup.setAttribute('data-loading', 'true');
2699
+ popup.setAttribute('aria-busy', 'true');
2700
+ popup.focus();
2701
+ };
2702
+
2703
+ const replaceButton = (popup, buttonToReplace) => {
2704
+ const actions = getActions();
2705
+ const loader = getLoader();
2706
+
2707
+ if (!buttonToReplace && isVisible(getConfirmButton())) {
2708
+ buttonToReplace = getConfirmButton();
2709
+ }
2710
+
2711
+ show(actions);
2712
+
2713
+ if (buttonToReplace) {
2714
+ hide(buttonToReplace);
2715
+ loader.setAttribute('data-button-to-replace', buttonToReplace.className);
2716
+ }
2717
+
2718
+ loader.parentNode.insertBefore(loader, buttonToReplace);
2719
+ addClass([popup, actions], swalClasses.loading);
2720
+ };
2721
+
2722
+ const handleInputOptionsAndValue = (instance, params) => {
2723
+ if (params.input === 'select' || params.input === 'radio') {
2724
+ handleInputOptions(instance, params);
2725
+ } else if (['text', 'email', 'number', 'tel', 'textarea'].includes(params.input) && (hasToPromiseFn(params.inputValue) || isPromise(params.inputValue))) {
2726
+ showLoading(getConfirmButton());
2727
+ handleInputValue(instance, params);
2728
+ }
2729
+ };
2730
+ const getInputValue = (instance, innerParams) => {
2731
+ const input = instance.getInput();
2732
+
2733
+ if (!input) {
2734
+ return null;
2735
+ }
2736
+
2737
+ switch (innerParams.input) {
2738
+ case 'checkbox':
2739
+ return getCheckboxValue(input);
2556
2740
 
2557
2741
  case 'radio':
2558
2742
  return getRadioValue(input);
@@ -2614,1195 +2798,1032 @@
2614
2798
  const option = document.createElement('option');
2615
2799
  option.value = optionValue;
2616
2800
  setInnerHtml(option, optionLabel);
2617
- option.selected = isSelected(optionValue, params.inputValue);
2618
- parent.appendChild(option);
2619
- };
2620
-
2621
- inputOptions.forEach(inputOption => {
2622
- const optionValue = inputOption[0];
2623
- const optionLabel = inputOption[1]; // <optgroup> spec:
2624
- // https://www.w3.org/TR/html401/interact/forms.html#h-17.6
2625
- // "...all OPTGROUP elements must be specified directly within a SELECT element (i.e., groups may not be nested)..."
2626
- // check whether this is a <optgroup>
2627
-
2628
- if (Array.isArray(optionLabel)) {
2629
- // if it is an array, then it is an <optgroup>
2630
- const optgroup = document.createElement('optgroup');
2631
- optgroup.label = optionValue;
2632
- optgroup.disabled = false; // not configurable for now
2633
-
2634
- select.appendChild(optgroup);
2635
- optionLabel.forEach(o => renderOption(optgroup, o[1], o[0]));
2636
- } else {
2637
- // case of <option>
2638
- renderOption(select, optionLabel, optionValue);
2639
- }
2640
- });
2641
- select.focus();
2642
- },
2643
- radio: (popup, inputOptions, params) => {
2644
- const radio = getDirectChildByClass(popup, swalClasses.radio);
2645
- inputOptions.forEach(inputOption => {
2646
- const radioValue = inputOption[0];
2647
- const radioLabel = inputOption[1];
2648
- const radioInput = document.createElement('input');
2649
- const radioLabelElement = document.createElement('label');
2650
- radioInput.type = 'radio';
2651
- radioInput.name = swalClasses.radio;
2652
- radioInput.value = radioValue;
2653
-
2654
- if (isSelected(radioValue, params.inputValue)) {
2655
- radioInput.checked = true;
2656
- }
2657
-
2658
- const label = document.createElement('span');
2659
- setInnerHtml(label, radioLabel);
2660
- label.className = swalClasses.label;
2661
- radioLabelElement.appendChild(radioInput);
2662
- radioLabelElement.appendChild(label);
2663
- radio.appendChild(radioLabelElement);
2664
- });
2665
- const radios = radio.querySelectorAll('input');
2666
-
2667
- if (radios.length) {
2668
- radios[0].focus();
2669
- }
2670
- }
2671
- };
2672
- /**
2673
- * Converts `inputOptions` into an array of `[value, label]`s
2674
- * @param inputOptions
2675
- */
2676
-
2677
- const formatInputOptions = inputOptions => {
2678
- const result = [];
2679
-
2680
- if (typeof Map !== 'undefined' && inputOptions instanceof Map) {
2681
- inputOptions.forEach((value, key) => {
2682
- let valueFormatted = value;
2683
-
2684
- if (typeof valueFormatted === 'object') {
2685
- // case of <optgroup>
2686
- valueFormatted = formatInputOptions(valueFormatted);
2687
- }
2688
-
2689
- result.push([key, valueFormatted]);
2690
- });
2691
- } else {
2692
- Object.keys(inputOptions).forEach(key => {
2693
- let valueFormatted = inputOptions[key];
2694
-
2695
- if (typeof valueFormatted === 'object') {
2696
- // case of <optgroup>
2697
- valueFormatted = formatInputOptions(valueFormatted);
2698
- }
2699
-
2700
- result.push([key, valueFormatted]);
2701
- });
2702
- }
2703
-
2704
- return result;
2705
- };
2706
-
2707
- const isSelected = (optionValue, inputValue) => {
2708
- return inputValue && inputValue.toString() === optionValue.toString();
2709
- };
2710
-
2711
- /**
2712
- * Hides loader and shows back the button which was hidden by .showLoading()
2713
- */
2714
-
2715
- function hideLoading() {
2716
- // do nothing if popup is closed
2717
- const innerParams = privateProps.innerParams.get(this);
2718
-
2719
- if (!innerParams) {
2720
- return;
2721
- }
2722
-
2723
- const domCache = privateProps.domCache.get(this);
2724
- hide(domCache.loader);
2725
-
2726
- if (isToast()) {
2727
- if (innerParams.icon) {
2728
- show(getIcon());
2729
- }
2730
- } else {
2731
- showRelatedButton(domCache);
2732
- }
2733
-
2734
- removeClass([domCache.popup, domCache.actions], swalClasses.loading);
2735
- domCache.popup.removeAttribute('aria-busy');
2736
- domCache.popup.removeAttribute('data-loading');
2737
- domCache.confirmButton.disabled = false;
2738
- domCache.denyButton.disabled = false;
2739
- domCache.cancelButton.disabled = false;
2740
- }
2741
-
2742
- const showRelatedButton = domCache => {
2743
- const buttonToReplace = domCache.popup.getElementsByClassName(domCache.loader.getAttribute('data-button-to-replace'));
2744
-
2745
- if (buttonToReplace.length) {
2746
- show(buttonToReplace[0], 'inline-block');
2747
- } else if (allButtonsAreHidden()) {
2748
- hide(domCache.actions);
2749
- }
2750
- };
2751
-
2752
- /**
2753
- * Gets the input DOM node, this method works with input parameter.
2754
- * @returns {HTMLElement | null}
2755
- */
2756
-
2757
- function getInput$1(instance) {
2758
- const innerParams = privateProps.innerParams.get(instance || this);
2759
- const domCache = privateProps.domCache.get(instance || this);
2760
-
2761
- if (!domCache) {
2762
- return null;
2763
- }
2764
-
2765
- return getInput(domCache.popup, innerParams.input);
2766
- }
2767
-
2768
- /**
2769
- * This module contains `WeakMap`s for each effectively-"private property" that a `Swal` has.
2770
- * For example, to set the private property "foo" of `this` to "bar", you can `privateProps.foo.set(this, 'bar')`
2771
- * This is the approach that Babel will probably take to implement private methods/fields
2772
- * https://github.com/tc39/proposal-private-methods
2773
- * https://github.com/babel/babel/pull/7555
2774
- * Once we have the changes from that PR in Babel, and our core class fits reasonable in *one module*
2775
- * then we can use that language feature.
2776
- */
2777
- var privateMethods = {
2778
- swalPromiseResolve: new WeakMap(),
2779
- swalPromiseReject: new WeakMap()
2780
- };
2781
-
2782
- /*
2783
- * Global function to determine if SweetAlert2 popup is shown
2784
- */
2785
-
2786
- const isVisible$1 = () => {
2787
- return isVisible(getPopup());
2788
- };
2789
- /*
2790
- * Global function to click 'Confirm' button
2791
- */
2792
-
2793
- const clickConfirm = () => getConfirmButton() && getConfirmButton().click();
2794
- /*
2795
- * Global function to click 'Deny' button
2796
- */
2797
-
2798
- const clickDeny = () => getDenyButton() && getDenyButton().click();
2799
- /*
2800
- * Global function to click 'Cancel' button
2801
- */
2801
+ option.selected = isSelected(optionValue, params.inputValue);
2802
+ parent.appendChild(option);
2803
+ };
2802
2804
 
2803
- const clickCancel = () => getCancelButton() && getCancelButton().click();
2805
+ inputOptions.forEach(inputOption => {
2806
+ const optionValue = inputOption[0];
2807
+ const optionLabel = inputOption[1]; // <optgroup> spec:
2808
+ // https://www.w3.org/TR/html401/interact/forms.html#h-17.6
2809
+ // "...all OPTGROUP elements must be specified directly within a SELECT element (i.e., groups may not be nested)..."
2810
+ // check whether this is a <optgroup>
2804
2811
 
2805
- /**
2806
- * @param {GlobalState} globalState
2807
- */
2812
+ if (Array.isArray(optionLabel)) {
2813
+ // if it is an array, then it is an <optgroup>
2814
+ const optgroup = document.createElement('optgroup');
2815
+ optgroup.label = optionValue;
2816
+ optgroup.disabled = false; // not configurable for now
2808
2817
 
2809
- const removeKeydownHandler = globalState => {
2810
- if (globalState.keydownTarget && globalState.keydownHandlerAdded) {
2811
- globalState.keydownTarget.removeEventListener('keydown', globalState.keydownHandler, {
2812
- capture: globalState.keydownListenerCapture
2818
+ select.appendChild(optgroup);
2819
+ optionLabel.forEach(o => renderOption(optgroup, o[1], o[0]));
2820
+ } else {
2821
+ // case of <option>
2822
+ renderOption(select, optionLabel, optionValue);
2823
+ }
2813
2824
  });
2814
- globalState.keydownHandlerAdded = false;
2815
- }
2816
- };
2817
- /**
2818
- * @param {SweetAlert2} instance
2819
- * @param {GlobalState} globalState
2820
- * @param {SweetAlertOptions} innerParams
2821
- * @param {*} dismissWith
2822
- */
2823
-
2824
- const addKeydownHandler = (instance, globalState, innerParams, dismissWith) => {
2825
- removeKeydownHandler(globalState);
2825
+ select.focus();
2826
+ },
2827
+ radio: (popup, inputOptions, params) => {
2828
+ const radio = getDirectChildByClass(popup, swalClasses.radio);
2829
+ inputOptions.forEach(inputOption => {
2830
+ const radioValue = inputOption[0];
2831
+ const radioLabel = inputOption[1];
2832
+ const radioInput = document.createElement('input');
2833
+ const radioLabelElement = document.createElement('label');
2834
+ radioInput.type = 'radio';
2835
+ radioInput.name = swalClasses.radio;
2836
+ radioInput.value = radioValue;
2826
2837
 
2827
- if (!innerParams.toast) {
2828
- globalState.keydownHandler = e => keydownHandler(instance, e, dismissWith);
2838
+ if (isSelected(radioValue, params.inputValue)) {
2839
+ radioInput.checked = true;
2840
+ }
2829
2841
 
2830
- globalState.keydownTarget = innerParams.keydownListenerCapture ? window : getPopup();
2831
- globalState.keydownListenerCapture = innerParams.keydownListenerCapture;
2832
- globalState.keydownTarget.addEventListener('keydown', globalState.keydownHandler, {
2833
- capture: globalState.keydownListenerCapture
2842
+ const label = document.createElement('span');
2843
+ setInnerHtml(label, radioLabel);
2844
+ label.className = swalClasses.label;
2845
+ radioLabelElement.appendChild(radioInput);
2846
+ radioLabelElement.appendChild(label);
2847
+ radio.appendChild(radioLabelElement);
2834
2848
  });
2835
- globalState.keydownHandlerAdded = true;
2849
+ const radios = radio.querySelectorAll('input');
2850
+
2851
+ if (radios.length) {
2852
+ radios[0].focus();
2853
+ }
2836
2854
  }
2837
2855
  };
2838
2856
  /**
2839
- * @param {SweetAlertOptions} innerParams
2840
- * @param {number} index
2841
- * @param {number} increment
2857
+ * Converts `inputOptions` into an array of `[value, label]`s
2858
+ * @param inputOptions
2842
2859
  */
2843
2860
 
2844
- const setFocus = (innerParams, index, increment) => {
2845
- const focusableElements = getFocusableElements(); // search for visible elements and select the next possible match
2861
+ const formatInputOptions = inputOptions => {
2862
+ const result = [];
2846
2863
 
2847
- if (focusableElements.length) {
2848
- index = index + increment; // rollover to first item
2864
+ if (typeof Map !== 'undefined' && inputOptions instanceof Map) {
2865
+ inputOptions.forEach((value, key) => {
2866
+ let valueFormatted = value;
2849
2867
 
2850
- if (index === focusableElements.length) {
2851
- index = 0; // go to last item
2852
- } else if (index === -1) {
2853
- index = focusableElements.length - 1;
2854
- }
2868
+ if (typeof valueFormatted === 'object') {
2869
+ // case of <optgroup>
2870
+ valueFormatted = formatInputOptions(valueFormatted);
2871
+ }
2855
2872
 
2856
- return focusableElements[index].focus();
2857
- } // no visible focusable elements, focus the popup
2873
+ result.push([key, valueFormatted]);
2874
+ });
2875
+ } else {
2876
+ Object.keys(inputOptions).forEach(key => {
2877
+ let valueFormatted = inputOptions[key];
2878
+
2879
+ if (typeof valueFormatted === 'object') {
2880
+ // case of <optgroup>
2881
+ valueFormatted = formatInputOptions(valueFormatted);
2882
+ }
2858
2883
 
2884
+ result.push([key, valueFormatted]);
2885
+ });
2886
+ }
2859
2887
 
2860
- getPopup().focus();
2888
+ return result;
2861
2889
  };
2862
- const arrowKeysNextButton = ['ArrowRight', 'ArrowDown'];
2863
- const arrowKeysPreviousButton = ['ArrowLeft', 'ArrowUp'];
2890
+
2891
+ const isSelected = (optionValue, inputValue) => {
2892
+ return inputValue && inputValue.toString() === optionValue.toString();
2893
+ };
2894
+
2864
2895
  /**
2865
2896
  * @param {SweetAlert2} instance
2866
- * @param {KeyboardEvent} e
2867
- * @param {function} dismissWith
2868
2897
  */
2869
2898
 
2870
- const keydownHandler = (instance, e, dismissWith) => {
2899
+ const handleConfirmButtonClick = instance => {
2871
2900
  const innerParams = privateProps.innerParams.get(instance);
2901
+ instance.disableButtons();
2872
2902
 
2873
- if (!innerParams) {
2874
- return; // This instance has already been destroyed
2875
- } // Ignore keydown during IME composition
2876
- // https://developer.mozilla.org/en-US/docs/Web/API/Document/keydown_event#ignoring_keydown_during_ime_composition
2877
- // https://github.com/sweetalert2/sweetalert2/issues/720
2878
- // https://github.com/sweetalert2/sweetalert2/issues/2406
2879
-
2880
-
2881
- if (e.isComposing || e.keyCode === 229) {
2882
- return;
2883
- }
2884
-
2885
- if (innerParams.stopKeydownPropagation) {
2886
- e.stopPropagation();
2887
- } // ENTER
2888
-
2889
-
2890
- if (e.key === 'Enter') {
2891
- handleEnter(instance, e, innerParams);
2892
- } // TAB
2893
- else if (e.key === 'Tab') {
2894
- handleTab(e, innerParams);
2895
- } // ARROWS - switch focus between buttons
2896
- else if ([...arrowKeysNextButton, ...arrowKeysPreviousButton].includes(e.key)) {
2897
- handleArrows(e.key);
2898
- } // ESC
2899
- else if (e.key === 'Escape') {
2900
- handleEsc(e, innerParams, dismissWith);
2903
+ if (innerParams.input) {
2904
+ handleConfirmOrDenyWithInput(instance, 'confirm');
2905
+ } else {
2906
+ confirm(instance, true);
2901
2907
  }
2902
2908
  };
2903
2909
  /**
2904
2910
  * @param {SweetAlert2} instance
2905
- * @param {KeyboardEvent} e
2906
- * @param {SweetAlertOptions} innerParams
2907
2911
  */
2908
2912
 
2913
+ const handleDenyButtonClick = instance => {
2914
+ const innerParams = privateProps.innerParams.get(instance);
2915
+ instance.disableButtons();
2909
2916
 
2910
- const handleEnter = (instance, e, innerParams) => {
2911
- // https://github.com/sweetalert2/sweetalert2/issues/2386
2912
- if (!callIfFunction(innerParams.allowEnterKey)) {
2913
- return;
2914
- }
2915
-
2916
- if (e.target && instance.getInput() && e.target instanceof HTMLElement && e.target.outerHTML === instance.getInput().outerHTML) {
2917
- if (['textarea', 'file'].includes(innerParams.input)) {
2918
- return; // do not submit
2919
- }
2920
-
2921
- clickConfirm();
2922
- e.preventDefault();
2917
+ if (innerParams.returnInputValueOnDeny) {
2918
+ handleConfirmOrDenyWithInput(instance, 'deny');
2919
+ } else {
2920
+ deny(instance, false);
2923
2921
  }
2924
2922
  };
2925
2923
  /**
2926
- * @param {KeyboardEvent} e
2927
- * @param {SweetAlertOptions} innerParams
2924
+ * @param {SweetAlert2} instance
2925
+ * @param {Function} dismissWith
2928
2926
  */
2929
2927
 
2930
-
2931
- const handleTab = (e, innerParams) => {
2932
- const targetElement = e.target;
2933
- const focusableElements = getFocusableElements();
2934
- let btnIndex = -1;
2935
-
2936
- for (let i = 0; i < focusableElements.length; i++) {
2937
- if (targetElement === focusableElements[i]) {
2938
- btnIndex = i;
2939
- break;
2940
- }
2941
- } // Cycle to the next button
2942
-
2943
-
2944
- if (!e.shiftKey) {
2945
- setFocus(innerParams, btnIndex, 1);
2946
- } // Cycle to the prev button
2947
- else {
2948
- setFocus(innerParams, btnIndex, -1);
2949
- }
2950
-
2951
- e.stopPropagation();
2952
- e.preventDefault();
2928
+ const handleCancelButtonClick = (instance, dismissWith) => {
2929
+ instance.disableButtons();
2930
+ dismissWith(DismissReason.cancel);
2953
2931
  };
2954
2932
  /**
2955
- * @param {string} key
2933
+ * @param {SweetAlert2} instance
2934
+ * @param {'confirm' | 'deny'} type
2956
2935
  */
2957
2936
 
2937
+ const handleConfirmOrDenyWithInput = (instance, type) => {
2938
+ const innerParams = privateProps.innerParams.get(instance);
2958
2939
 
2959
- const handleArrows = key => {
2960
- const confirmButton = getConfirmButton();
2961
- const denyButton = getDenyButton();
2962
- const cancelButton = getCancelButton();
2963
-
2964
- if (document.activeElement instanceof HTMLElement && ![confirmButton, denyButton, cancelButton].includes(document.activeElement)) {
2940
+ if (!innerParams.input) {
2941
+ error("The \"input\" parameter is needed to be set when using returnInputValueOn".concat(capitalizeFirstLetter(type)));
2965
2942
  return;
2966
2943
  }
2967
2944
 
2968
- const sibling = arrowKeysNextButton.includes(key) ? 'nextElementSibling' : 'previousElementSibling';
2969
- let buttonToFocus = document.activeElement;
2945
+ const inputValue = getInputValue(instance, innerParams);
2970
2946
 
2971
- for (let i = 0; i < getActions().children.length; i++) {
2972
- buttonToFocus = buttonToFocus[sibling];
2947
+ if (innerParams.inputValidator) {
2948
+ handleInputValidator(instance, inputValue, type);
2949
+ } else if (!instance.getInput().checkValidity()) {
2950
+ instance.enableButtons();
2951
+ instance.showValidationMessage(innerParams.validationMessage);
2952
+ } else if (type === 'deny') {
2953
+ deny(instance, inputValue);
2954
+ } else {
2955
+ confirm(instance, inputValue);
2956
+ }
2957
+ };
2958
+ /**
2959
+ * @param {SweetAlert2} instance
2960
+ * @param {string} inputValue
2961
+ * @param {'confirm' | 'deny'} type
2962
+ */
2973
2963
 
2974
- if (!buttonToFocus) {
2975
- return;
2976
- }
2977
2964
 
2978
- if (buttonToFocus instanceof HTMLButtonElement && isVisible(buttonToFocus)) {
2979
- break;
2980
- }
2981
- }
2965
+ const handleInputValidator = (instance, inputValue, type) => {
2966
+ const innerParams = privateProps.innerParams.get(instance);
2967
+ instance.disableInput();
2968
+ const validationPromise = Promise.resolve().then(() => asPromise(innerParams.inputValidator(inputValue, innerParams.validationMessage)));
2969
+ validationPromise.then(validationMessage => {
2970
+ instance.enableButtons();
2971
+ instance.enableInput();
2982
2972
 
2983
- if (buttonToFocus instanceof HTMLButtonElement) {
2984
- buttonToFocus.focus();
2985
- }
2973
+ if (validationMessage) {
2974
+ instance.showValidationMessage(validationMessage);
2975
+ } else if (type === 'deny') {
2976
+ deny(instance, inputValue);
2977
+ } else {
2978
+ confirm(instance, inputValue);
2979
+ }
2980
+ });
2986
2981
  };
2987
2982
  /**
2988
- * @param {KeyboardEvent} e
2989
- * @param {SweetAlertOptions} innerParams
2990
- * @param {function} dismissWith
2983
+ * @param {SweetAlert2} instance
2984
+ * @param {any} value
2991
2985
  */
2992
2986
 
2993
2987
 
2994
- const handleEsc = (e, innerParams, dismissWith) => {
2995
- if (callIfFunction(innerParams.allowEscapeKey)) {
2996
- e.preventDefault();
2997
- dismissWith(DismissReason.esc);
2988
+ const deny = (instance, value) => {
2989
+ const innerParams = privateProps.innerParams.get(instance || undefined);
2990
+
2991
+ if (innerParams.showLoaderOnDeny) {
2992
+ showLoading(getDenyButton());
2998
2993
  }
2999
- };
3000
2994
 
3001
- /*
3002
- * Instance method to close sweetAlert
3003
- */
2995
+ if (innerParams.preDeny) {
2996
+ privateProps.awaitingPromise.set(instance || undefined, true); // Flagging the instance as awaiting a promise so it's own promise's reject/resolve methods doesn't get destroyed until the result from this preDeny's promise is received
3004
2997
 
3005
- function removePopupAndResetState(instance, container, returnFocus, didClose) {
3006
- if (isToast()) {
3007
- triggerDidCloseAndDispose(instance, didClose);
2998
+ const preDenyPromise = Promise.resolve().then(() => asPromise(innerParams.preDeny(value, innerParams.validationMessage)));
2999
+ preDenyPromise.then(preDenyValue => {
3000
+ if (preDenyValue === false) {
3001
+ instance.hideLoading();
3002
+ handleAwaitingPromise(instance);
3003
+ } else {
3004
+ instance.close({
3005
+ isDenied: true,
3006
+ value: typeof preDenyValue === 'undefined' ? value : preDenyValue
3007
+ });
3008
+ }
3009
+ }).catch(error$$1 => rejectWith(instance || undefined, error$$1));
3008
3010
  } else {
3009
- restoreActiveElement(returnFocus).then(() => triggerDidCloseAndDispose(instance, didClose));
3010
- removeKeydownHandler(globalState);
3011
+ instance.close({
3012
+ isDenied: true,
3013
+ value
3014
+ });
3011
3015
  }
3016
+ };
3017
+ /**
3018
+ * @param {SweetAlert2} instance
3019
+ * @param {any} value
3020
+ */
3012
3021
 
3013
- const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); // workaround for #2088
3014
- // for some reason removing the container in Safari will scroll the document to bottom
3015
3022
 
3016
- if (isSafari) {
3017
- container.setAttribute('style', 'display:none !important');
3018
- container.removeAttribute('class');
3019
- container.innerHTML = '';
3020
- } else {
3021
- container.remove();
3022
- }
3023
+ const succeedWith = (instance, value) => {
3024
+ instance.close({
3025
+ isConfirmed: true,
3026
+ value
3027
+ });
3028
+ };
3029
+ /**
3030
+ *
3031
+ * @param {SweetAlert2} instance
3032
+ * @param {string} error
3033
+ */
3023
3034
 
3024
- if (isModal()) {
3025
- undoScrollbar();
3026
- undoIOSfix();
3027
- unsetAriaHidden();
3028
- }
3029
3035
 
3030
- removeBodyClasses();
3031
- }
3036
+ const rejectWith = (instance, error$$1) => {
3037
+ // @ts-ignore
3038
+ instance.rejectPromise(error$$1);
3039
+ };
3040
+ /**
3041
+ *
3042
+ * @param {SweetAlert2} instance
3043
+ * @param {any} value
3044
+ */
3032
3045
 
3033
- function removeBodyClasses() {
3034
- removeClass([document.documentElement, document.body], [swalClasses.shown, swalClasses['height-auto'], swalClasses['no-backdrop'], swalClasses['toast-shown']]);
3035
- }
3036
3046
 
3037
- function close(resolveValue) {
3038
- resolveValue = prepareResolveValue(resolveValue);
3039
- const swalPromiseResolve = privateMethods.swalPromiseResolve.get(this);
3040
- const didClose = triggerClosePopup(this);
3047
+ const confirm = (instance, value) => {
3048
+ const innerParams = privateProps.innerParams.get(instance || undefined);
3041
3049
 
3042
- if (this.isAwaitingPromise()) {
3043
- // A swal awaiting for a promise (after a click on Confirm or Deny) cannot be dismissed anymore #2335
3044
- if (!resolveValue.isDismissed) {
3045
- handleAwaitingPromise(this);
3046
- swalPromiseResolve(resolveValue);
3047
- }
3048
- } else if (didClose) {
3049
- // Resolve Swal promise
3050
- swalPromiseResolve(resolveValue);
3050
+ if (innerParams.showLoaderOnConfirm) {
3051
+ showLoading();
3051
3052
  }
3052
- }
3053
- function isAwaitingPromise() {
3054
- return !!privateProps.awaitingPromise.get(this);
3055
- }
3056
3053
 
3057
- const triggerClosePopup = instance => {
3058
- const popup = getPopup();
3054
+ if (innerParams.preConfirm) {
3055
+ instance.resetValidationMessage();
3056
+ privateProps.awaitingPromise.set(instance || undefined, true); // Flagging the instance as awaiting a promise so it's own promise's reject/resolve methods doesn't get destroyed until the result from this preConfirm's promise is received
3059
3057
 
3060
- if (!popup) {
3061
- return false;
3058
+ const preConfirmPromise = Promise.resolve().then(() => asPromise(innerParams.preConfirm(value, innerParams.validationMessage)));
3059
+ preConfirmPromise.then(preConfirmValue => {
3060
+ if (isVisible(getValidationMessage()) || preConfirmValue === false) {
3061
+ instance.hideLoading();
3062
+ handleAwaitingPromise(instance);
3063
+ } else {
3064
+ succeedWith(instance, typeof preConfirmValue === 'undefined' ? value : preConfirmValue);
3065
+ }
3066
+ }).catch(error$$1 => rejectWith(instance || undefined, error$$1));
3067
+ } else {
3068
+ succeedWith(instance, value);
3062
3069
  }
3070
+ };
3063
3071
 
3072
+ const handlePopupClick = (instance, domCache, dismissWith) => {
3064
3073
  const innerParams = privateProps.innerParams.get(instance);
3065
3074
 
3066
- if (!innerParams || hasClass(popup, innerParams.hideClass.popup)) {
3067
- return false;
3068
- }
3075
+ if (innerParams.toast) {
3076
+ handleToastClick(instance, domCache, dismissWith);
3077
+ } else {
3078
+ // Ignore click events that had mousedown on the popup but mouseup on the container
3079
+ // This can happen when the user drags a slider
3080
+ handleModalMousedown(domCache); // Ignore click events that had mousedown on the container but mouseup on the popup
3069
3081
 
3070
- removeClass(popup, innerParams.showClass.popup);
3071
- addClass(popup, innerParams.hideClass.popup);
3072
- const backdrop = getContainer();
3073
- removeClass(backdrop, innerParams.showClass.backdrop);
3074
- addClass(backdrop, innerParams.hideClass.backdrop);
3075
- handlePopupAnimation(instance, popup, innerParams);
3076
- return true;
3082
+ handleContainerMousedown(domCache);
3083
+ handleModalClick(instance, domCache, dismissWith);
3084
+ }
3077
3085
  };
3078
3086
 
3079
- function rejectPromise(error) {
3080
- const rejectPromise = privateMethods.swalPromiseReject.get(this);
3081
- handleAwaitingPromise(this);
3082
-
3083
- if (rejectPromise) {
3084
- // Reject Swal promise
3085
- rejectPromise(error);
3086
- }
3087
- }
3088
- const handleAwaitingPromise = instance => {
3089
- if (instance.isAwaitingPromise()) {
3090
- privateProps.awaitingPromise.delete(instance); // The instance might have been previously partly destroyed, we must resume the destroy process in this case #2335
3087
+ const handleToastClick = (instance, domCache, dismissWith) => {
3088
+ // Closing toast by internal click
3089
+ domCache.popup.onclick = () => {
3090
+ const innerParams = privateProps.innerParams.get(instance);
3091
3091
 
3092
- if (!privateProps.innerParams.get(instance)) {
3093
- instance._destroy();
3092
+ if (innerParams && (isAnyButtonShown(innerParams) || innerParams.timer || innerParams.input)) {
3093
+ return;
3094
3094
  }
3095
- }
3095
+
3096
+ dismissWith(DismissReason.close);
3097
+ };
3096
3098
  };
3099
+ /**
3100
+ * @param {*} innerParams
3101
+ * @returns {boolean}
3102
+ */
3097
3103
 
3098
- const prepareResolveValue = resolveValue => {
3099
- // When user calls Swal.close()
3100
- if (typeof resolveValue === 'undefined') {
3101
- return {
3102
- isConfirmed: false,
3103
- isDenied: false,
3104
- isDismissed: true
3105
- };
3106
- }
3107
3104
 
3108
- return Object.assign({
3109
- isConfirmed: false,
3110
- isDenied: false,
3111
- isDismissed: false
3112
- }, resolveValue);
3105
+ const isAnyButtonShown = innerParams => {
3106
+ return innerParams.showConfirmButton || innerParams.showDenyButton || innerParams.showCancelButton || innerParams.showCloseButton;
3113
3107
  };
3114
3108
 
3115
- const handlePopupAnimation = (instance, popup, innerParams) => {
3116
- const container = getContainer(); // If animation is supported, animate
3109
+ let ignoreOutsideClick = false;
3117
3110
 
3118
- const animationIsSupported = animationEndEvent && hasCssAnimation(popup);
3111
+ const handleModalMousedown = domCache => {
3112
+ domCache.popup.onmousedown = () => {
3113
+ domCache.container.onmouseup = function (e) {
3114
+ domCache.container.onmouseup = undefined; // We only check if the mouseup target is the container because usually it doesn't
3115
+ // have any other direct children aside of the popup
3119
3116
 
3120
- if (typeof innerParams.willClose === 'function') {
3121
- innerParams.willClose(popup);
3122
- }
3117
+ if (e.target === domCache.container) {
3118
+ ignoreOutsideClick = true;
3119
+ }
3120
+ };
3121
+ };
3122
+ };
3123
3123
 
3124
- if (animationIsSupported) {
3125
- animatePopup(instance, popup, container, innerParams.returnFocus, innerParams.didClose);
3126
- } else {
3127
- // Otherwise, remove immediately
3128
- removePopupAndResetState(instance, container, innerParams.returnFocus, innerParams.didClose);
3129
- }
3124
+ const handleContainerMousedown = domCache => {
3125
+ domCache.container.onmousedown = () => {
3126
+ domCache.popup.onmouseup = function (e) {
3127
+ domCache.popup.onmouseup = undefined; // We also need to check if the mouseup target is a child of the popup
3128
+
3129
+ if (e.target === domCache.popup || domCache.popup.contains(e.target)) {
3130
+ ignoreOutsideClick = true;
3131
+ }
3132
+ };
3133
+ };
3130
3134
  };
3131
3135
 
3132
- const animatePopup = (instance, popup, container, returnFocus, didClose) => {
3133
- globalState.swalCloseEventFinishedCallback = removePopupAndResetState.bind(null, instance, container, returnFocus, didClose);
3134
- popup.addEventListener(animationEndEvent, function (e) {
3135
- if (e.target === popup) {
3136
- globalState.swalCloseEventFinishedCallback();
3137
- delete globalState.swalCloseEventFinishedCallback;
3136
+ const handleModalClick = (instance, domCache, dismissWith) => {
3137
+ domCache.container.onclick = e => {
3138
+ const innerParams = privateProps.innerParams.get(instance);
3139
+
3140
+ if (ignoreOutsideClick) {
3141
+ ignoreOutsideClick = false;
3142
+ return;
3138
3143
  }
3139
- });
3140
- };
3141
3144
 
3142
- const triggerDidCloseAndDispose = (instance, didClose) => {
3143
- setTimeout(() => {
3144
- if (typeof didClose === 'function') {
3145
- didClose.bind(instance.params)();
3145
+ if (e.target === domCache.container && callIfFunction(innerParams.allowOutsideClick)) {
3146
+ dismissWith(DismissReason.backdrop);
3146
3147
  }
3147
-
3148
- instance._destroy();
3149
- });
3148
+ };
3150
3149
  };
3151
3150
 
3152
- function setButtonsDisabled(instance, buttons, disabled) {
3153
- const domCache = privateProps.domCache.get(instance);
3154
- buttons.forEach(button => {
3155
- domCache[button].disabled = disabled;
3156
- });
3157
- }
3151
+ const isJqueryElement = elem => typeof elem === 'object' && elem.jquery;
3158
3152
 
3159
- function setInputDisabled(input, disabled) {
3160
- if (!input) {
3161
- return false;
3162
- }
3153
+ const isElement = elem => elem instanceof Element || isJqueryElement(elem);
3163
3154
 
3164
- if (input.type === 'radio') {
3165
- const radiosContainer = input.parentNode.parentNode;
3166
- const radios = radiosContainer.querySelectorAll('input');
3155
+ const argsToParams = args => {
3156
+ const params = {};
3167
3157
 
3168
- for (let i = 0; i < radios.length; i++) {
3169
- radios[i].disabled = disabled;
3170
- }
3158
+ if (typeof args[0] === 'object' && !isElement(args[0])) {
3159
+ Object.assign(params, args[0]);
3171
3160
  } else {
3172
- input.disabled = disabled;
3161
+ ['title', 'html', 'icon'].forEach((name, index) => {
3162
+ const arg = args[index];
3163
+
3164
+ if (typeof arg === 'string' || isElement(arg)) {
3165
+ params[name] = arg;
3166
+ } else if (arg !== undefined) {
3167
+ error("Unexpected type of ".concat(name, "! Expected \"string\" or \"Element\", got ").concat(typeof arg));
3168
+ }
3169
+ });
3173
3170
  }
3174
- }
3175
3171
 
3176
- function enableButtons() {
3177
- setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], false);
3178
- }
3179
- function disableButtons() {
3180
- setButtonsDisabled(this, ['confirmButton', 'denyButton', 'cancelButton'], true);
3181
- }
3182
- function enableInput() {
3183
- return setInputDisabled(this.getInput(), false);
3184
- }
3185
- function disableInput() {
3186
- return setInputDisabled(this.getInput(), true);
3187
- }
3172
+ return params;
3173
+ };
3188
3174
 
3189
- function showValidationMessage(error) {
3190
- const domCache = privateProps.domCache.get(this);
3191
- const params = privateProps.innerParams.get(this);
3192
- setInnerHtml(domCache.validationMessage, error);
3193
- domCache.validationMessage.className = swalClasses['validation-message'];
3175
+ function fire() {
3176
+ const Swal = this; // eslint-disable-line @typescript-eslint/no-this-alias
3194
3177
 
3195
- if (params.customClass && params.customClass.validationMessage) {
3196
- addClass(domCache.validationMessage, params.customClass.validationMessage);
3178
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
3179
+ args[_key] = arguments[_key];
3197
3180
  }
3198
3181
 
3199
- show(domCache.validationMessage);
3200
- const input = this.getInput();
3182
+ return new Swal(...args);
3183
+ }
3184
+
3185
+ /**
3186
+ * Returns an extended version of `Swal` containing `params` as defaults.
3187
+ * Useful for reusing Swal configuration.
3188
+ *
3189
+ * For example:
3190
+ *
3191
+ * Before:
3192
+ * const textPromptOptions = { input: 'text', showCancelButton: true }
3193
+ * const {value: firstName} = await Swal.fire({ ...textPromptOptions, title: 'What is your first name?' })
3194
+ * const {value: lastName} = await Swal.fire({ ...textPromptOptions, title: 'What is your last name?' })
3195
+ *
3196
+ * After:
3197
+ * const TextPrompt = Swal.mixin({ input: 'text', showCancelButton: true })
3198
+ * const {value: firstName} = await TextPrompt('What is your first name?')
3199
+ * const {value: lastName} = await TextPrompt('What is your last name?')
3200
+ *
3201
+ * @param mixinParams
3202
+ */
3203
+ function mixin(mixinParams) {
3204
+ class MixinSwal extends this {
3205
+ _main(params, priorityMixinParams) {
3206
+ return super._main(params, Object.assign({}, mixinParams, priorityMixinParams));
3207
+ }
3201
3208
 
3202
- if (input) {
3203
- input.setAttribute('aria-invalid', true);
3204
- input.setAttribute('aria-describedby', swalClasses['validation-message']);
3205
- focusInput(input);
3206
- addClass(input, swalClasses.inputerror);
3207
3209
  }
3208
- } // Hide block with validation message
3209
3210
 
3210
- function resetValidationMessage$1() {
3211
- const domCache = privateProps.domCache.get(this);
3211
+ return MixinSwal;
3212
+ }
3212
3213
 
3213
- if (domCache.validationMessage) {
3214
- hide(domCache.validationMessage);
3215
- }
3214
+ /**
3215
+ * If `timer` parameter is set, returns number of milliseconds of timer remained.
3216
+ * Otherwise, returns undefined.
3217
+ */
3216
3218
 
3217
- const input = this.getInput();
3219
+ const getTimerLeft = () => {
3220
+ return globalState.timeout && globalState.timeout.getTimerLeft();
3221
+ };
3222
+ /**
3223
+ * Stop timer. Returns number of milliseconds of timer remained.
3224
+ * If `timer` parameter isn't set, returns undefined.
3225
+ */
3218
3226
 
3219
- if (input) {
3220
- input.removeAttribute('aria-invalid');
3221
- input.removeAttribute('aria-describedby');
3222
- removeClass(input, swalClasses.inputerror);
3227
+ const stopTimer = () => {
3228
+ if (globalState.timeout) {
3229
+ stopTimerProgressBar();
3230
+ return globalState.timeout.stop();
3223
3231
  }
3224
- }
3225
-
3226
- function getProgressSteps$1() {
3227
- const domCache = privateProps.domCache.get(this);
3228
- return domCache.progressSteps;
3229
- }
3232
+ };
3233
+ /**
3234
+ * Resume timer. Returns number of milliseconds of timer remained.
3235
+ * If `timer` parameter isn't set, returns undefined.
3236
+ */
3230
3237
 
3238
+ const resumeTimer = () => {
3239
+ if (globalState.timeout) {
3240
+ const remaining = globalState.timeout.start();
3241
+ animateTimerProgressBar(remaining);
3242
+ return remaining;
3243
+ }
3244
+ };
3231
3245
  /**
3232
- * Updates popup parameters.
3246
+ * Resume timer. Returns number of milliseconds of timer remained.
3247
+ * If `timer` parameter isn't set, returns undefined.
3233
3248
  */
3234
3249
 
3235
- function update(params) {
3236
- const popup = getPopup();
3237
- const innerParams = privateProps.innerParams.get(this);
3250
+ const toggleTimer = () => {
3251
+ const timer = globalState.timeout;
3252
+ return timer && (timer.running ? stopTimer() : resumeTimer());
3253
+ };
3254
+ /**
3255
+ * Increase timer. Returns number of milliseconds of an updated timer.
3256
+ * If `timer` parameter isn't set, returns undefined.
3257
+ */
3238
3258
 
3239
- if (!popup || hasClass(popup, innerParams.hideClass.popup)) {
3240
- return warn("You're trying to update the closed or closing popup, that won't work. Use the update() method in preConfirm parameter or show a new popup.");
3259
+ const increaseTimer = n => {
3260
+ if (globalState.timeout) {
3261
+ const remaining = globalState.timeout.increase(n);
3262
+ animateTimerProgressBar(remaining, true);
3263
+ return remaining;
3241
3264
  }
3265
+ };
3266
+ /**
3267
+ * Check if timer is running. Returns true if timer is running
3268
+ * or false if timer is paused or stopped.
3269
+ * If `timer` parameter isn't set, returns undefined
3270
+ */
3242
3271
 
3243
- const validUpdatableParams = filterValidParams(params);
3244
- const updatedParams = Object.assign({}, innerParams, validUpdatableParams);
3245
- render(this, updatedParams);
3246
- privateProps.innerParams.set(this, updatedParams);
3247
- Object.defineProperties(this, {
3248
- params: {
3249
- value: Object.assign({}, this.params, params),
3250
- writable: false,
3251
- enumerable: true
3252
- }
3253
- });
3272
+ const isTimerRunning = () => {
3273
+ return globalState.timeout && globalState.timeout.isRunning();
3274
+ };
3275
+
3276
+ let bodyClickListenerAdded = false;
3277
+ const clickHandlers = {};
3278
+ function bindClickHandler() {
3279
+ let attr = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'data-swal-template';
3280
+ clickHandlers[attr] = this;
3281
+
3282
+ if (!bodyClickListenerAdded) {
3283
+ document.body.addEventListener('click', bodyClickListener);
3284
+ bodyClickListenerAdded = true;
3285
+ }
3254
3286
  }
3255
3287
 
3256
- const filterValidParams = params => {
3257
- const validUpdatableParams = {};
3258
- Object.keys(params).forEach(param => {
3259
- if (isUpdatableParameter(param)) {
3260
- validUpdatableParams[param] = params[param];
3261
- } else {
3262
- warn("Invalid parameter to update: ".concat(param));
3288
+ const bodyClickListener = event => {
3289
+ for (let el = event.target; el && el !== document; el = el.parentNode) {
3290
+ for (const attr in clickHandlers) {
3291
+ const template = el.getAttribute(attr);
3292
+
3293
+ if (template) {
3294
+ clickHandlers[attr].fire({
3295
+ template
3296
+ });
3297
+ return;
3298
+ }
3263
3299
  }
3264
- });
3265
- return validUpdatableParams;
3300
+ }
3266
3301
  };
3267
3302
 
3268
- function _destroy() {
3269
- const domCache = privateProps.domCache.get(this);
3270
- const innerParams = privateProps.innerParams.get(this);
3271
-
3272
- if (!innerParams) {
3273
- disposeWeakMaps(this); // The WeakMaps might have been partly destroyed, we must recall it to dispose any remaining WeakMaps #2335
3274
3303
 
3275
- return; // This instance has already been destroyed
3276
- } // Check if there is another Swal closing
3277
3304
 
3305
+ var staticMethods = /*#__PURE__*/Object.freeze({
3306
+ isValidParameter: isValidParameter,
3307
+ isUpdatableParameter: isUpdatableParameter,
3308
+ isDeprecatedParameter: isDeprecatedParameter,
3309
+ argsToParams: argsToParams,
3310
+ isVisible: isVisible$1,
3311
+ clickConfirm: clickConfirm,
3312
+ clickDeny: clickDeny,
3313
+ clickCancel: clickCancel,
3314
+ getContainer: getContainer,
3315
+ getPopup: getPopup,
3316
+ getTitle: getTitle,
3317
+ getHtmlContainer: getHtmlContainer,
3318
+ getImage: getImage,
3319
+ getIcon: getIcon,
3320
+ getInputLabel: getInputLabel,
3321
+ getCloseButton: getCloseButton,
3322
+ getActions: getActions,
3323
+ getConfirmButton: getConfirmButton,
3324
+ getDenyButton: getDenyButton,
3325
+ getCancelButton: getCancelButton,
3326
+ getLoader: getLoader,
3327
+ getFooter: getFooter,
3328
+ getTimerProgressBar: getTimerProgressBar,
3329
+ getFocusableElements: getFocusableElements,
3330
+ getValidationMessage: getValidationMessage,
3331
+ isLoading: isLoading,
3332
+ fire: fire,
3333
+ mixin: mixin,
3334
+ showLoading: showLoading,
3335
+ enableLoading: showLoading,
3336
+ getTimerLeft: getTimerLeft,
3337
+ stopTimer: stopTimer,
3338
+ resumeTimer: resumeTimer,
3339
+ toggleTimer: toggleTimer,
3340
+ increaseTimer: increaseTimer,
3341
+ isTimerRunning: isTimerRunning,
3342
+ bindClickHandler: bindClickHandler
3343
+ });
3278
3344
 
3279
- if (domCache.popup && globalState.swalCloseEventFinishedCallback) {
3280
- globalState.swalCloseEventFinishedCallback();
3281
- delete globalState.swalCloseEventFinishedCallback;
3345
+ class Timer {
3346
+ /**
3347
+ * @param {Function} callback
3348
+ * @param {number} delay
3349
+ */
3350
+ constructor(callback, delay) {
3351
+ this.callback = callback;
3352
+ this.remaining = delay;
3353
+ this.running = false;
3354
+ this.start();
3282
3355
  }
3283
3356
 
3284
- if (typeof innerParams.didDestroy === 'function') {
3285
- innerParams.didDestroy();
3357
+ start() {
3358
+ if (!this.running) {
3359
+ this.running = true;
3360
+ this.started = new Date();
3361
+ this.id = setTimeout(this.callback, this.remaining);
3362
+ }
3363
+
3364
+ return this.remaining;
3286
3365
  }
3287
3366
 
3288
- disposeSwal(this);
3289
- }
3290
- /**
3291
- * @param {SweetAlert2} instance
3292
- */
3367
+ stop() {
3368
+ if (this.running) {
3369
+ this.running = false;
3370
+ clearTimeout(this.id);
3371
+ this.remaining -= new Date().getTime() - this.started.getTime();
3372
+ }
3293
3373
 
3294
- const disposeSwal = instance => {
3295
- disposeWeakMaps(instance); // Unset this.params so GC will dispose it (#1569)
3296
- // @ts-ignore
3374
+ return this.remaining;
3375
+ }
3297
3376
 
3298
- delete instance.params; // Unset globalState props so GC will dispose globalState (#1569)
3377
+ increase(n) {
3378
+ const running = this.running;
3299
3379
 
3300
- delete globalState.keydownHandler;
3301
- delete globalState.keydownTarget; // Unset currentInstance
3380
+ if (running) {
3381
+ this.stop();
3382
+ }
3302
3383
 
3303
- delete globalState.currentInstance;
3304
- };
3305
- /**
3306
- * @param {SweetAlert2} instance
3307
- */
3384
+ this.remaining += n;
3308
3385
 
3386
+ if (running) {
3387
+ this.start();
3388
+ }
3309
3389
 
3310
- const disposeWeakMaps = instance => {
3311
- // If the current instance is awaiting a promise result, we keep the privateMethods to call them once the promise result is retrieved #2335
3312
- // @ts-ignore
3313
- if (instance.isAwaitingPromise()) {
3314
- unsetWeakMaps(privateProps, instance);
3315
- privateProps.awaitingPromise.set(instance, true);
3316
- } else {
3317
- unsetWeakMaps(privateMethods, instance);
3318
- unsetWeakMaps(privateProps, instance);
3390
+ return this.remaining;
3319
3391
  }
3320
- };
3321
- /**
3322
- * @param {object} obj
3323
- * @param {SweetAlert2} instance
3324
- */
3325
3392
 
3393
+ getTimerLeft() {
3394
+ if (this.running) {
3395
+ this.stop();
3396
+ this.start();
3397
+ }
3326
3398
 
3327
- const unsetWeakMaps = (obj, instance) => {
3328
- for (const i in obj) {
3329
- obj[i].delete(instance);
3399
+ return this.remaining;
3330
3400
  }
3331
- };
3332
-
3333
-
3334
-
3335
- var instanceMethods = /*#__PURE__*/Object.freeze({
3336
- hideLoading: hideLoading,
3337
- disableLoading: hideLoading,
3338
- getInput: getInput$1,
3339
- close: close,
3340
- isAwaitingPromise: isAwaitingPromise,
3341
- rejectPromise: rejectPromise,
3342
- handleAwaitingPromise: handleAwaitingPromise,
3343
- closePopup: close,
3344
- closeModal: close,
3345
- closeToast: close,
3346
- enableButtons: enableButtons,
3347
- disableButtons: disableButtons,
3348
- enableInput: enableInput,
3349
- disableInput: disableInput,
3350
- showValidationMessage: showValidationMessage,
3351
- resetValidationMessage: resetValidationMessage$1,
3352
- getProgressSteps: getProgressSteps$1,
3353
- update: update,
3354
- _destroy: _destroy
3355
- });
3356
-
3357
- /**
3358
- * @param {SweetAlert2} instance
3359
- */
3360
3401
 
3361
- const handleConfirmButtonClick = instance => {
3362
- const innerParams = privateProps.innerParams.get(instance);
3363
- instance.disableButtons();
3364
-
3365
- if (innerParams.input) {
3366
- handleConfirmOrDenyWithInput(instance, 'confirm');
3367
- } else {
3368
- confirm(instance, true);
3402
+ isRunning() {
3403
+ return this.running;
3369
3404
  }
3370
- };
3371
- /**
3372
- * @param {SweetAlert2} instance
3373
- */
3374
-
3375
- const handleDenyButtonClick = instance => {
3376
- const innerParams = privateProps.innerParams.get(instance);
3377
- instance.disableButtons();
3378
3405
 
3379
- if (innerParams.returnInputValueOnDeny) {
3380
- handleConfirmOrDenyWithInput(instance, 'deny');
3381
- } else {
3382
- deny(instance, false);
3383
- }
3384
- };
3385
- /**
3386
- * @param {SweetAlert2} instance
3387
- * @param {Function} dismissWith
3388
- */
3406
+ }
3389
3407
 
3390
- const handleCancelButtonClick = (instance, dismissWith) => {
3391
- instance.disableButtons();
3392
- dismissWith(DismissReason.cancel);
3393
- };
3408
+ const swalStringParams = ['swal-title', 'swal-html', 'swal-footer'];
3394
3409
  /**
3395
- * @param {SweetAlert2} instance
3396
- * @param {'confirm' | 'deny'} type
3410
+ * @param {SweetAlertOptions} params
3411
+ * @returns {SweetAlertOptions}
3397
3412
  */
3398
3413
 
3399
- const handleConfirmOrDenyWithInput = (instance, type) => {
3400
- const innerParams = privateProps.innerParams.get(instance);
3414
+ const getTemplateParams = params => {
3415
+ /** @type {HTMLTemplateElement} */
3416
+ const template = typeof params.template === 'string' ? document.querySelector(params.template) : params.template;
3401
3417
 
3402
- if (!innerParams.input) {
3403
- error("The \"input\" parameter is needed to be set when using returnInputValueOn".concat(capitalizeFirstLetter(type)));
3404
- return;
3418
+ if (!template) {
3419
+ return {};
3405
3420
  }
3421
+ /** @type {DocumentFragment} */
3406
3422
 
3407
- const inputValue = getInputValue(instance, innerParams);
3408
3423
 
3409
- if (innerParams.inputValidator) {
3410
- handleInputValidator(instance, inputValue, type);
3411
- } else if (!instance.getInput().checkValidity()) {
3412
- instance.enableButtons();
3413
- instance.showValidationMessage(innerParams.validationMessage);
3414
- } else if (type === 'deny') {
3415
- deny(instance, inputValue);
3416
- } else {
3417
- confirm(instance, inputValue);
3418
- }
3424
+ const templateContent = template.content;
3425
+ showWarningsForElements(templateContent);
3426
+ const result = Object.assign(getSwalParams(templateContent), getSwalButtons(templateContent), getSwalImage(templateContent), getSwalIcon(templateContent), getSwalInput(templateContent), getSwalStringParams(templateContent, swalStringParams));
3427
+ return result;
3419
3428
  };
3420
3429
  /**
3421
- * @param {SweetAlert2} instance
3422
- * @param {string} inputValue
3423
- * @param {'confirm' | 'deny'} type
3430
+ * @param {DocumentFragment} templateContent
3431
+ * @returns {SweetAlertOptions}
3424
3432
  */
3425
3433
 
3434
+ const getSwalParams = templateContent => {
3435
+ const result = {};
3436
+ /** @type {HTMLElement[]} */
3426
3437
 
3427
- const handleInputValidator = (instance, inputValue, type) => {
3428
- const innerParams = privateProps.innerParams.get(instance);
3429
- instance.disableInput();
3430
- const validationPromise = Promise.resolve().then(() => asPromise(innerParams.inputValidator(inputValue, innerParams.validationMessage)));
3431
- validationPromise.then(validationMessage => {
3432
- instance.enableButtons();
3433
- instance.enableInput();
3438
+ const swalParams = Array.from(templateContent.querySelectorAll('swal-param'));
3439
+ swalParams.forEach(param => {
3440
+ showWarningsForAttributes(param, ['name', 'value']);
3441
+ const paramName = param.getAttribute('name');
3442
+ const value = param.getAttribute('value');
3434
3443
 
3435
- if (validationMessage) {
3436
- instance.showValidationMessage(validationMessage);
3437
- } else if (type === 'deny') {
3438
- deny(instance, inputValue);
3439
- } else {
3440
- confirm(instance, inputValue);
3444
+ if (typeof defaultParams[paramName] === 'boolean' && value === 'false') {
3445
+ result[paramName] = false;
3446
+ }
3447
+
3448
+ if (typeof defaultParams[paramName] === 'object') {
3449
+ result[paramName] = JSON.parse(value);
3441
3450
  }
3442
3451
  });
3452
+ return result;
3443
3453
  };
3444
3454
  /**
3445
- * @param {SweetAlert2} instance
3446
- * @param {any} value
3455
+ * @param {DocumentFragment} templateContent
3456
+ * @returns {SweetAlertOptions}
3447
3457
  */
3448
3458
 
3449
3459
 
3450
- const deny = (instance, value) => {
3451
- const innerParams = privateProps.innerParams.get(instance || undefined);
3452
-
3453
- if (innerParams.showLoaderOnDeny) {
3454
- showLoading(getDenyButton());
3455
- }
3456
-
3457
- if (innerParams.preDeny) {
3458
- privateProps.awaitingPromise.set(instance || undefined, true); // Flagging the instance as awaiting a promise so it's own promise's reject/resolve methods doesn't get destroyed until the result from this preDeny's promise is received
3459
-
3460
- const preDenyPromise = Promise.resolve().then(() => asPromise(innerParams.preDeny(value, innerParams.validationMessage)));
3461
- preDenyPromise.then(preDenyValue => {
3462
- if (preDenyValue === false) {
3463
- instance.hideLoading();
3464
- handleAwaitingPromise(instance);
3465
- } else {
3466
- instance.close({
3467
- isDenied: true,
3468
- value: typeof preDenyValue === 'undefined' ? value : preDenyValue
3469
- });
3470
- }
3471
- }).catch(error$$1 => rejectWith(instance || undefined, error$$1));
3472
- } else {
3473
- instance.close({
3474
- isDenied: true,
3475
- value
3476
- });
3477
- }
3478
- };
3479
- /**
3480
- * @param {SweetAlert2} instance
3481
- * @param {any} value
3482
- */
3460
+ const getSwalButtons = templateContent => {
3461
+ const result = {};
3462
+ /** @type {HTMLElement[]} */
3483
3463
 
3464
+ const swalButtons = Array.from(templateContent.querySelectorAll('swal-button'));
3465
+ swalButtons.forEach(button => {
3466
+ showWarningsForAttributes(button, ['type', 'color', 'aria-label']);
3467
+ const type = button.getAttribute('type');
3468
+ result["".concat(type, "ButtonText")] = button.innerHTML;
3469
+ result["show".concat(capitalizeFirstLetter(type), "Button")] = true;
3484
3470
 
3485
- const succeedWith = (instance, value) => {
3486
- instance.close({
3487
- isConfirmed: true,
3488
- value
3471
+ if (button.hasAttribute('color')) {
3472
+ result["".concat(type, "ButtonColor")] = button.getAttribute('color');
3473
+ }
3474
+
3475
+ if (button.hasAttribute('aria-label')) {
3476
+ result["".concat(type, "ButtonAriaLabel")] = button.getAttribute('aria-label');
3477
+ }
3489
3478
  });
3479
+ return result;
3490
3480
  };
3491
3481
  /**
3492
- *
3493
- * @param {SweetAlert2} instance
3494
- * @param {string} error
3482
+ * @param {DocumentFragment} templateContent
3483
+ * @returns {SweetAlertOptions}
3495
3484
  */
3496
3485
 
3497
3486
 
3498
- const rejectWith = (instance, error$$1) => {
3499
- // @ts-ignore
3500
- instance.rejectPromise(error$$1);
3501
- };
3502
- /**
3503
- *
3504
- * @param {SweetAlert2} instance
3505
- * @param {any} value
3506
- */
3487
+ const getSwalImage = templateContent => {
3488
+ const result = {};
3489
+ /** @type {HTMLElement} */
3507
3490
 
3491
+ const image = templateContent.querySelector('swal-image');
3508
3492
 
3509
- const confirm = (instance, value) => {
3510
- const innerParams = privateProps.innerParams.get(instance || undefined);
3493
+ if (image) {
3494
+ showWarningsForAttributes(image, ['src', 'width', 'height', 'alt']);
3511
3495
 
3512
- if (innerParams.showLoaderOnConfirm) {
3513
- showLoading();
3514
- }
3496
+ if (image.hasAttribute('src')) {
3497
+ result.imageUrl = image.getAttribute('src');
3498
+ }
3515
3499
 
3516
- if (innerParams.preConfirm) {
3517
- instance.resetValidationMessage();
3518
- privateProps.awaitingPromise.set(instance || undefined, true); // Flagging the instance as awaiting a promise so it's own promise's reject/resolve methods doesn't get destroyed until the result from this preConfirm's promise is received
3500
+ if (image.hasAttribute('width')) {
3501
+ result.imageWidth = image.getAttribute('width');
3502
+ }
3519
3503
 
3520
- const preConfirmPromise = Promise.resolve().then(() => asPromise(innerParams.preConfirm(value, innerParams.validationMessage)));
3521
- preConfirmPromise.then(preConfirmValue => {
3522
- if (isVisible(getValidationMessage()) || preConfirmValue === false) {
3523
- instance.hideLoading();
3524
- handleAwaitingPromise(instance);
3525
- } else {
3526
- succeedWith(instance, typeof preConfirmValue === 'undefined' ? value : preConfirmValue);
3527
- }
3528
- }).catch(error$$1 => rejectWith(instance || undefined, error$$1));
3529
- } else {
3530
- succeedWith(instance, value);
3504
+ if (image.hasAttribute('height')) {
3505
+ result.imageHeight = image.getAttribute('height');
3506
+ }
3507
+
3508
+ if (image.hasAttribute('alt')) {
3509
+ result.imageAlt = image.getAttribute('alt');
3510
+ }
3531
3511
  }
3512
+
3513
+ return result;
3532
3514
  };
3515
+ /**
3516
+ * @param {DocumentFragment} templateContent
3517
+ * @returns {SweetAlertOptions}
3518
+ */
3533
3519
 
3534
- const handlePopupClick = (instance, domCache, dismissWith) => {
3535
- const innerParams = privateProps.innerParams.get(instance);
3536
3520
 
3537
- if (innerParams.toast) {
3538
- handleToastClick(instance, domCache, dismissWith);
3539
- } else {
3540
- // Ignore click events that had mousedown on the popup but mouseup on the container
3541
- // This can happen when the user drags a slider
3542
- handleModalMousedown(domCache); // Ignore click events that had mousedown on the container but mouseup on the popup
3521
+ const getSwalIcon = templateContent => {
3522
+ const result = {};
3523
+ /** @type {HTMLElement} */
3543
3524
 
3544
- handleContainerMousedown(domCache);
3545
- handleModalClick(instance, domCache, dismissWith);
3546
- }
3547
- };
3525
+ const icon = templateContent.querySelector('swal-icon');
3548
3526
 
3549
- const handleToastClick = (instance, domCache, dismissWith) => {
3550
- // Closing toast by internal click
3551
- domCache.popup.onclick = () => {
3552
- const innerParams = privateProps.innerParams.get(instance);
3527
+ if (icon) {
3528
+ showWarningsForAttributes(icon, ['type', 'color']);
3553
3529
 
3554
- if (innerParams && (isAnyButtonShown(innerParams) || innerParams.timer || innerParams.input)) {
3555
- return;
3530
+ if (icon.hasAttribute('type')) {
3531
+ /** @type {SweetAlertIcon} */
3532
+ // @ts-ignore
3533
+ result.icon = icon.getAttribute('type');
3556
3534
  }
3557
3535
 
3558
- dismissWith(DismissReason.close);
3559
- };
3560
- };
3561
- /**
3562
- * @param {*} innerParams
3563
- * @returns {boolean}
3564
- */
3536
+ if (icon.hasAttribute('color')) {
3537
+ result.iconColor = icon.getAttribute('color');
3538
+ }
3565
3539
 
3540
+ result.iconHtml = icon.innerHTML;
3541
+ }
3566
3542
 
3567
- const isAnyButtonShown = innerParams => {
3568
- return innerParams.showConfirmButton || innerParams.showDenyButton || innerParams.showCancelButton || innerParams.showCloseButton;
3543
+ return result;
3569
3544
  };
3545
+ /**
3546
+ * @param {DocumentFragment} templateContent
3547
+ * @returns {SweetAlertOptions}
3548
+ */
3570
3549
 
3571
- let ignoreOutsideClick = false;
3572
3550
 
3573
- const handleModalMousedown = domCache => {
3574
- domCache.popup.onmousedown = () => {
3575
- domCache.container.onmouseup = function (e) {
3576
- domCache.container.onmouseup = undefined; // We only check if the mouseup target is the container because usually it doesn't
3577
- // have any other direct children aside of the popup
3551
+ const getSwalInput = templateContent => {
3552
+ const result = {};
3553
+ /** @type {HTMLElement} */
3578
3554
 
3579
- if (e.target === domCache.container) {
3580
- ignoreOutsideClick = true;
3581
- }
3582
- };
3583
- };
3584
- };
3555
+ const input = templateContent.querySelector('swal-input');
3585
3556
 
3586
- const handleContainerMousedown = domCache => {
3587
- domCache.container.onmousedown = () => {
3588
- domCache.popup.onmouseup = function (e) {
3589
- domCache.popup.onmouseup = undefined; // We also need to check if the mouseup target is a child of the popup
3557
+ if (input) {
3558
+ showWarningsForAttributes(input, ['type', 'label', 'placeholder', 'value']);
3559
+ /** @type {SweetAlertInput} */
3560
+ // @ts-ignore
3590
3561
 
3591
- if (e.target === domCache.popup || domCache.popup.contains(e.target)) {
3592
- ignoreOutsideClick = true;
3593
- }
3594
- };
3595
- };
3596
- };
3562
+ result.input = input.getAttribute('type') || 'text';
3597
3563
 
3598
- const handleModalClick = (instance, domCache, dismissWith) => {
3599
- domCache.container.onclick = e => {
3600
- const innerParams = privateProps.innerParams.get(instance);
3564
+ if (input.hasAttribute('label')) {
3565
+ result.inputLabel = input.getAttribute('label');
3566
+ }
3601
3567
 
3602
- if (ignoreOutsideClick) {
3603
- ignoreOutsideClick = false;
3604
- return;
3568
+ if (input.hasAttribute('placeholder')) {
3569
+ result.inputPlaceholder = input.getAttribute('placeholder');
3605
3570
  }
3606
3571
 
3607
- if (e.target === domCache.container && callIfFunction(innerParams.allowOutsideClick)) {
3608
- dismissWith(DismissReason.backdrop);
3572
+ if (input.hasAttribute('value')) {
3573
+ result.inputValue = input.getAttribute('value');
3609
3574
  }
3610
- };
3575
+ }
3576
+ /** @type {HTMLElement[]} */
3577
+
3578
+
3579
+ const inputOptions = Array.from(templateContent.querySelectorAll('swal-input-option'));
3580
+
3581
+ if (inputOptions.length) {
3582
+ result.inputOptions = {};
3583
+ inputOptions.forEach(option => {
3584
+ showWarningsForAttributes(option, ['value']);
3585
+ const optionValue = option.getAttribute('value');
3586
+ const optionName = option.innerHTML;
3587
+ result.inputOptions[optionValue] = optionName;
3588
+ });
3589
+ }
3590
+
3591
+ return result;
3611
3592
  };
3593
+ /**
3594
+ * @param {DocumentFragment} templateContent
3595
+ * @param {string[]} paramNames
3596
+ * @returns {SweetAlertOptions}
3597
+ */
3612
3598
 
3613
- const isJqueryElement = elem => typeof elem === 'object' && elem.jquery;
3614
3599
 
3615
- const isElement = elem => elem instanceof Element || isJqueryElement(elem);
3600
+ const getSwalStringParams = (templateContent, paramNames) => {
3601
+ const result = {};
3616
3602
 
3617
- const argsToParams = args => {
3618
- const params = {};
3603
+ for (const i in paramNames) {
3604
+ const paramName = paramNames[i];
3605
+ /** @type {HTMLElement} */
3619
3606
 
3620
- if (typeof args[0] === 'object' && !isElement(args[0])) {
3621
- Object.assign(params, args[0]);
3622
- } else {
3623
- ['title', 'html', 'icon'].forEach((name, index) => {
3624
- const arg = args[index];
3607
+ const tag = templateContent.querySelector(paramName);
3625
3608
 
3626
- if (typeof arg === 'string' || isElement(arg)) {
3627
- params[name] = arg;
3628
- } else if (arg !== undefined) {
3629
- error("Unexpected type of ".concat(name, "! Expected \"string\" or \"Element\", got ").concat(typeof arg));
3630
- }
3631
- });
3609
+ if (tag) {
3610
+ showWarningsForAttributes(tag, []);
3611
+ result[paramName.replace(/^swal-/, '')] = tag.innerHTML.trim();
3612
+ }
3632
3613
  }
3633
3614
 
3634
- return params;
3615
+ return result;
3635
3616
  };
3617
+ /**
3618
+ * @param {DocumentFragment} templateContent
3619
+ */
3636
3620
 
3637
- function fire() {
3638
- const Swal = this; // eslint-disable-line @typescript-eslint/no-this-alias
3639
3621
 
3640
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
3641
- args[_key] = arguments[_key];
3642
- }
3622
+ const showWarningsForElements = templateContent => {
3623
+ const allowedElements = swalStringParams.concat(['swal-param', 'swal-button', 'swal-image', 'swal-icon', 'swal-input', 'swal-input-option']);
3624
+ Array.from(templateContent.children).forEach(el => {
3625
+ const tagName = el.tagName.toLowerCase();
3626
+
3627
+ if (!allowedElements.includes(tagName)) {
3628
+ warn("Unrecognized element <".concat(tagName, ">"));
3629
+ }
3630
+ });
3631
+ };
3632
+ /**
3633
+ * @param {HTMLElement} el
3634
+ * @param {string[]} allowedAttributes
3635
+ */
3643
3636
 
3644
- return new Swal(...args);
3645
- }
3646
3637
 
3638
+ const showWarningsForAttributes = (el, allowedAttributes) => {
3639
+ Array.from(el.attributes).forEach(attribute => {
3640
+ if (allowedAttributes.indexOf(attribute.name) === -1) {
3641
+ warn(["Unrecognized attribute \"".concat(attribute.name, "\" on <").concat(el.tagName.toLowerCase(), ">."), "".concat(allowedAttributes.length ? "Allowed attributes are: ".concat(allowedAttributes.join(', ')) : 'To set the value, use HTML within the element.')]);
3642
+ }
3643
+ });
3644
+ };
3645
+
3646
+ const SHOW_CLASS_TIMEOUT = 10;
3647
3647
  /**
3648
- * Returns an extended version of `Swal` containing `params` as defaults.
3649
- * Useful for reusing Swal configuration.
3650
- *
3651
- * For example:
3652
- *
3653
- * Before:
3654
- * const textPromptOptions = { input: 'text', showCancelButton: true }
3655
- * const {value: firstName} = await Swal.fire({ ...textPromptOptions, title: 'What is your first name?' })
3656
- * const {value: lastName} = await Swal.fire({ ...textPromptOptions, title: 'What is your last name?' })
3657
- *
3658
- * After:
3659
- * const TextPrompt = Swal.mixin({ input: 'text', showCancelButton: true })
3660
- * const {value: firstName} = await TextPrompt('What is your first name?')
3661
- * const {value: lastName} = await TextPrompt('What is your last name?')
3648
+ * Open popup, add necessary classes and styles, fix scrollbar
3662
3649
  *
3663
- * @param mixinParams
3650
+ * @param {SweetAlertOptions} params
3664
3651
  */
3665
- function mixin(mixinParams) {
3666
- class MixinSwal extends this {
3667
- _main(params, priorityMixinParams) {
3668
- return super._main(params, Object.assign({}, mixinParams, priorityMixinParams));
3669
- }
3670
3652
 
3653
+ const openPopup = params => {
3654
+ const container = getContainer();
3655
+ const popup = getPopup();
3656
+
3657
+ if (typeof params.willOpen === 'function') {
3658
+ params.willOpen(popup);
3671
3659
  }
3672
3660
 
3673
- return MixinSwal;
3674
- }
3661
+ const bodyStyles = window.getComputedStyle(document.body);
3662
+ const initialBodyOverflow = bodyStyles.overflowY;
3663
+ addClasses$1(container, popup, params); // scrolling is 'hidden' until animation is done, after that 'auto'
3675
3664
 
3676
- /**
3677
- * If `timer` parameter is set, returns number of milliseconds of timer remained.
3678
- * Otherwise, returns undefined.
3679
- */
3665
+ setTimeout(() => {
3666
+ setScrollingVisibility(container, popup);
3667
+ }, SHOW_CLASS_TIMEOUT);
3680
3668
 
3681
- const getTimerLeft = () => {
3682
- return globalState.timeout && globalState.timeout.getTimerLeft();
3669
+ if (isModal()) {
3670
+ fixScrollContainer(container, params.scrollbarPadding, initialBodyOverflow);
3671
+ setAriaHidden();
3672
+ }
3673
+
3674
+ if (!isToast() && !globalState.previousActiveElement) {
3675
+ globalState.previousActiveElement = document.activeElement;
3676
+ }
3677
+
3678
+ if (typeof params.didOpen === 'function') {
3679
+ setTimeout(() => params.didOpen(popup));
3680
+ }
3681
+
3682
+ removeClass(container, swalClasses['no-transition']);
3683
3683
  };
3684
3684
  /**
3685
- * Stop timer. Returns number of milliseconds of timer remained.
3686
- * If `timer` parameter isn't set, returns undefined.
3685
+ * @param {AnimationEvent} event
3687
3686
  */
3688
3687
 
3689
- const stopTimer = () => {
3690
- if (globalState.timeout) {
3691
- stopTimerProgressBar();
3692
- return globalState.timeout.stop();
3688
+ const swalOpenAnimationFinished = event => {
3689
+ const popup = getPopup();
3690
+
3691
+ if (event.target !== popup) {
3692
+ return;
3693
3693
  }
3694
+
3695
+ const container = getContainer();
3696
+ popup.removeEventListener(animationEndEvent, swalOpenAnimationFinished);
3697
+ container.style.overflowY = 'auto';
3694
3698
  };
3695
3699
  /**
3696
- * Resume timer. Returns number of milliseconds of timer remained.
3697
- * If `timer` parameter isn't set, returns undefined.
3700
+ * @param {HTMLElement} container
3701
+ * @param {HTMLElement} popup
3698
3702
  */
3699
3703
 
3700
- const resumeTimer = () => {
3701
- if (globalState.timeout) {
3702
- const remaining = globalState.timeout.start();
3703
- animateTimerProgressBar(remaining);
3704
- return remaining;
3704
+
3705
+ const setScrollingVisibility = (container, popup) => {
3706
+ if (animationEndEvent && hasCssAnimation(popup)) {
3707
+ container.style.overflowY = 'hidden';
3708
+ popup.addEventListener(animationEndEvent, swalOpenAnimationFinished);
3709
+ } else {
3710
+ container.style.overflowY = 'auto';
3705
3711
  }
3706
3712
  };
3707
3713
  /**
3708
- * Resume timer. Returns number of milliseconds of timer remained.
3709
- * If `timer` parameter isn't set, returns undefined.
3714
+ * @param {HTMLElement} container
3715
+ * @param {boolean} scrollbarPadding
3716
+ * @param {string} initialBodyOverflow
3710
3717
  */
3711
3718
 
3712
- const toggleTimer = () => {
3713
- const timer = globalState.timeout;
3714
- return timer && (timer.running ? stopTimer() : resumeTimer());
3719
+
3720
+ const fixScrollContainer = (container, scrollbarPadding, initialBodyOverflow) => {
3721
+ iOSfix();
3722
+
3723
+ if (scrollbarPadding && initialBodyOverflow !== 'hidden') {
3724
+ fixScrollbar();
3725
+ } // sweetalert2/issues/1247
3726
+
3727
+
3728
+ setTimeout(() => {
3729
+ container.scrollTop = 0;
3730
+ });
3715
3731
  };
3716
3732
  /**
3717
- * Increase timer. Returns number of milliseconds of an updated timer.
3718
- * If `timer` parameter isn't set, returns undefined.
3733
+ * @param {HTMLElement} container
3734
+ * @param {HTMLElement} popup
3735
+ * @param {SweetAlertOptions} params
3719
3736
  */
3720
3737
 
3721
- const increaseTimer = n => {
3722
- if (globalState.timeout) {
3723
- const remaining = globalState.timeout.increase(n);
3724
- animateTimerProgressBar(remaining, true);
3725
- return remaining;
3738
+
3739
+ const addClasses$1 = (container, popup, params) => {
3740
+ addClass(container, params.showClass.backdrop); // this workaround with opacity is needed for https://github.com/sweetalert2/sweetalert2/issues/2059
3741
+
3742
+ popup.style.setProperty('opacity', '0', 'important');
3743
+ show(popup, 'grid');
3744
+ setTimeout(() => {
3745
+ // Animate popup right after showing it
3746
+ addClass(popup, params.showClass.popup); // and remove the opacity workaround
3747
+
3748
+ popup.style.removeProperty('opacity');
3749
+ }, SHOW_CLASS_TIMEOUT); // 10ms in order to fix #2062
3750
+
3751
+ addClass([document.documentElement, document.body], swalClasses.shown);
3752
+
3753
+ if (params.heightAuto && params.backdrop && !params.toast) {
3754
+ addClass([document.documentElement, document.body], swalClasses['height-auto']);
3755
+ }
3756
+ };
3757
+
3758
+ var defaultInputValidators = {
3759
+ /**
3760
+ * @param {string} string
3761
+ * @param {string} validationMessage
3762
+ * @returns {Promise<void | string>}
3763
+ */
3764
+ email: (string, validationMessage) => {
3765
+ return /^[a-zA-Z0-9.+_-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]{2,24}$/.test(string) ? Promise.resolve() : Promise.resolve(validationMessage || 'Invalid email address');
3766
+ },
3767
+
3768
+ /**
3769
+ * @param {string} string
3770
+ * @param {string} validationMessage
3771
+ * @returns {Promise<void | string>}
3772
+ */
3773
+ url: (string, validationMessage) => {
3774
+ // taken from https://stackoverflow.com/a/3809435 with a small change from #1306 and #2013
3775
+ return /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-z]{2,63}\b([-a-zA-Z0-9@:%_+.~#?&/=]*)$/.test(string) ? Promise.resolve() : Promise.resolve(validationMessage || 'Invalid URL');
3726
3776
  }
3727
3777
  };
3778
+
3728
3779
  /**
3729
- * Check if timer is running. Returns true if timer is running
3730
- * or false if timer is paused or stopped.
3731
- * If `timer` parameter isn't set, returns undefined
3780
+ * @param {SweetAlertOptions} params
3732
3781
  */
3733
3782
 
3734
- const isTimerRunning = () => {
3735
- return globalState.timeout && globalState.timeout.isRunning();
3736
- };
3783
+ function setDefaultInputValidators(params) {
3784
+ // Use default `inputValidator` for supported input types if not provided
3785
+ if (!params.inputValidator) {
3786
+ Object.keys(defaultInputValidators).forEach(key => {
3787
+ if (params.input === key) {
3788
+ params.inputValidator = defaultInputValidators[key];
3789
+ }
3790
+ });
3791
+ }
3792
+ }
3793
+ /**
3794
+ * @param {SweetAlertOptions} params
3795
+ */
3737
3796
 
3738
- let bodyClickListenerAdded = false;
3739
- const clickHandlers = {};
3740
- function bindClickHandler() {
3741
- let attr = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'data-swal-template';
3742
- clickHandlers[attr] = this;
3743
3797
 
3744
- if (!bodyClickListenerAdded) {
3745
- document.body.addEventListener('click', bodyClickListener);
3746
- bodyClickListenerAdded = true;
3798
+ function validateCustomTargetElement(params) {
3799
+ // Determine if the custom target element is valid
3800
+ if (!params.target || typeof params.target === 'string' && !document.querySelector(params.target) || typeof params.target !== 'string' && !params.target.appendChild) {
3801
+ warn('Target parameter is not valid, defaulting to "body"');
3802
+ params.target = 'body';
3747
3803
  }
3748
3804
  }
3805
+ /**
3806
+ * Set type, text and actions on popup
3807
+ *
3808
+ * @param {SweetAlertOptions} params
3809
+ */
3749
3810
 
3750
- const bodyClickListener = event => {
3751
- for (let el = event.target; el && el !== document; el = el.parentNode) {
3752
- for (const attr in clickHandlers) {
3753
- const template = el.getAttribute(attr);
3754
3811
 
3755
- if (template) {
3756
- clickHandlers[attr].fire({
3757
- template
3758
- });
3759
- return;
3760
- }
3761
- }
3812
+ function setParameters(params) {
3813
+ setDefaultInputValidators(params); // showLoaderOnConfirm && preConfirm
3814
+
3815
+ if (params.showLoaderOnConfirm && !params.preConfirm) {
3816
+ warn('showLoaderOnConfirm is set to true, but preConfirm is not defined.\n' + 'showLoaderOnConfirm should be used together with preConfirm, see usage example:\n' + 'https://sweetalert2.github.io/#ajax-request');
3762
3817
  }
3763
- };
3764
3818
 
3819
+ validateCustomTargetElement(params); // Replace newlines with <br> in title
3765
3820
 
3821
+ if (typeof params.title === 'string') {
3822
+ params.title = params.title.split('\n').join('<br />');
3823
+ }
3766
3824
 
3767
- var staticMethods = /*#__PURE__*/Object.freeze({
3768
- isValidParameter: isValidParameter,
3769
- isUpdatableParameter: isUpdatableParameter,
3770
- isDeprecatedParameter: isDeprecatedParameter,
3771
- argsToParams: argsToParams,
3772
- isVisible: isVisible$1,
3773
- clickConfirm: clickConfirm,
3774
- clickDeny: clickDeny,
3775
- clickCancel: clickCancel,
3776
- getContainer: getContainer,
3777
- getPopup: getPopup,
3778
- getTitle: getTitle,
3779
- getHtmlContainer: getHtmlContainer,
3780
- getImage: getImage,
3781
- getIcon: getIcon,
3782
- getInputLabel: getInputLabel,
3783
- getCloseButton: getCloseButton,
3784
- getActions: getActions,
3785
- getConfirmButton: getConfirmButton,
3786
- getDenyButton: getDenyButton,
3787
- getCancelButton: getCancelButton,
3788
- getLoader: getLoader,
3789
- getFooter: getFooter,
3790
- getTimerProgressBar: getTimerProgressBar,
3791
- getFocusableElements: getFocusableElements,
3792
- getValidationMessage: getValidationMessage,
3793
- isLoading: isLoading,
3794
- fire: fire,
3795
- mixin: mixin,
3796
- showLoading: showLoading,
3797
- enableLoading: showLoading,
3798
- getTimerLeft: getTimerLeft,
3799
- stopTimer: stopTimer,
3800
- resumeTimer: resumeTimer,
3801
- toggleTimer: toggleTimer,
3802
- increaseTimer: increaseTimer,
3803
- isTimerRunning: isTimerRunning,
3804
- bindClickHandler: bindClickHandler
3805
- });
3825
+ init(params);
3826
+ }
3806
3827
 
3807
3828
  let currentInstance;
3808
3829
 
@@ -3877,12 +3898,24 @@
3877
3898
  }
3878
3899
 
3879
3900
  }
3901
+ /**
3902
+ * @param {SweetAlert2} instance
3903
+ * @param {DomCache} domCache
3904
+ * @param {SweetAlertOptions} innerParams
3905
+ * @returns {Promise}
3906
+ */
3907
+
3880
3908
 
3881
3909
  const swalPromise = (instance, domCache, innerParams) => {
3882
3910
  return new Promise((resolve, reject) => {
3883
3911
  // functions to handle all closings/dismissals
3912
+
3913
+ /**
3914
+ * @param {DismissReason} dismiss
3915
+ */
3884
3916
  const dismissWith = dismiss => {
3885
- instance.closePopup({
3917
+ // @ts-ignore
3918
+ instance.close({
3886
3919
  isDismissed: true,
3887
3920
  dismiss
3888
3921
  });
@@ -3891,13 +3924,22 @@
3891
3924
  privateMethods.swalPromiseResolve.set(instance, resolve);
3892
3925
  privateMethods.swalPromiseReject.set(instance, reject);
3893
3926
 
3894
- domCache.confirmButton.onclick = () => handleConfirmButtonClick(instance);
3927
+ domCache.confirmButton.onclick = () => {
3928
+ handleConfirmButtonClick(instance);
3929
+ };
3895
3930
 
3896
- domCache.denyButton.onclick = () => handleDenyButtonClick(instance);
3931
+ domCache.denyButton.onclick = () => {
3932
+ handleDenyButtonClick(instance);
3933
+ };
3897
3934
 
3898
- domCache.cancelButton.onclick = () => handleCancelButtonClick(instance, dismissWith);
3935
+ domCache.cancelButton.onclick = () => {
3936
+ handleCancelButtonClick(instance, dismissWith);
3937
+ };
3899
3938
 
3900
- domCache.closeButton.onclick = () => dismissWith(DismissReason.close);
3939
+ domCache.closeButton.onclick = () => {
3940
+ // @ts-ignore
3941
+ dismissWith(DismissReason.close);
3942
+ };
3901
3943
 
3902
3944
  handlePopupClick(instance, domCache, dismissWith);
3903
3945
  addKeydownHandler(instance, globalState, innerParams, dismissWith);
@@ -3911,6 +3953,12 @@
3911
3953
  });
3912
3954
  });
3913
3955
  };
3956
+ /**
3957
+ * @param {SweetAlertOptions} userParams
3958
+ * @param {SweetAlertOptions} mixinParams
3959
+ * @returns {SweetAlertOptions}
3960
+ */
3961
+
3914
3962
 
3915
3963
  const prepareParams = (userParams, mixinParams) => {
3916
3964
  const templateParams = getTemplateParams(userParams);
@@ -3945,7 +3993,7 @@
3945
3993
  /**
3946
3994
  * @param {GlobalState} globalState
3947
3995
  * @param {SweetAlertOptions} innerParams
3948
- * @param {function} dismissWith
3996
+ * @param {Function} dismissWith
3949
3997
  */
3950
3998
 
3951
3999
 
@@ -3983,7 +4031,8 @@
3983
4031
  }
3984
4032
 
3985
4033
  if (!callIfFunction(innerParams.allowEnterKey)) {
3986
- return blurActiveElement();
4034
+ blurActiveElement();
4035
+ return;
3987
4036
  }
3988
4037
 
3989
4038
  if (!focusButton(domCache, innerParams)) {
@@ -4055,6 +4104,10 @@
4055
4104
  Object.assign(SweetAlert, staticMethods); // Proxy to instance methods to constructor, for now, for backwards compatibility
4056
4105
 
4057
4106
  Object.keys(instanceMethods).forEach(key => {
4107
+ /**
4108
+ * @param {...any} args
4109
+ * @returns {any}
4110
+ */
4058
4111
  SweetAlert[key] = function () {
4059
4112
  if (currentInstance) {
4060
4113
  return currentInstance[key](...arguments);
@@ -4062,7 +4115,7 @@
4062
4115
  };
4063
4116
  });
4064
4117
  SweetAlert.DismissReason = DismissReason;
4065
- SweetAlert.version = '11.4.29';
4118
+ SweetAlert.version = '11.4.32';
4066
4119
 
4067
4120
  const Swal = SweetAlert; // @ts-ignore
4068
4121