@windwalker-io/unicorn-next 0.1.18 → 0.1.21

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.
Files changed (108) hide show
  1. package/dist/chunks/_arrayPush.js +325 -108
  2. package/dist/chunks/_arrayPush.js.map +1 -1
  3. package/dist/chunks/_baseRest.js +155 -60
  4. package/dist/chunks/_baseRest.js.map +1 -1
  5. package/dist/chunks/_baseUnary.js +463 -0
  6. package/dist/chunks/_baseUnary.js.map +1 -0
  7. package/dist/chunks/_getPrototype.js +292 -100
  8. package/dist/chunks/_getPrototype.js.map +1 -1
  9. package/dist/chunks/alert-adapter.js +29 -0
  10. package/dist/chunks/alert-adapter.js.map +1 -0
  11. package/dist/chunks/alert.js +21 -0
  12. package/dist/chunks/alert.js.map +1 -0
  13. package/dist/chunks/arr.js +24 -0
  14. package/dist/chunks/arr.js.map +1 -0
  15. package/dist/chunks/button-radio.js +127 -145
  16. package/dist/chunks/button-radio.js.map +1 -1
  17. package/dist/chunks/checkboxes-multi-select.js +44 -43
  18. package/dist/chunks/checkboxes-multi-select.js.map +1 -1
  19. package/dist/chunks/chunk.js +24 -0
  20. package/dist/chunks/cloneDeep.js +679 -212
  21. package/dist/chunks/cloneDeep.js.map +1 -1
  22. package/dist/chunks/cropper.min.js +6 -5
  23. package/dist/chunks/cropper.min.js.map +1 -1
  24. package/dist/chunks/crypto.js +26 -0
  25. package/dist/chunks/crypto.js.map +1 -0
  26. package/dist/chunks/data.js +49 -0
  27. package/dist/chunks/data.js.map +1 -0
  28. package/dist/chunks/dom.js +128 -0
  29. package/dist/chunks/dom.js.map +1 -0
  30. package/dist/chunks/events.js +270 -0
  31. package/dist/chunks/events.js.map +1 -0
  32. package/dist/chunks/field-cascade-select.js +207 -250
  33. package/dist/chunks/field-cascade-select.js.map +1 -1
  34. package/dist/chunks/field-file-drag.js +175 -209
  35. package/dist/chunks/field-file-drag.js.map +1 -1
  36. package/dist/chunks/field-flatpickr.js +94 -898
  37. package/dist/chunks/field-flatpickr.js.map +1 -1
  38. package/dist/chunks/field-modal-select.js +728 -467
  39. package/dist/chunks/field-modal-select.js.map +1 -1
  40. package/dist/chunks/field-modal-tree.js +771 -766
  41. package/dist/chunks/field-modal-tree.js.map +1 -1
  42. package/dist/chunks/field-multi-uploader.js +249 -256
  43. package/dist/chunks/field-multi-uploader.js.map +1 -1
  44. package/dist/chunks/field-repeatable.js +111 -127
  45. package/dist/chunks/field-repeatable.js.map +1 -1
  46. package/dist/chunks/field-single-image-drag.js +286 -338
  47. package/dist/chunks/field-single-image-drag.js.map +1 -1
  48. package/dist/chunks/form.js +146 -159
  49. package/dist/chunks/form.js.map +1 -1
  50. package/dist/chunks/grid.js +349 -418
  51. package/dist/chunks/grid.js.map +1 -1
  52. package/dist/chunks/helper.js +39 -0
  53. package/dist/chunks/helper.js.map +1 -0
  54. package/dist/chunks/http-client.js +221 -211
  55. package/dist/chunks/http-client.js.map +1 -1
  56. package/dist/chunks/iframe-modal.js +95 -115
  57. package/dist/chunks/iframe-modal.js.map +1 -1
  58. package/dist/chunks/keep-tab.js +92 -101
  59. package/dist/chunks/keep-tab.js.map +1 -1
  60. package/dist/chunks/lang.js +250 -0
  61. package/dist/chunks/lang.js.map +1 -0
  62. package/dist/chunks/legacy.js +197 -201
  63. package/dist/chunks/legacy.js.map +1 -1
  64. package/dist/chunks/list-dependent.js +195 -228
  65. package/dist/chunks/list-dependent.js.map +1 -1
  66. package/dist/chunks/loader.js +106 -0
  67. package/dist/chunks/loader.js.map +1 -0
  68. package/dist/chunks/monthSelect.js +251 -0
  69. package/dist/chunks/monthSelect.js.map +1 -0
  70. package/dist/chunks/router.js +111 -0
  71. package/dist/chunks/router.js.map +1 -0
  72. package/dist/chunks/s3-multipart-uploader.js +183 -210
  73. package/dist/chunks/s3-multipart-uploader.js.map +1 -1
  74. package/dist/chunks/s3-uploader.js +106 -128
  75. package/dist/chunks/s3-uploader.js.map +1 -1
  76. package/dist/chunks/show-on.js +358 -205
  77. package/dist/chunks/show-on.js.map +1 -1
  78. package/dist/chunks/timing.js +10 -0
  79. package/dist/chunks/timing.js.map +1 -0
  80. package/dist/chunks/tinymce.js +153 -203
  81. package/dist/chunks/tinymce.js.map +1 -1
  82. package/dist/chunks/ui-bootstrap5.js +58 -72
  83. package/dist/chunks/ui-bootstrap5.js.map +1 -1
  84. package/dist/chunks/ui.js +320 -0
  85. package/dist/chunks/ui.js.map +1 -0
  86. package/dist/chunks/unicorn.js.map +1 -1
  87. package/dist/chunks/useQueue.js +111 -0
  88. package/dist/chunks/useQueue.js.map +1 -0
  89. package/dist/chunks/useStack.js +76 -0
  90. package/dist/chunks/useStack.js.map +1 -0
  91. package/dist/chunks/validation.js +761 -853
  92. package/dist/chunks/validation.js.map +1 -1
  93. package/dist/editor.css +1 -1
  94. package/dist/index.d.ts +27 -15
  95. package/dist/multi-level-menu.css +1 -1
  96. package/dist/switcher.css +1 -1
  97. package/dist/unicorn.js +805 -130
  98. package/dist/unicorn.js.map +1 -1
  99. package/package.json +3 -3
  100. package/src/composable/useBsModalAlert.ts +92 -12
  101. package/src/composable/useHttp.ts +13 -1
  102. package/src/module/s3-uploader.ts +1 -1
  103. package/src/service/ui.ts +31 -15
  104. package/vite.config.ts +5 -1
  105. package/dist/chunks/_commonjsHelpers.js +0 -7
  106. package/dist/chunks/index.js +0 -314
  107. package/dist/chunks/isArguments.js +0 -146
  108. package/dist/chunks/unicorn.js +0 -2580
@@ -1,888 +1,796 @@
1
- import { a as useUniDirective, x as getBoundedInstance, a6 as mergeDeep, a7 as trans, a8 as useUITheme, B as html, v as selectOne, w as selectAll } from "./unicorn.js";
2
- const maxInt = 2147483647;
3
- const base = 36;
4
- const tMin = 1;
5
- const tMax = 26;
6
- const skew = 38;
7
- const damp = 700;
8
- const initialBias = 72;
9
- const initialN = 128;
10
- const delimiter = "-";
11
- const regexNonASCII = /[^\0-\x7F]/;
12
- const regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g;
13
- const errors = {
14
- "overflow": "Overflow: input needs wider integers to process",
15
- "not-basic": "Illegal input >= 0x80 (not a basic code point)",
16
- "invalid-input": "Invalid input"
1
+ import { t as mergeDeep } from "./arr.js";
2
+ import { d as selectOne, o as html, r as getBoundedInstance, u as selectAll } from "./dom.js";
3
+ import { x as useUITheme } from "./ui.js";
4
+ import { n as trans } from "./lang.js";
5
+ import { useUniDirective } from "../unicorn.js";
6
+ //#region ../../../../node_modules/punycode/punycode.es6.js
7
+ /** Highest positive signed 32-bit float value */
8
+ var maxInt = 2147483647;
9
+ /** Bootstring parameters */
10
+ var base = 36;
11
+ var tMin = 1;
12
+ var tMax = 26;
13
+ var skew = 38;
14
+ var damp = 700;
15
+ var initialBias = 72;
16
+ var initialN = 128;
17
+ var delimiter = "-";
18
+ var regexNonASCII = /[^\0-\x7F]/;
19
+ var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g;
20
+ /** Error messages */
21
+ var errors = {
22
+ "overflow": "Overflow: input needs wider integers to process",
23
+ "not-basic": "Illegal input >= 0x80 (not a basic code point)",
24
+ "invalid-input": "Invalid input"
17
25
  };
18
- const baseMinusTMin = base - tMin;
19
- const floor = /* @__PURE__ */ (() => Math.floor)();
20
- const stringFromCharCode = /* @__PURE__ */ (() => String.fromCharCode)();
26
+ /** Convenience shortcuts */
27
+ var baseMinusTMin = base - tMin;
28
+ var floor = Math.floor;
29
+ var stringFromCharCode = String.fromCharCode;
30
+ /**
31
+ * A generic error utility function.
32
+ * @private
33
+ * @param {String} type The error type.
34
+ * @returns {Error} Throws a `RangeError` with the applicable error message.
35
+ */
21
36
  function error(type) {
22
- throw new RangeError(errors[type]);
37
+ throw new RangeError(errors[type]);
23
38
  }
39
+ /**
40
+ * A generic `Array#map` utility function.
41
+ * @private
42
+ * @param {Array} array The array to iterate over.
43
+ * @param {Function} callback The function that gets called for every array
44
+ * item.
45
+ * @returns {Array} A new array of values returned by the callback function.
46
+ */
24
47
  function map(array, callback) {
25
- const result = [];
26
- let length = array.length;
27
- while (length--) {
28
- result[length] = callback(array[length]);
29
- }
30
- return result;
48
+ const result = [];
49
+ let length = array.length;
50
+ while (length--) result[length] = callback(array[length]);
51
+ return result;
31
52
  }
53
+ /**
54
+ * A simple `Array#map`-like wrapper to work with domain name strings or email
55
+ * addresses.
56
+ * @private
57
+ * @param {String} domain The domain name or email address.
58
+ * @param {Function} callback The function that gets called for every
59
+ * character.
60
+ * @returns {String} A new string of characters returned by the callback
61
+ * function.
62
+ */
32
63
  function mapDomain(domain, callback) {
33
- const parts = domain.split("@");
34
- let result = "";
35
- if (parts.length > 1) {
36
- result = parts[0] + "@";
37
- domain = parts[1];
38
- }
39
- domain = domain.replace(regexSeparators, ".");
40
- const labels = domain.split(".");
41
- const encoded = map(labels, callback).join(".");
42
- return result + encoded;
64
+ const parts = domain.split("@");
65
+ let result = "";
66
+ if (parts.length > 1) {
67
+ result = parts[0] + "@";
68
+ domain = parts[1];
69
+ }
70
+ domain = domain.replace(regexSeparators, ".");
71
+ const encoded = map(domain.split("."), callback).join(".");
72
+ return result + encoded;
43
73
  }
74
+ /**
75
+ * Creates an array containing the numeric code points of each Unicode
76
+ * character in the string. While JavaScript uses UCS-2 internally,
77
+ * this function will convert a pair of surrogate halves (each of which
78
+ * UCS-2 exposes as separate characters) into a single code point,
79
+ * matching UTF-16.
80
+ * @see `punycode.ucs2.encode`
81
+ * @see <https://mathiasbynens.be/notes/javascript-encoding>
82
+ * @memberOf punycode.ucs2
83
+ * @name decode
84
+ * @param {String} string The Unicode input string (UCS-2).
85
+ * @returns {Array} The new array of code points.
86
+ */
44
87
  function ucs2decode(string) {
45
- const output = [];
46
- let counter = 0;
47
- const length = string.length;
48
- while (counter < length) {
49
- const value = string.charCodeAt(counter++);
50
- if (value >= 55296 && value <= 56319 && counter < length) {
51
- const extra = string.charCodeAt(counter++);
52
- if ((extra & 64512) == 56320) {
53
- output.push(((value & 1023) << 10) + (extra & 1023) + 65536);
54
- } else {
55
- output.push(value);
56
- counter--;
57
- }
58
- } else {
59
- output.push(value);
60
- }
61
- }
62
- return output;
88
+ const output = [];
89
+ let counter = 0;
90
+ const length = string.length;
91
+ while (counter < length) {
92
+ const value = string.charCodeAt(counter++);
93
+ if (value >= 55296 && value <= 56319 && counter < length) {
94
+ const extra = string.charCodeAt(counter++);
95
+ if ((extra & 64512) == 56320) output.push(((value & 1023) << 10) + (extra & 1023) + 65536);
96
+ else {
97
+ output.push(value);
98
+ counter--;
99
+ }
100
+ } else output.push(value);
101
+ }
102
+ return output;
63
103
  }
64
- const digitToBasic = function(digit, flag) {
65
- return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
104
+ /**
105
+ * Converts a digit/integer into a basic code point.
106
+ * @see `basicToDigit()`
107
+ * @private
108
+ * @param {Number} digit The numeric value of a basic code point.
109
+ * @returns {Number} The basic code point whose value (when used for
110
+ * representing integers) is `digit`, which needs to be in the range
111
+ * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
112
+ * used; else, the lowercase form is used. The behavior is undefined
113
+ * if `flag` is non-zero and `digit` has no uppercase form.
114
+ */
115
+ var digitToBasic = function(digit, flag) {
116
+ return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
66
117
  };
67
- const adapt = function(delta, numPoints, firstTime) {
68
- let k = 0;
69
- delta = firstTime ? floor(delta / damp) : delta >> 1;
70
- delta += floor(delta / numPoints);
71
- for (; delta > baseMinusTMin * tMax >> 1; k += base) {
72
- delta = floor(delta / baseMinusTMin);
73
- }
74
- return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
118
+ /**
119
+ * Bias adaptation function as per section 3.4 of RFC 3492.
120
+ * https://tools.ietf.org/html/rfc3492#section-3.4
121
+ * @private
122
+ */
123
+ var adapt = function(delta, numPoints, firstTime) {
124
+ let k = 0;
125
+ delta = firstTime ? floor(delta / damp) : delta >> 1;
126
+ delta += floor(delta / numPoints);
127
+ for (; delta > baseMinusTMin * tMax >> 1; k += base) delta = floor(delta / baseMinusTMin);
128
+ return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
75
129
  };
76
- const encode = function(input) {
77
- const output = [];
78
- input = ucs2decode(input);
79
- const inputLength = input.length;
80
- let n = initialN;
81
- let delta = 0;
82
- let bias = initialBias;
83
- for (const currentValue of input) {
84
- if (currentValue < 128) {
85
- output.push(stringFromCharCode(currentValue));
86
- }
87
- }
88
- const basicLength = output.length;
89
- let handledCPCount = basicLength;
90
- if (basicLength) {
91
- output.push(delimiter);
92
- }
93
- while (handledCPCount < inputLength) {
94
- let m = maxInt;
95
- for (const currentValue of input) {
96
- if (currentValue >= n && currentValue < m) {
97
- m = currentValue;
98
- }
99
- }
100
- const handledCPCountPlusOne = handledCPCount + 1;
101
- if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
102
- error("overflow");
103
- }
104
- delta += (m - n) * handledCPCountPlusOne;
105
- n = m;
106
- for (const currentValue of input) {
107
- if (currentValue < n && ++delta > maxInt) {
108
- error("overflow");
109
- }
110
- if (currentValue === n) {
111
- let q = delta;
112
- for (let k = base; ; k += base) {
113
- const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
114
- if (q < t) {
115
- break;
116
- }
117
- const qMinusT = q - t;
118
- const baseMinusT = base - t;
119
- output.push(
120
- stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
121
- );
122
- q = floor(qMinusT / baseMinusT);
123
- }
124
- output.push(stringFromCharCode(digitToBasic(q, 0)));
125
- bias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength);
126
- delta = 0;
127
- ++handledCPCount;
128
- }
129
- }
130
- ++delta;
131
- ++n;
132
- }
133
- return output.join("");
130
+ /**
131
+ * Converts a string of Unicode symbols (e.g. a domain name label) to a
132
+ * Punycode string of ASCII-only symbols.
133
+ * @memberOf punycode
134
+ * @param {String} input The string of Unicode symbols.
135
+ * @returns {String} The resulting Punycode string of ASCII-only symbols.
136
+ */
137
+ var encode = function(input) {
138
+ const output = [];
139
+ input = ucs2decode(input);
140
+ const inputLength = input.length;
141
+ let n = initialN;
142
+ let delta = 0;
143
+ let bias = initialBias;
144
+ for (const currentValue of input) if (currentValue < 128) output.push(stringFromCharCode(currentValue));
145
+ const basicLength = output.length;
146
+ let handledCPCount = basicLength;
147
+ if (basicLength) output.push(delimiter);
148
+ while (handledCPCount < inputLength) {
149
+ let m = maxInt;
150
+ for (const currentValue of input) if (currentValue >= n && currentValue < m) m = currentValue;
151
+ const handledCPCountPlusOne = handledCPCount + 1;
152
+ if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) error("overflow");
153
+ delta += (m - n) * handledCPCountPlusOne;
154
+ n = m;
155
+ for (const currentValue of input) {
156
+ if (currentValue < n && ++delta > maxInt) error("overflow");
157
+ if (currentValue === n) {
158
+ let q = delta;
159
+ for (let k = base;; k += base) {
160
+ const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias;
161
+ if (q < t) break;
162
+ const qMinusT = q - t;
163
+ const baseMinusT = base - t;
164
+ output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0)));
165
+ q = floor(qMinusT / baseMinusT);
166
+ }
167
+ output.push(stringFromCharCode(digitToBasic(q, 0)));
168
+ bias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength);
169
+ delta = 0;
170
+ ++handledCPCount;
171
+ }
172
+ }
173
+ ++delta;
174
+ ++n;
175
+ }
176
+ return output.join("");
134
177
  };
135
- const toASCII = function(input) {
136
- return mapDomain(input, function(string) {
137
- return regexNonASCII.test(string) ? "xn--" + encode(string) : string;
138
- });
178
+ /**
179
+ * Converts a Unicode string representing a domain name or an email address to
180
+ * Punycode. Only the non-ASCII parts of the domain name will be converted,
181
+ * i.e. it doesn't matter if you call it with a domain that's already in
182
+ * ASCII.
183
+ * @memberOf punycode
184
+ * @param {String} input The domain name or email address to convert, as a
185
+ * Unicode string.
186
+ * @returns {String} The Punycode representation of the given domain name or
187
+ * email address.
188
+ */
189
+ var toASCII = function(input) {
190
+ return mapDomain(input, function(string) {
191
+ return regexNonASCII.test(string) ? "xn--" + encode(string) : string;
192
+ });
139
193
  };
140
- const validatorHandlers = {};
141
- const defaultOptions = {
142
- scroll: false,
143
- scrollOffset: -100,
144
- enabled: true,
145
- fieldSelector: null,
146
- validatedClass: null
194
+ //#endregion
195
+ //#region src/module/validation.ts
196
+ var validatorHandlers = {};
197
+ var defaultOptions = {
198
+ scroll: false,
199
+ scrollOffset: -100,
200
+ enabled: true,
201
+ fieldSelector: null,
202
+ validatedClass: null
147
203
  };
148
- const defaultFieldOptions = {
149
- formSelector: "[uni-form-validate]",
150
- errorSelector: "[data-field-error]",
151
- selector: "input[data-field-input], select[data-field-input], textarea[data-field-input]",
152
- validClass: "is-valid",
153
- invalidClass: "is-invalid",
154
- events: ["change"],
155
- errorMessageClass: "invalid-tooltip",
156
- inputOptions: false,
157
- inputOptionsWrapperSelector: "div[data-field-input]",
158
- inputOptionsSelector: "[data-input-option]"
204
+ var defaultFieldOptions = {
205
+ formSelector: "[uni-form-validate]",
206
+ errorSelector: "[data-field-error]",
207
+ selector: "input[data-field-input], select[data-field-input], textarea[data-field-input]",
208
+ validClass: "is-valid",
209
+ invalidClass: "is-invalid",
210
+ events: ["change"],
211
+ errorMessageClass: "invalid-tooltip",
212
+ inputOptions: false,
213
+ inputOptionsWrapperSelector: "div[data-field-input]",
214
+ inputOptionsSelector: "[data-input-option]"
215
+ };
216
+ var UnicornFormValidation = class {
217
+ presetFields = [];
218
+ static globalValidators = {};
219
+ validators = {};
220
+ options;
221
+ $form;
222
+ static is = "uni-form-validate";
223
+ constructor(el, options = {}) {
224
+ this.$form = selectOne(el);
225
+ this.options = this.mergeOptions(options);
226
+ this.registerDefaultValidators();
227
+ this.init();
228
+ }
229
+ mergeOptions(options) {
230
+ if (Array.isArray(options)) options = {};
231
+ return this.options = mergeDeep({}, defaultOptions, this.options || {}, options);
232
+ }
233
+ get scrollEnabled() {
234
+ return this.options.scroll;
235
+ }
236
+ get scrollOffset() {
237
+ return Number(this.options.scrollOffset || -100);
238
+ }
239
+ get fieldSelector() {
240
+ return this.options.fieldSelector || "input, select, textarea";
241
+ }
242
+ get validatedClass() {
243
+ return this.options.validatedClass || "was-validated";
244
+ }
245
+ init() {
246
+ if (this.$form.tagName === "FORM") {
247
+ this.$form.setAttribute("novalidate", "true");
248
+ this.$form.addEventListener("submit", (event) => {
249
+ if (this.options.enabled && !this.validateAll()) {
250
+ event.stopImmediatePropagation();
251
+ event.stopPropagation();
252
+ event.preventDefault();
253
+ this.$form.dispatchEvent(new CustomEvent("invalid"));
254
+ return false;
255
+ }
256
+ return true;
257
+ }, false);
258
+ }
259
+ this.prepareFields(this.findDOMFields());
260
+ this.prepareFields(this.presetFields);
261
+ }
262
+ findDOMFields() {
263
+ return selectAll(this.$form.querySelectorAll(this.fieldSelector));
264
+ }
265
+ prepareFields(inputs) {
266
+ inputs.forEach((input) => {
267
+ this.prepareFieldWrapper(input);
268
+ });
269
+ return Promise.resolve();
270
+ }
271
+ prepareFieldWrapper(input) {
272
+ if ([
273
+ "INPUT",
274
+ "SELECT",
275
+ "TEXTAREA"
276
+ ].indexOf(input.tagName) !== -1) {
277
+ let wrapper = input.closest("[uni-field-validate]");
278
+ if (!wrapper) {
279
+ wrapper = input.closest("[data-input-container]") || input.parentElement;
280
+ wrapper?.setAttribute("uni-field-validate", "{}");
281
+ }
282
+ return wrapper;
283
+ }
284
+ return input;
285
+ }
286
+ findFields(containsPresets = true) {
287
+ let inputs = this.findDOMFields();
288
+ if (containsPresets) inputs.push(...this.presetFields);
289
+ return inputs.map((input) => this.prepareFieldWrapper(input)).filter((input) => input != null);
290
+ }
291
+ getFieldComponents(containsPresets = true) {
292
+ const components = [];
293
+ for (const field of this.findFields(containsPresets)) {
294
+ const v = this.getFieldComponent(field);
295
+ if (v) components.push(v);
296
+ }
297
+ return components;
298
+ }
299
+ getFieldComponent(input) {
300
+ let v = getBoundedInstance(input, "field.validation");
301
+ if (!v) {
302
+ const wrapper = input.closest("[uni-field-validate]");
303
+ if (wrapper) v = getBoundedInstance(wrapper, "field.validation");
304
+ }
305
+ return v;
306
+ }
307
+ validateAll(fields) {
308
+ this.markFormAsUnvalidated();
309
+ fields = fields || this.findFields();
310
+ let firstFail = null;
311
+ for (const field of fields) {
312
+ const fv = this.getFieldComponent(field);
313
+ if (!fv) continue;
314
+ if (!fv.checkValidity() && !firstFail) firstFail = field;
315
+ }
316
+ this.markFormAsValidated();
317
+ if (firstFail && this.scrollEnabled) this.scrollTo(firstFail);
318
+ return firstFail === null;
319
+ }
320
+ async validateAllAsync(fields) {
321
+ this.markFormAsUnvalidated();
322
+ fields = fields || this.findFields();
323
+ let firstFail = null;
324
+ const promises = [];
325
+ for (const field of fields) {
326
+ const fv = this.getFieldComponent(field);
327
+ if (!fv) continue;
328
+ promises.push(fv.checkValidityAsync().then((result) => {
329
+ if (!result && !firstFail) firstFail = field;
330
+ return result;
331
+ }));
332
+ }
333
+ await Promise.all(promises);
334
+ this.markFormAsValidated();
335
+ if (firstFail && this.scrollEnabled) this.scrollTo(firstFail);
336
+ return firstFail === null;
337
+ }
338
+ scrollTo(element) {
339
+ const offset = this.scrollOffset;
340
+ const offsetPosition = element.getBoundingClientRect().top + window.scrollY + offset;
341
+ window.scrollTo({
342
+ top: offsetPosition,
343
+ behavior: "smooth"
344
+ });
345
+ }
346
+ markFormAsValidated() {
347
+ if (!this.$form) return;
348
+ this.$form.classList.add(this.validatedClass);
349
+ }
350
+ markFormAsUnvalidated() {
351
+ if (!this.$form) return;
352
+ this.$form.classList.remove(this.validatedClass);
353
+ }
354
+ addField(field) {
355
+ this.presetFields.push(field);
356
+ this.prepareFieldWrapper(field);
357
+ return this;
358
+ }
359
+ registerDefaultValidators() {
360
+ for (let name in validatorHandlers) this.addValidator(name, validatorHandlers[name]);
361
+ }
362
+ /**
363
+ * Add validator handler.
364
+ */
365
+ addValidator(name, handler, options = {}) {
366
+ options = options || {};
367
+ this.validators[name] = {
368
+ handler,
369
+ options
370
+ };
371
+ return this;
372
+ }
373
+ /**
374
+ * Add validator handler.
375
+ */
376
+ static addGlobalValidator(name, handler, options = {}) {
377
+ options = options || {};
378
+ this.globalValidators[name] = {
379
+ handler,
380
+ options
381
+ };
382
+ return this;
383
+ }
384
+ };
385
+ var UnicornFieldValidation = class {
386
+ $input;
387
+ options = {};
388
+ static is = "uni-field-validate";
389
+ constructor(el, options = {}) {
390
+ this.el = el;
391
+ this.setOptions(options);
392
+ this.$input = this.selectInput();
393
+ this.init();
394
+ }
395
+ setOptions(options) {
396
+ if (Array.isArray(options)) options = {};
397
+ this.options = options;
398
+ return this;
399
+ }
400
+ get mergedOptions() {
401
+ return mergeDeep({}, defaultFieldOptions, this.globalOptions, this.options);
402
+ }
403
+ get $form() {
404
+ return this.getForm();
405
+ }
406
+ get errorSelector() {
407
+ return this.mergedOptions.errorSelector;
408
+ }
409
+ get selector() {
410
+ return this.mergedOptions.selector;
411
+ }
412
+ get validClass() {
413
+ return this.mergedOptions.validClass;
414
+ }
415
+ get invalidClass() {
416
+ return this.mergedOptions.invalidClass;
417
+ }
418
+ get isVisible() {
419
+ return !!(this.el.offsetWidth || this.el.offsetHeight || this.el.getClientRects().length);
420
+ }
421
+ get isInputOptions() {
422
+ return Boolean(this.mergedOptions.inputOptions);
423
+ }
424
+ get validationMessage() {
425
+ return this.$input?.validationMessage || "";
426
+ }
427
+ get validity() {
428
+ return this.$input?.validity;
429
+ }
430
+ selectInput() {
431
+ let selector = this.selector;
432
+ if (this.mergedOptions.inputOptions) selector += ", " + this.mergedOptions.inputOptionsWrapperSelector;
433
+ let input = this.el.querySelector(selector);
434
+ if (!input) input = this.el.querySelector("input, select, textarea");
435
+ if (!input) return;
436
+ return this.$input = input;
437
+ }
438
+ init() {
439
+ this.selectInput();
440
+ this.bindEvents();
441
+ this.prepareWrapper();
442
+ if (this.isInputOptions) {
443
+ const $input = this.$input;
444
+ if (!($input instanceof HTMLInputElement) && !($input instanceof HTMLSelectElement) && !($input instanceof HTMLTextAreaElement)) {
445
+ $input.validationMessage = "";
446
+ $input.setCustomValidity = (msg) => {
447
+ $input.validationMessage = String(msg);
448
+ };
449
+ $input.checkValidity = () => {
450
+ return this.checkInputOptionsValidity();
451
+ };
452
+ }
453
+ }
454
+ }
455
+ bindEvents() {
456
+ if (!this.$input) return;
457
+ this.$input.addEventListener("invalid", (e) => {
458
+ this.showInvalidResponse();
459
+ });
460
+ this.mergedOptions.events.forEach((eventName) => {
461
+ this.$input?.addEventListener(eventName, () => {
462
+ this.checkValidity();
463
+ });
464
+ });
465
+ }
466
+ prepareWrapper() {
467
+ if (this.el.querySelector(this.errorSelector)?.classList?.contains("invalid-tooltip")) {
468
+ if (window.getComputedStyle(this.el).position === "static") this.el.style.position = "relative";
469
+ }
470
+ }
471
+ checkValidity() {
472
+ if (!this.$input) return true;
473
+ if (this.$input.hasAttribute("readonly")) return true;
474
+ if (this.$input.hasAttribute("[data-novalidate]")) return true;
475
+ if (this.$input.closest("[data-novalidate]")) return true;
476
+ if (this.hasChildDirectives()) return true;
477
+ this.$input.setCustomValidity("");
478
+ let valid = this.$input.checkValidity();
479
+ if (valid && this.$form) valid = this.runCustomValidity();
480
+ this.updateValidClass(valid);
481
+ return valid;
482
+ }
483
+ runCustomValidity() {
484
+ if (!this.$input) return true;
485
+ const validates = (this.$input.getAttribute("data-validate") || "").split("|");
486
+ let result = true;
487
+ if (this.$input.value !== "" && validates.length) {
488
+ if (!this.checkCustomDataAttributeValidity()) return false;
489
+ for (const validatorName of validates) {
490
+ const [validator, options] = this.getValidator(validatorName) || [null, {}];
491
+ if (!validator) continue;
492
+ Object.assign(options, validator.options);
493
+ let r = validator.handler(this.$input.value, this.$input, options, this);
494
+ if (r instanceof Promise || typeof r === "object" && r.then) {
495
+ r.then((result) => {
496
+ this.handleAsyncCustomResult(result, validator);
497
+ });
498
+ continue;
499
+ }
500
+ if (!this.handleCustomResult(r, validator)) {
501
+ result = false;
502
+ break;
503
+ }
504
+ }
505
+ }
506
+ return result;
507
+ }
508
+ async checkValidityAsync() {
509
+ if (!this.$input) return true;
510
+ if (this.$input.hasAttribute("readonly")) return true;
511
+ if (this.$input.hasAttribute("[data-novalidate]")) return true;
512
+ if (this.hasChildDirectives()) return true;
513
+ this.$input.setCustomValidity("");
514
+ let valid = this.$input.checkValidity();
515
+ if (valid && this.$form) valid = await this.runCustomValidityAsync();
516
+ this.updateValidClass(valid);
517
+ return valid;
518
+ }
519
+ async runCustomValidityAsync() {
520
+ if (!this.$input) return true;
521
+ const validates = (this.$input.getAttribute("data-validate") || "").split("|");
522
+ const results = [];
523
+ const promises = [];
524
+ if (this.$input.value !== "" && validates.length) {
525
+ if (!this.checkCustomDataAttributeValidity()) return false;
526
+ for (const validatorName of validates) {
527
+ let [validator, options] = this.getValidator(validatorName) || [null, {}];
528
+ if (!validator) continue;
529
+ options = Object.assign({}, options, validator.options || {});
530
+ promises.push(Promise.resolve(validator.handler(this.$input.value, this.$input, options, this)).then((r) => {
531
+ results.push(this.handleAsyncCustomResult(r, validator));
532
+ return r;
533
+ }));
534
+ }
535
+ }
536
+ await Promise.all(promises);
537
+ for (const result of results) if (result === false) return false;
538
+ return true;
539
+ }
540
+ checkCustomDataAttributeValidity() {
541
+ const error = this.$input?.dataset.validationFail;
542
+ return this.handleCustomResult(error);
543
+ }
544
+ checkInputOptionsValidity() {
545
+ if (!this.$input) return true;
546
+ const isRequired = this.$input.getAttribute("required") != null;
547
+ const optionWrappers = this.$input.querySelectorAll(this.mergedOptions.inputOptionsSelector);
548
+ let result = true;
549
+ if (isRequired) for (const optionWrapper of optionWrappers) {
550
+ const input = optionWrapper.querySelector("input");
551
+ result = false;
552
+ if (input?.checked) {
553
+ result = true;
554
+ break;
555
+ }
556
+ }
557
+ const n = document.createElement("input");
558
+ n.required = isRequired;
559
+ if (result) n.value = "placeholder";
560
+ n.checkValidity();
561
+ this.$input.validationMessage = n.validationMessage;
562
+ this.$input.validity = n.validity;
563
+ for (const optionWrapper of optionWrappers) optionWrapper.querySelector("input")?.setCustomValidity(n.validationMessage);
564
+ if (!result) this.$input.dispatchEvent(new CustomEvent("invalid"));
565
+ return result;
566
+ }
567
+ /**
568
+ * @param valid {boolean}
569
+ */
570
+ updateValidClass(valid) {
571
+ const $invalidTarget = this.getErrorElement()?.previousElementSibling;
572
+ this.$input?.classList.remove(this.invalidClass);
573
+ this.$input?.classList.remove(this.validClass);
574
+ this.el.classList.remove(this.invalidClass);
575
+ this.el.classList.remove(this.validClass);
576
+ $invalidTarget?.classList.remove(this.invalidClass);
577
+ $invalidTarget?.classList.remove(this.validClass);
578
+ if (valid) {
579
+ this.$input?.classList.add(this.validClass);
580
+ this.el.classList.add(this.validClass);
581
+ $invalidTarget?.classList.add(this.validClass);
582
+ } else {
583
+ this.$input?.classList.add(this.invalidClass);
584
+ this.el.classList.add(this.invalidClass);
585
+ $invalidTarget?.classList.add(this.invalidClass);
586
+ }
587
+ }
588
+ getFormValidation(element) {
589
+ return getBoundedInstance(element || this.getForm(), "form.validation");
590
+ }
591
+ get globalOptions() {
592
+ return this.getFormValidation()?.options?.fieldDefaults ?? {};
593
+ }
594
+ getValidator(name) {
595
+ const matches = name.match(/(?<type>[\w\-_]+)(\((?<params>.*)\))*/);
596
+ if (!matches) return null;
597
+ const validatorName = matches.groups?.type || "";
598
+ const params = matches.groups?.params || "";
599
+ const validator = this.getFormValidation(this.$form)?.validators[validatorName] || UnicornFormValidation.globalValidators[validatorName];
600
+ if (!validator) return null;
601
+ const paramMatches = params.matchAll(/(?<key>\w+)(\s?[=:]\s?(?<value>\w+))?/g);
602
+ const options = {};
603
+ for (const paramMatch of paramMatches) {
604
+ const match = paramMatch?.groups;
605
+ if (!match) continue;
606
+ options[match.key] = handleParamValue(match.value);
607
+ }
608
+ return [validator, options];
609
+ }
610
+ handleCustomResult(result, validator) {
611
+ if (typeof result === "string") {
612
+ this.$input?.setCustomValidity(result);
613
+ result = result === "";
614
+ } else if (result === void 0) result = true;
615
+ if (result) this.$input?.setCustomValidity("");
616
+ else if (validator) this.raiseCustomErrorState(validator);
617
+ return result;
618
+ }
619
+ handleAsyncCustomResult(result, validator) {
620
+ result = this.handleCustomResult(result, validator);
621
+ this.$input?.checkValidity();
622
+ this.updateValidClass(result);
623
+ return result;
624
+ }
625
+ raiseCustomErrorState(validator) {
626
+ let help;
627
+ if (this.$input?.validationMessage === "") {
628
+ help = validator.options?.notice;
629
+ if (typeof help === "function") help = help(this.$input, this);
630
+ if (help != null) this.$input?.setCustomValidity(help);
631
+ }
632
+ if (this.$input?.validationMessage === "") this.$input?.setCustomValidity(trans("unicorn.message.validation.custom.error"));
633
+ this.$input?.dispatchEvent(new CustomEvent("invalid"));
634
+ }
635
+ setAsInvalidAndReport(error) {
636
+ this.setCustomValidity(error);
637
+ this.showInvalidResponse();
638
+ }
639
+ setCustomValidity(error) {
640
+ this.$input?.setCustomValidity(error);
641
+ }
642
+ reportValidity() {
643
+ if (this.validationMessage !== "") this.showInvalidResponse();
644
+ }
645
+ showInvalidResponse() {
646
+ if (this.hasChildDirectives()) return;
647
+ /** @type ValidityState */
648
+ const state = this.$input?.validity;
649
+ let message = this.$input?.validationMessage || "";
650
+ for (let key in state) if (state[key] && this.$input?.dataset[key + "Message"]) {
651
+ message = this.$input?.dataset[key + "Message"] || "";
652
+ break;
653
+ }
654
+ if (!this.isVisible) {
655
+ let title = this.findLabel()?.textContent;
656
+ if (!title) title = this.$input?.name || "";
657
+ useUITheme().renderMessage(`Field: ${title} - ${message}`, "warning");
658
+ }
659
+ let $help = this.getErrorElement();
660
+ if (!$help) {
661
+ $help = this.createHelpElement();
662
+ this.el.appendChild($help);
663
+ this.prepareWrapper();
664
+ }
665
+ $help.textContent = message;
666
+ this.updateValidClass(false);
667
+ }
668
+ getErrorElement() {
669
+ return this.el.querySelector(this.errorSelector);
670
+ }
671
+ createHelpElement() {
672
+ const className = this.mergedOptions.errorMessageClass;
673
+ const parsed = this.parseSelector(this.errorSelector || "");
674
+ const $help = html(`<div class="${className}"></div>`);
675
+ $help.classList.add(...parsed.classes);
676
+ parsed.attrs.forEach((attr) => {
677
+ $help.setAttribute(attr[0], attr[1] || "");
678
+ });
679
+ parsed.ids.forEach((id) => {
680
+ $help.id = id;
681
+ });
682
+ return $help;
683
+ }
684
+ /**
685
+ * @see https://stackoverflow.com/a/17888178
686
+ */
687
+ parseSelector(subselector) {
688
+ const obj = {
689
+ tags: [],
690
+ classes: [],
691
+ ids: [],
692
+ attrs: []
693
+ };
694
+ for (const token of subselector.split(/(?=\.)|(?=#)|(?=\[)/)) switch (token[0]) {
695
+ case "#":
696
+ obj.ids.push(token.slice(1));
697
+ break;
698
+ case ".":
699
+ obj.classes.push(token.slice(1));
700
+ break;
701
+ case "[":
702
+ obj.attrs.push(token.slice(1, -1).split("="));
703
+ break;
704
+ default:
705
+ obj.tags.push(token);
706
+ break;
707
+ }
708
+ return obj;
709
+ }
710
+ setAsValidAndClearResponse() {
711
+ this.setCustomValidity("");
712
+ this.updateValidClass(true);
713
+ this.clearInvalidResponse();
714
+ }
715
+ clearInvalidResponse() {
716
+ const $help = this.el.querySelector(this.errorSelector);
717
+ $help.textContent = "";
718
+ }
719
+ getForm() {
720
+ return this.el.closest(this.options.formSelector || "[uni-form-validate]");
721
+ }
722
+ findLabel() {
723
+ const id = this.$input?.id || "";
724
+ const wrapper = this.$input?.closest("[data-field-wrapper]");
725
+ let label = null;
726
+ if (wrapper) label = wrapper.querySelector("[data-field-label]");
727
+ if (!label) label = document.querySelector(`label[for="${id}"]`);
728
+ return label;
729
+ }
730
+ hasChildDirectives() {
731
+ return this.el.querySelector("[uni-field-validate]") != null;
732
+ }
159
733
  };
160
- class UnicornFormValidation {
161
- presetFields = [];
162
- static globalValidators = {};
163
- validators = {};
164
- options;
165
- $form;
166
- static is = "uni-form-validate";
167
- constructor(el, options = {}) {
168
- this.$form = selectOne(el);
169
- this.options = this.mergeOptions(options);
170
- this.registerDefaultValidators();
171
- this.init();
172
- }
173
- mergeOptions(options) {
174
- if (Array.isArray(options)) {
175
- options = {};
176
- }
177
- return this.options = mergeDeep({}, defaultOptions, this.options || {}, options);
178
- }
179
- get scrollEnabled() {
180
- return this.options.scroll;
181
- }
182
- get scrollOffset() {
183
- return Number(this.options.scrollOffset || -100);
184
- }
185
- get fieldSelector() {
186
- return this.options.fieldSelector || "input, select, textarea";
187
- }
188
- get validatedClass() {
189
- return this.options.validatedClass || "was-validated";
190
- }
191
- init() {
192
- if (this.$form.tagName === "FORM") {
193
- this.$form.setAttribute("novalidate", "true");
194
- this.$form.addEventListener("submit", (event) => {
195
- if (this.options.enabled && !this.validateAll()) {
196
- event.stopImmediatePropagation();
197
- event.stopPropagation();
198
- event.preventDefault();
199
- this.$form.dispatchEvent(new CustomEvent("invalid"));
200
- return false;
201
- }
202
- return true;
203
- }, false);
204
- }
205
- this.prepareFields(this.findDOMFields());
206
- this.prepareFields(this.presetFields);
207
- }
208
- findDOMFields() {
209
- return selectAll(this.$form.querySelectorAll(this.fieldSelector));
210
- }
211
- prepareFields(inputs) {
212
- inputs.forEach((input) => {
213
- this.prepareFieldWrapper(input);
214
- });
215
- return Promise.resolve();
216
- }
217
- prepareFieldWrapper(input) {
218
- if (["INPUT", "SELECT", "TEXTAREA"].indexOf(input.tagName) !== -1) {
219
- let wrapper = input.closest("[uni-field-validate]");
220
- if (!wrapper) {
221
- wrapper = input.closest("[data-input-container]") || input.parentElement;
222
- wrapper?.setAttribute("uni-field-validate", "{}");
223
- }
224
- return wrapper;
225
- }
226
- return input;
227
- }
228
- findFields(containsPresets = true) {
229
- let inputs = this.findDOMFields();
230
- if (containsPresets) {
231
- inputs.push(...this.presetFields);
232
- }
233
- return inputs.map((input) => this.prepareFieldWrapper(input)).filter((input) => input != null);
234
- }
235
- getFieldComponents(containsPresets = true) {
236
- const components = [];
237
- for (const field of this.findFields(containsPresets)) {
238
- const v = this.getFieldComponent(field);
239
- if (v) {
240
- components.push(v);
241
- }
242
- }
243
- return components;
244
- }
245
- getFieldComponent(input) {
246
- let v = getBoundedInstance(input, "field.validation");
247
- if (!v) {
248
- const wrapper = input.closest("[uni-field-validate]");
249
- if (wrapper) {
250
- v = getBoundedInstance(wrapper, "field.validation");
251
- }
252
- }
253
- return v;
254
- }
255
- validateAll(fields) {
256
- this.markFormAsUnvalidated();
257
- fields = fields || this.findFields();
258
- let firstFail = null;
259
- for (const field of fields) {
260
- const fv = this.getFieldComponent(field);
261
- if (!fv) {
262
- continue;
263
- }
264
- const result = fv.checkValidity();
265
- if (!result && !firstFail) {
266
- firstFail = field;
267
- }
268
- }
269
- this.markFormAsValidated();
270
- if (firstFail && this.scrollEnabled) {
271
- this.scrollTo(firstFail);
272
- }
273
- return firstFail === null;
274
- }
275
- async validateAllAsync(fields) {
276
- this.markFormAsUnvalidated();
277
- fields = fields || this.findFields();
278
- let firstFail = null;
279
- const promises = [];
280
- for (const field of fields) {
281
- const fv = this.getFieldComponent(field);
282
- if (!fv) {
283
- continue;
284
- }
285
- promises.push(
286
- fv.checkValidityAsync().then((result) => {
287
- if (!result && !firstFail) {
288
- firstFail = field;
289
- }
290
- return result;
291
- })
292
- );
293
- }
294
- await Promise.all(promises);
295
- this.markFormAsValidated();
296
- if (firstFail && this.scrollEnabled) {
297
- this.scrollTo(firstFail);
298
- }
299
- return firstFail === null;
300
- }
301
- scrollTo(element) {
302
- const offset = this.scrollOffset;
303
- const elementPosition = element.getBoundingClientRect().top;
304
- const offsetPosition = elementPosition + window.scrollY + offset;
305
- window.scrollTo({
306
- top: offsetPosition,
307
- behavior: "smooth"
308
- });
309
- }
310
- markFormAsValidated() {
311
- if (!this.$form) {
312
- return;
313
- }
314
- this.$form.classList.add(this.validatedClass);
315
- }
316
- markFormAsUnvalidated() {
317
- if (!this.$form) {
318
- return;
319
- }
320
- this.$form.classList.remove(this.validatedClass);
321
- }
322
- addField(field) {
323
- this.presetFields.push(field);
324
- this.prepareFieldWrapper(field);
325
- return this;
326
- }
327
- registerDefaultValidators() {
328
- for (let name in validatorHandlers) {
329
- this.addValidator(name, validatorHandlers[name]);
330
- }
331
- }
332
- /**
333
- * Add validator handler.
334
- */
335
- addValidator(name, handler, options = {}) {
336
- options = options || {};
337
- this.validators[name] = {
338
- handler,
339
- options
340
- };
341
- return this;
342
- }
343
- /**
344
- * Add validator handler.
345
- */
346
- static addGlobalValidator(name, handler, options = {}) {
347
- options = options || {};
348
- this.globalValidators[name] = {
349
- handler,
350
- options
351
- };
352
- return this;
353
- }
354
- }
355
- class UnicornFieldValidation {
356
- constructor(el, options = {}) {
357
- this.el = el;
358
- this.setOptions(options);
359
- this.$input = this.selectInput();
360
- this.init();
361
- }
362
- $input;
363
- options = {};
364
- static is = "uni-field-validate";
365
- setOptions(options) {
366
- if (Array.isArray(options)) {
367
- options = {};
368
- }
369
- this.options = options;
370
- return this;
371
- }
372
- get mergedOptions() {
373
- return mergeDeep({}, defaultFieldOptions, this.globalOptions, this.options);
374
- }
375
- get $form() {
376
- return this.getForm();
377
- }
378
- get errorSelector() {
379
- return this.mergedOptions.errorSelector;
380
- }
381
- get selector() {
382
- return this.mergedOptions.selector;
383
- }
384
- get validClass() {
385
- return this.mergedOptions.validClass;
386
- }
387
- get invalidClass() {
388
- return this.mergedOptions.invalidClass;
389
- }
390
- get isVisible() {
391
- return !!(this.el.offsetWidth || this.el.offsetHeight || this.el.getClientRects().length);
392
- }
393
- get isInputOptions() {
394
- return Boolean(this.mergedOptions.inputOptions);
395
- }
396
- get validationMessage() {
397
- return this.$input?.validationMessage || "";
398
- }
399
- get validity() {
400
- return this.$input?.validity;
401
- }
402
- selectInput() {
403
- let selector = this.selector;
404
- if (this.mergedOptions.inputOptions) {
405
- selector += ", " + this.mergedOptions.inputOptionsWrapperSelector;
406
- }
407
- let input = this.el.querySelector(selector);
408
- if (!input) {
409
- input = this.el.querySelector("input, select, textarea");
410
- }
411
- if (!input) {
412
- return void 0;
413
- }
414
- return this.$input = input;
415
- }
416
- init() {
417
- this.selectInput();
418
- this.bindEvents();
419
- this.prepareWrapper();
420
- if (this.isInputOptions) {
421
- const $input = this.$input;
422
- if (!($input instanceof HTMLInputElement) && !($input instanceof HTMLSelectElement) && !($input instanceof HTMLTextAreaElement)) {
423
- $input.validationMessage = "";
424
- $input.setCustomValidity = (msg) => {
425
- $input.validationMessage = String(msg);
426
- };
427
- $input.checkValidity = () => {
428
- return this.checkInputOptionsValidity();
429
- };
430
- }
431
- }
432
- }
433
- bindEvents() {
434
- if (!this.$input) {
435
- return;
436
- }
437
- this.$input.addEventListener("invalid", (e) => {
438
- this.showInvalidResponse();
439
- });
440
- const events = this.mergedOptions.events;
441
- events.forEach((eventName) => {
442
- this.$input?.addEventListener(eventName, () => {
443
- this.checkValidity();
444
- });
445
- });
446
- }
447
- prepareWrapper() {
448
- if (this.el.querySelector(this.errorSelector)?.classList?.contains("invalid-tooltip")) {
449
- if (window.getComputedStyle(this.el).position === "static") {
450
- this.el.style.position = "relative";
451
- }
452
- }
453
- }
454
- checkValidity() {
455
- if (!this.$input) {
456
- return true;
457
- }
458
- if (this.$input.hasAttribute("readonly")) {
459
- return true;
460
- }
461
- if (this.$input.hasAttribute("[data-novalidate]")) {
462
- return true;
463
- }
464
- if (this.$input.closest("[data-novalidate]")) {
465
- return true;
466
- }
467
- if (this.hasChildDirectives()) {
468
- return true;
469
- }
470
- this.$input.setCustomValidity("");
471
- let valid = this.$input.checkValidity();
472
- if (valid && this.$form) {
473
- valid = this.runCustomValidity();
474
- }
475
- this.updateValidClass(valid);
476
- return valid;
477
- }
478
- runCustomValidity() {
479
- if (!this.$input) {
480
- return true;
481
- }
482
- const validates = (this.$input.getAttribute("data-validate") || "").split("|");
483
- let result = true;
484
- if (this.$input.value !== "" && validates.length) {
485
- if (!this.checkCustomDataAttributeValidity()) {
486
- return false;
487
- }
488
- for (const validatorName of validates) {
489
- const [validator, options] = this.getValidator(validatorName) || [null, {}];
490
- if (!validator) {
491
- continue;
492
- }
493
- Object.assign(options, validator.options);
494
- let r = validator.handler(this.$input.value, this.$input, options, this);
495
- if (r instanceof Promise || typeof r === "object" && r.then) {
496
- r.then((result2) => {
497
- this.handleAsyncCustomResult(result2, validator);
498
- });
499
- continue;
500
- }
501
- if (!this.handleCustomResult(r, validator)) {
502
- result = false;
503
- break;
504
- }
505
- }
506
- }
507
- return result;
508
- }
509
- async checkValidityAsync() {
510
- if (!this.$input) {
511
- return true;
512
- }
513
- if (this.$input.hasAttribute("readonly")) {
514
- return true;
515
- }
516
- if (this.$input.hasAttribute("[data-novalidate]")) {
517
- return true;
518
- }
519
- if (this.hasChildDirectives()) {
520
- return true;
521
- }
522
- this.$input.setCustomValidity("");
523
- let valid = this.$input.checkValidity();
524
- if (valid && this.$form) {
525
- valid = await this.runCustomValidityAsync();
526
- }
527
- this.updateValidClass(valid);
528
- return valid;
529
- }
530
- async runCustomValidityAsync() {
531
- if (!this.$input) {
532
- return true;
533
- }
534
- const validates = (this.$input.getAttribute("data-validate") || "").split("|");
535
- const results = [];
536
- const promises = [];
537
- if (this.$input.value !== "" && validates.length) {
538
- if (!this.checkCustomDataAttributeValidity()) {
539
- return false;
540
- }
541
- for (const validatorName of validates) {
542
- let [validator, options] = this.getValidator(validatorName) || [null, {}];
543
- if (!validator) {
544
- continue;
545
- }
546
- options = Object.assign({}, options, validator.options || {});
547
- promises.push(
548
- Promise.resolve(validator.handler(this.$input.value, this.$input, options, this)).then((r) => {
549
- results.push(this.handleAsyncCustomResult(r, validator));
550
- return r;
551
- })
552
- );
553
- }
554
- }
555
- await Promise.all(promises);
556
- for (const result of results) {
557
- if (result === false) {
558
- return false;
559
- }
560
- }
561
- return true;
562
- }
563
- checkCustomDataAttributeValidity() {
564
- const error2 = this.$input?.dataset.validationFail;
565
- return this.handleCustomResult(error2);
566
- }
567
- checkInputOptionsValidity() {
568
- if (!this.$input) {
569
- return true;
570
- }
571
- const isRequired = this.$input.getAttribute("required") != null;
572
- const optionWrappers = this.$input.querySelectorAll(this.mergedOptions.inputOptionsSelector);
573
- let result = true;
574
- if (isRequired) {
575
- for (const optionWrapper of optionWrappers) {
576
- const input = optionWrapper.querySelector("input");
577
- result = false;
578
- if (input?.checked) {
579
- result = true;
580
- break;
581
- }
582
- }
583
- }
584
- const n = document.createElement("input");
585
- n.required = isRequired;
586
- if (result) {
587
- n.value = "placeholder";
588
- }
589
- n.checkValidity();
590
- this.$input.validationMessage = n.validationMessage;
591
- this.$input.validity = n.validity;
592
- for (const optionWrapper of optionWrappers) {
593
- const input = optionWrapper.querySelector("input");
594
- input?.setCustomValidity(n.validationMessage);
595
- }
596
- if (!result) {
597
- this.$input.dispatchEvent(
598
- new CustomEvent("invalid")
599
- );
600
- }
601
- return result;
602
- }
603
- /**
604
- * @param valid {boolean}
605
- */
606
- updateValidClass(valid) {
607
- const $errorElement = this.getErrorElement();
608
- const $invalidTarget = $errorElement?.previousElementSibling;
609
- this.$input?.classList.remove(this.invalidClass);
610
- this.$input?.classList.remove(this.validClass);
611
- this.el.classList.remove(this.invalidClass);
612
- this.el.classList.remove(this.validClass);
613
- $invalidTarget?.classList.remove(this.invalidClass);
614
- $invalidTarget?.classList.remove(this.validClass);
615
- if (valid) {
616
- this.$input?.classList.add(this.validClass);
617
- this.el.classList.add(this.validClass);
618
- $invalidTarget?.classList.add(this.validClass);
619
- } else {
620
- this.$input?.classList.add(this.invalidClass);
621
- this.el.classList.add(this.invalidClass);
622
- $invalidTarget?.classList.add(this.invalidClass);
623
- }
624
- }
625
- getFormValidation(element) {
626
- return getBoundedInstance(element || this.getForm(), "form.validation");
627
- }
628
- get globalOptions() {
629
- return this.getFormValidation()?.options?.fieldDefaults ?? {};
630
- }
631
- getValidator(name) {
632
- const matches = name.match(/(?<type>[\w\-_]+)(\((?<params>.*)\))*/);
633
- if (!matches) {
634
- return null;
635
- }
636
- const validatorName = matches.groups?.type || "";
637
- const params = matches.groups?.params || "";
638
- const fv = this.getFormValidation(this.$form);
639
- const validator = fv?.validators[validatorName] || UnicornFormValidation.globalValidators[validatorName];
640
- if (!validator) {
641
- return null;
642
- }
643
- const paramMatches = params.matchAll(/(?<key>\w+)(\s?[=:]\s?(?<value>\w+))?/g);
644
- const options = {};
645
- for (const paramMatch of paramMatches) {
646
- const match = paramMatch?.groups;
647
- if (!match) {
648
- continue;
649
- }
650
- options[match.key] = handleParamValue(match.value);
651
- }
652
- return [validator, options];
653
- }
654
- handleCustomResult(result, validator) {
655
- if (typeof result === "string") {
656
- this.$input?.setCustomValidity(result);
657
- result = result === "";
658
- } else if (result === void 0) {
659
- result = true;
660
- }
661
- if (result) {
662
- this.$input?.setCustomValidity("");
663
- } else if (validator) {
664
- this.raiseCustomErrorState(validator);
665
- }
666
- return result;
667
- }
668
- handleAsyncCustomResult(result, validator) {
669
- result = this.handleCustomResult(result, validator);
670
- this.$input?.checkValidity();
671
- this.updateValidClass(result);
672
- return result;
673
- }
674
- raiseCustomErrorState(validator) {
675
- let help;
676
- if (this.$input?.validationMessage === "") {
677
- help = validator.options?.notice;
678
- if (typeof help === "function") {
679
- help = help(this.$input, this);
680
- }
681
- if (help != null) {
682
- this.$input?.setCustomValidity(help);
683
- }
684
- }
685
- if (this.$input?.validationMessage === "") {
686
- this.$input?.setCustomValidity(trans("unicorn.message.validation.custom.error"));
687
- }
688
- this.$input?.dispatchEvent(
689
- new CustomEvent("invalid")
690
- );
691
- }
692
- setAsInvalidAndReport(error2) {
693
- this.setCustomValidity(error2);
694
- this.showInvalidResponse();
695
- }
696
- setCustomValidity(error2) {
697
- this.$input?.setCustomValidity(error2);
698
- }
699
- reportValidity() {
700
- if (this.validationMessage !== "") {
701
- this.showInvalidResponse();
702
- }
703
- }
704
- showInvalidResponse() {
705
- if (this.hasChildDirectives()) {
706
- return;
707
- }
708
- const state = this.$input?.validity;
709
- let message = this.$input?.validationMessage || "";
710
- for (let key in state) {
711
- if (state[key] && this.$input?.dataset[key + "Message"]) {
712
- message = this.$input?.dataset[key + "Message"] || "";
713
- break;
714
- }
715
- }
716
- if (!this.isVisible) {
717
- let title = this.findLabel()?.textContent;
718
- if (!title) {
719
- title = this.$input?.name || "";
720
- }
721
- useUITheme().renderMessage(
722
- `Field: ${title} - ${message}`,
723
- "warning"
724
- );
725
- }
726
- let $help = this.getErrorElement();
727
- if (!$help) {
728
- $help = this.createHelpElement();
729
- this.el.appendChild($help);
730
- this.prepareWrapper();
731
- }
732
- $help.textContent = message;
733
- this.updateValidClass(false);
734
- }
735
- getErrorElement() {
736
- return this.el.querySelector(this.errorSelector);
737
- }
738
- createHelpElement() {
739
- const className = this.mergedOptions.errorMessageClass;
740
- const parsed = this.parseSelector(this.errorSelector || "");
741
- const $help = html(`<div class="${className}"></div>`);
742
- $help.classList.add(...parsed.classes);
743
- parsed.attrs.forEach((attr) => {
744
- $help.setAttribute(attr[0], attr[1] || "");
745
- });
746
- parsed.ids.forEach((id) => {
747
- $help.id = id;
748
- });
749
- return $help;
750
- }
751
- /**
752
- * @see https://stackoverflow.com/a/17888178
753
- */
754
- parseSelector(subselector) {
755
- const obj = { tags: [], classes: [], ids: [], attrs: [] };
756
- for (const token of subselector.split(/(?=\.)|(?=#)|(?=\[)/)) {
757
- switch (token[0]) {
758
- case "#":
759
- obj.ids.push(token.slice(1));
760
- break;
761
- case ".":
762
- obj.classes.push(token.slice(1));
763
- break;
764
- case "[":
765
- obj.attrs.push(token.slice(1, -1).split("="));
766
- break;
767
- default:
768
- obj.tags.push(token);
769
- break;
770
- }
771
- }
772
- return obj;
773
- }
774
- setAsValidAndClearResponse() {
775
- this.setCustomValidity("");
776
- this.updateValidClass(true);
777
- this.clearInvalidResponse();
778
- }
779
- clearInvalidResponse() {
780
- const $help = this.el.querySelector(this.errorSelector);
781
- $help.textContent = "";
782
- }
783
- getForm() {
784
- return this.el.closest(this.options.formSelector || "[uni-form-validate]");
785
- }
786
- findLabel() {
787
- const id = this.$input?.id || "";
788
- const wrapper = this.$input?.closest("[data-field-wrapper]");
789
- let label = null;
790
- if (wrapper) {
791
- label = wrapper.querySelector("[data-field-label]");
792
- }
793
- if (!label) {
794
- label = document.querySelector(`label[for="${id}"]`);
795
- }
796
- return label;
797
- }
798
- hasChildDirectives() {
799
- return this.el.querySelector("[uni-field-validate]") != null;
800
- }
801
- }
802
734
  validatorHandlers.username = function(value, element) {
803
- const regex = new RegExp(`[<|>|"|'|%|;|(|)|&]`, "i");
804
- return !regex.test(value);
735
+ return !(/* @__PURE__ */ new RegExp("[<|>|\"|'|%|;|(|)|&]", "i")).test(value);
805
736
  };
806
737
  validatorHandlers.numeric = function(value, element) {
807
- const regex = /^(\d|-)?(\d|,)*\.?\d*$/;
808
- return regex.test(value);
738
+ return /^(\d|-)?(\d|,)*\.?\d*$/.test(value);
809
739
  };
810
740
  validatorHandlers.email = function(value, element) {
811
- value = toASCII(value);
812
- const regex = /^[a-zA-Z0-9.!#$%&’*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
813
- return regex.test(value);
741
+ value = toASCII(value);
742
+ return /^[a-zA-Z0-9.!#$%&’*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(value);
814
743
  };
815
744
  validatorHandlers.url = function(value, element) {
816
- const regex = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i;
817
- return regex.test(value);
745
+ return /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i.test(value);
818
746
  };
819
747
  validatorHandlers.alnum = function(value, element) {
820
- const regex = /^[a-zA-Z0-9]*$/;
821
- return regex.test(value);
748
+ return /^[a-zA-Z0-9]*$/.test(value);
822
749
  };
823
750
  validatorHandlers.color = function(value, element) {
824
- const regex = /^#(?:[0-9a-f]{3}){1,2}$/;
825
- return regex.test(value);
751
+ return /^#(?:[0-9a-f]{3}){1,2}$/.test(value);
826
752
  };
753
+ /**
754
+ * @see http://www.virtuosimedia.com/dev/php/37-tested-php-perl-and-javascript-regular-expressions
755
+ */
827
756
  validatorHandlers.creditcard = function(value, element) {
828
- const regex = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6011[0-9]{12}|622((12[6-9]|1[3-9][0-9])|([2-8][0-9][0-9])|(9(([0-1][0-9])|(2[0-5]))))[0-9]{10}|64[4-9][0-9]{13}|65[0-9]{14}|3(?:0[0-5]|[68][0-9])[0-9]{11}|3[47][0-9]{13})*$/;
829
- return regex.test(value);
757
+ return /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6011[0-9]{12}|622((12[6-9]|1[3-9][0-9])|([2-8][0-9][0-9])|(9(([0-1][0-9])|(2[0-5]))))[0-9]{10}|64[4-9][0-9]{13}|65[0-9]{14}|3(?:0[0-5]|[68][0-9])[0-9]{11}|3[47][0-9]{13})*$/.test(value);
830
758
  };
831
759
  validatorHandlers.ip = function(value, element) {
832
- const regex = /^((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))*$/;
833
- return regex.test(value);
760
+ return /^((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))*$/.test(value);
834
761
  };
835
762
  validatorHandlers["password-confirm"] = function(value, element) {
836
- const selector = element.dataset.confirmTarget;
837
- if (!selector) {
838
- throw new Error('Validator: "password-confirm" must add "data-confirm-target" attribute.');
839
- }
840
- const target = document.querySelector(selector);
841
- return target?.value === value;
763
+ const selector = element.dataset.confirmTarget;
764
+ if (!selector) throw new Error("Validator: \"password-confirm\" must add \"data-confirm-target\" attribute.");
765
+ return document.querySelector(selector)?.value === value;
842
766
  };
843
- const ready = /* @__PURE__ */ Promise.all([
844
- /* @__PURE__ */ useUniDirective("form-validate", {
845
- mounted(el, binding) {
846
- getBoundedInstance(el, "form.validation", (ele) => {
847
- return new UnicornFormValidation(ele, JSON.parse(binding.value || "{}"));
848
- });
849
- },
850
- updated(el, binding) {
851
- const instance = getBoundedInstance(el, "form.validation");
852
- instance.mergeOptions(JSON.parse(binding.value || "{}"));
853
- }
854
- }),
855
- /* @__PURE__ */ useUniDirective("field-validate", {
856
- mounted(el, binding) {
857
- getBoundedInstance(el, "field.validation", (ele) => {
858
- return new UnicornFieldValidation(ele, JSON.parse(binding.value || "{}"));
859
- });
860
- },
861
- updated(el, binding) {
862
- const instance = getBoundedInstance(el, "field.validation");
863
- instance.setOptions(JSON.parse(binding.value || "{}") || {});
864
- }
865
- })
866
- ]);
767
+ var ready = /* @__PURE__ */ Promise.all([/* @__PURE__ */ useUniDirective("form-validate", {
768
+ mounted(el, binding) {
769
+ getBoundedInstance(el, "form.validation", (ele) => {
770
+ return new UnicornFormValidation(ele, JSON.parse(binding.value || "{}"));
771
+ });
772
+ },
773
+ updated(el, binding) {
774
+ getBoundedInstance(el, "form.validation").mergeOptions(JSON.parse(binding.value || "{}"));
775
+ }
776
+ }), /* @__PURE__ */ useUniDirective("field-validate", {
777
+ mounted(el, binding) {
778
+ getBoundedInstance(el, "field.validation", (ele) => {
779
+ return new UnicornFieldValidation(ele, JSON.parse(binding.value || "{}"));
780
+ });
781
+ },
782
+ updated(el, binding) {
783
+ getBoundedInstance(el, "field.validation").setOptions(JSON.parse(binding.value || "{}") || {});
784
+ }
785
+ })]);
867
786
  function handleParamValue(value) {
868
- if (!isNaN(Number(value))) {
869
- return Number(value);
870
- }
871
- if (value === "null") {
872
- return null;
873
- }
874
- if (value === "true") {
875
- return true;
876
- }
877
- if (value === "false") {
878
- return true;
879
- }
880
- return value;
787
+ if (!isNaN(Number(value))) return Number(value);
788
+ if (value === "null") return null;
789
+ if (value === "true") return true;
790
+ if (value === "false") return true;
791
+ return value;
881
792
  }
882
- export {
883
- UnicornFieldValidation,
884
- UnicornFormValidation,
885
- ready,
886
- validatorHandlers as validators
887
- };
888
- //# sourceMappingURL=validation.js.map
793
+ //#endregion
794
+ export { UnicornFieldValidation, UnicornFormValidation, ready, validatorHandlers as validators };
795
+
796
+ //# sourceMappingURL=validation.js.map