@schukai/monster 4.46.2 → 4.46.4
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.
- package/CHANGELOG.md +16 -0
- package/package.json +1 -1
- package/source/components/form/quantity.mjs +236 -229
- package/source/dom/util/init-options-from-attributes.mjs +56 -53
- package/source/types/is.mjs +82 -64
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
## [4.46.4] - 2025-11-19
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Fix option parsing: correctly convert numeric attributes when default is Infinity
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## [4.46.3] - 2025-11-19
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
- **quantity:** max boundary
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
5
21
|
## [4.46.2] - 2025-11-19
|
|
6
22
|
|
|
7
23
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.46.
|
|
1
|
+
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.46.4"}
|
|
@@ -14,8 +14,8 @@ import { instanceSymbol } from "../../constants.mjs";
|
|
|
14
14
|
import { ATTRIBUTE_ROLE } from "../../dom/constants.mjs";
|
|
15
15
|
import { CustomControl } from "../../dom/customcontrol.mjs";
|
|
16
16
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
assembleMethodSymbol,
|
|
18
|
+
registerCustomElement,
|
|
19
19
|
} from "../../dom/customelement.mjs";
|
|
20
20
|
import { fireCustomEvent } from "../../dom/events.mjs";
|
|
21
21
|
|
|
@@ -61,100 +61,105 @@ const holdIntervalSymbol = Symbol("holdInterval");
|
|
|
61
61
|
* @fires monster-quantity-change
|
|
62
62
|
*/
|
|
63
63
|
class Quantity extends CustomControl {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
64
|
+
static get [instanceSymbol]() {
|
|
65
|
+
return Symbol.for("@schukai/monster/components/form/quantity@@instance");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
[assembleMethodSymbol]() {
|
|
69
|
+
super[assembleMethodSymbol]();
|
|
70
|
+
|
|
71
|
+
initControlReferences.call(this);
|
|
72
|
+
initEventHandler.call(this);
|
|
73
|
+
applyEditableState.call(this);
|
|
74
|
+
clampAndRender.call(this, this.getOption("value"));
|
|
75
|
+
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Current numeric value
|
|
81
|
+
* @return {number|null}
|
|
82
|
+
*/
|
|
83
|
+
get value() {
|
|
84
|
+
return this.getOption("value");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Sets the value programmatically (including clamping & FormValue)
|
|
89
|
+
* @param {number|string|null} v
|
|
90
|
+
*/
|
|
91
|
+
set value(v) {
|
|
92
|
+
const n = normalizeNumber(v, this.getOption("precision"));
|
|
93
|
+
clampAndRender.call(this, n);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Options
|
|
98
|
+
*
|
|
99
|
+
* @property {Object} templates
|
|
100
|
+
* @property {string} templates.main Main template
|
|
101
|
+
* @property {Object} templateMapping
|
|
102
|
+
* @property {string} templateMapping.plus Icon (SVG-Path) Plus
|
|
103
|
+
* @property {string} templateMapping.minus Icon (SVG-Path) Minus
|
|
104
|
+
* @property {Object} classes CSS classes
|
|
105
|
+
* @property {string} classes.button Button class (e.g. monster-button-outline-primary)
|
|
106
|
+
* @property {string} classes.input Additional class for input
|
|
107
|
+
* @property {Object} features Feature toggles
|
|
108
|
+
* @property {boolean} features.editable Allow manual input
|
|
109
|
+
* @property {boolean} features.hold Press-and-hold accelerates
|
|
110
|
+
* @property {boolean} features.enforceBounds Clamp value when manual input is out of bounds
|
|
111
|
+
* @property {number} value Current value
|
|
112
|
+
* @property {number} min Use Number.NEGATIVE_INFINITY and Number.POSITIVE_INFINITY for no bounds
|
|
113
|
+
* @property {number} max Use Number.NEGATIVE_INFINITY and Number.POSITIVE_INFINITY for no bounds
|
|
114
|
+
* @property {number} step Increment/decrement step
|
|
115
|
+
* @property {number} precision Round to N decimal places (null = no explicit rounding)
|
|
116
|
+
* @property {boolean} disabled Disable the input field (also disables manual input)
|
|
117
|
+
* @property {string} placeholder Placeholder text
|
|
118
|
+
* @property {string} inputmode For mobile keyboards
|
|
119
|
+
*/
|
|
120
|
+
get defaults() {
|
|
121
|
+
return Object.assign({}, super.defaults, {
|
|
122
|
+
templates: { main: getTemplate() },
|
|
123
|
+
templateMapping: {
|
|
124
|
+
plus: `
|
|
125
125
|
<path d="M8 1a1 1 0 0 1 1 1v5h5a1 1 0 1 1 0 2H9v5a1 1 0 1 1-2 0V9H2a1 1 0 1 1 0-2h5V2a1 1 0 0 1 1-1z"/>`,
|
|
126
|
-
|
|
126
|
+
minus: `
|
|
127
127
|
<path d="M2 7.5a1 1 0 0 0 0 1H14a1 1 0 1 0 0-2H2a1 1 0 0 0 0 1z"/>`,
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
128
|
+
},
|
|
129
|
+
classes: {
|
|
130
|
+
button: "monster-button-outline-primary",
|
|
131
|
+
input: "",
|
|
132
|
+
},
|
|
133
|
+
features: {
|
|
134
|
+
editable: true,
|
|
135
|
+
hold: true,
|
|
136
|
+
enforceBounds: true,
|
|
137
|
+
},
|
|
138
|
+
value: 0,
|
|
139
|
+
min: 0,
|
|
140
|
+
max: Number.POSITIVE_INFINITY,
|
|
141
|
+
step: 1,
|
|
142
|
+
precision: null,
|
|
143
|
+
|
|
144
|
+
disabled: false,
|
|
145
|
+
placeholder: "",
|
|
146
|
+
inputmode: "decimal",
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
static getTag() {
|
|
151
|
+
return "monster-quantity";
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// If you want a stylesheet, return it here.
|
|
155
|
+
static getCSSStyleSheet() {
|
|
156
|
+
return [QuantityStyleSheet];
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function getFiniteNumberOr(optionValue, fallback) {
|
|
161
|
+
const n = Number(optionValue);
|
|
162
|
+
return Number.isFinite(n) ? n : fallback;
|
|
158
163
|
}
|
|
159
164
|
|
|
160
165
|
/**
|
|
@@ -164,18 +169,18 @@ class Quantity extends CustomControl {
|
|
|
164
169
|
* @return {void}
|
|
165
170
|
*/
|
|
166
171
|
function initControlReferences() {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
172
|
+
this[controlElementSymbol] = this.shadowRoot.querySelector(
|
|
173
|
+
`[${ATTRIBUTE_ROLE}="control"]`,
|
|
174
|
+
);
|
|
175
|
+
this[decrementButtonSymbol] = this.shadowRoot.querySelector(
|
|
176
|
+
`[${ATTRIBUTE_ROLE}="decrement"]`,
|
|
177
|
+
);
|
|
178
|
+
this[incrementButtonSymbol] = this.shadowRoot.querySelector(
|
|
179
|
+
`[${ATTRIBUTE_ROLE}="increment"]`,
|
|
180
|
+
);
|
|
181
|
+
this[inputElementSymbol] = this.shadowRoot.querySelector(
|
|
182
|
+
`[${ATTRIBUTE_ROLE}="input"]`,
|
|
183
|
+
);
|
|
179
184
|
}
|
|
180
185
|
|
|
181
186
|
/**
|
|
@@ -185,150 +190,152 @@ function initControlReferences() {
|
|
|
185
190
|
* @return {void}
|
|
186
191
|
*/
|
|
187
192
|
function initEventHandler() {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
193
|
+
const stepOnce = (dir) => {
|
|
194
|
+
const step = Number(this.getOption("step")) || 1;
|
|
195
|
+
const cur = toNumberOr(this.value, 0);
|
|
196
|
+
const next = cur + (dir > 0 ? step : -step);
|
|
197
|
+
clampAndRender.call(this, next, {
|
|
198
|
+
fire: true,
|
|
199
|
+
kind: dir > 0 ? "increment" : "decrement",
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const startHold = (dir) => {
|
|
204
|
+
if (!this.getOption("features.hold")) return;
|
|
205
|
+
clearTimeout(this[holdTimerSymbol]);
|
|
206
|
+
clearInterval(this[holdIntervalSymbol]);
|
|
207
|
+
|
|
208
|
+
// After a short delay, repeat faster
|
|
209
|
+
this[holdTimerSymbol] = setTimeout(() => {
|
|
210
|
+
this[holdIntervalSymbol] = setInterval(() => stepOnce(dir), 60);
|
|
211
|
+
}, 300);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const stopHold = () => {
|
|
215
|
+
clearTimeout(this[holdTimerSymbol]);
|
|
216
|
+
clearInterval(this[holdIntervalSymbol]);
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// Buttons
|
|
220
|
+
this[decrementButtonSymbol].addEventListener("click", (e) => stepOnce(-1));
|
|
221
|
+
this[incrementButtonSymbol].addEventListener("click", (e) => stepOnce(1));
|
|
222
|
+
|
|
223
|
+
// Press & hold (Mouse/Touch)
|
|
224
|
+
["mousedown", "pointerdown", "touchstart"].forEach((ev) => {
|
|
225
|
+
this[decrementButtonSymbol].addEventListener(ev, () => startHold(-1));
|
|
226
|
+
this[incrementButtonSymbol].addEventListener(ev, () => startHold(1));
|
|
227
|
+
});
|
|
228
|
+
["mouseup", "mouseleave", "pointerup", "touchend", "touchcancel"].forEach(
|
|
229
|
+
(ev) => {
|
|
230
|
+
this[decrementButtonSymbol].addEventListener(ev, stopHold);
|
|
231
|
+
this[incrementButtonSymbol].addEventListener(ev, stopHold);
|
|
232
|
+
},
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
// Keyboard on input
|
|
236
|
+
this[inputElementSymbol].addEventListener("keydown", (e) => {
|
|
237
|
+
if (e.key === "ArrowUp") {
|
|
238
|
+
e.preventDefault();
|
|
239
|
+
stepOnce(1);
|
|
240
|
+
} else if (e.key === "ArrowDown") {
|
|
241
|
+
e.preventDefault();
|
|
242
|
+
stepOnce(-1);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Manual input
|
|
247
|
+
this[inputElementSymbol].addEventListener("input", () => {
|
|
248
|
+
if (!this.getOption("features.editable")) return;
|
|
249
|
+
// Only store temporarily, clamp on blur/enter – but update FormValue immediately
|
|
250
|
+
const raw = this[inputElementSymbol].value;
|
|
251
|
+
const n = normalizeNumber(raw, this.getOption("precision"));
|
|
252
|
+
this.setOption("value", n);
|
|
253
|
+
this.setFormValue(n);
|
|
254
|
+
fireChanged.call(this, "input");
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
this[inputElementSymbol].addEventListener("blur", () => {
|
|
258
|
+
if (!this.getOption("features.editable")) return;
|
|
259
|
+
const n = normalizeNumber(
|
|
260
|
+
this[inputElementSymbol].value,
|
|
261
|
+
this.getOption("precision"),
|
|
262
|
+
);
|
|
263
|
+
clampAndRender.call(this, n, { fire: true, kind: "blur" });
|
|
264
|
+
});
|
|
260
265
|
}
|
|
261
266
|
|
|
262
267
|
function applyEditableState() {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
268
|
+
const editable = !!this.getOption("features.editable");
|
|
269
|
+
this[inputElementSymbol].toggleAttribute("readonly", !editable);
|
|
270
|
+
this[inputElementSymbol].toggleAttribute(
|
|
271
|
+
"disabled",
|
|
272
|
+
!!this.getOption("disabled"),
|
|
273
|
+
);
|
|
269
274
|
}
|
|
270
275
|
|
|
271
276
|
function clampAndRender(n, opts = {}) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
277
|
+
const min = getFiniteNumberOr(
|
|
278
|
+
this.getOption("min"),
|
|
279
|
+
Number.NEGATIVE_INFINITY,
|
|
280
|
+
);
|
|
281
|
+
const max = getFiniteNumberOr(
|
|
282
|
+
this.getOption("max"),
|
|
283
|
+
Number.POSITIVE_INFINITY,
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
let value = n;
|
|
287
|
+
if (this.getOption("features.enforceBounds")) {
|
|
288
|
+
value = Math.min(max, Math.max(min, toNumberOr(n, 0)));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Precision
|
|
292
|
+
const p = this.getOption("precision");
|
|
293
|
+
if (Number.isInteger(p) && p >= 0) {
|
|
294
|
+
value = Number(toFixedSafe(value, p));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Render into input
|
|
298
|
+
this[inputElementSymbol].value =
|
|
299
|
+
value === null || Number.isNaN(value) ? "" : String(value);
|
|
300
|
+
|
|
301
|
+
// Options + FormValue
|
|
302
|
+
this.setOption("value", value);
|
|
303
|
+
this.setFormValue(value);
|
|
304
|
+
|
|
305
|
+
if (opts.fire) fireChanged.call(this, opts.kind || "programmatic");
|
|
299
306
|
}
|
|
300
307
|
|
|
301
308
|
function fireChanged(kind) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
309
|
+
fireCustomEvent(this, "monster-quantity-change", {
|
|
310
|
+
element: this,
|
|
311
|
+
value: this.value,
|
|
312
|
+
kind, // 'increment' | 'decrement' | 'input' | 'blur' | 'programmatic'
|
|
313
|
+
});
|
|
307
314
|
}
|
|
308
315
|
|
|
309
316
|
function normalizeNumber(v, precision) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
+
if (v === null || v === undefined || v === "") return null;
|
|
318
|
+
let n = Number(v);
|
|
319
|
+
if (!Number.isFinite(n)) return null;
|
|
320
|
+
if (Number.isInteger(precision) && precision >= 0) {
|
|
321
|
+
n = Number(toFixedSafe(n, precision));
|
|
322
|
+
}
|
|
323
|
+
return n;
|
|
317
324
|
}
|
|
318
325
|
|
|
319
326
|
function toNumberOr(v, dflt) {
|
|
320
|
-
|
|
321
|
-
|
|
327
|
+
const n = Number(v);
|
|
328
|
+
return Number.isFinite(n) ? n : dflt;
|
|
322
329
|
}
|
|
323
330
|
|
|
324
331
|
function toFixedSafe(n, p) {
|
|
325
|
-
|
|
326
|
-
|
|
332
|
+
// Prevents 1.00000000000002 effects
|
|
333
|
+
return (Math.round(n * Math.pow(10, p)) / Math.pow(10, p)).toFixed(p);
|
|
327
334
|
}
|
|
328
335
|
|
|
329
336
|
function getTemplate() {
|
|
330
|
-
|
|
331
|
-
|
|
337
|
+
// language=HTML
|
|
338
|
+
return `
|
|
332
339
|
<div data-monster-role="control" part="control">
|
|
333
340
|
<monster-input-group part="input-group">
|
|
334
341
|
<button type="button"
|
|
@@ -14,12 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
import { Pathfinder } from "../../data/pathfinder.mjs";
|
|
16
16
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
isBoolean,
|
|
18
|
+
isString,
|
|
19
|
+
isObject,
|
|
20
|
+
isNumber,
|
|
21
|
+
isArray,
|
|
22
|
+
isFunction,
|
|
23
|
+
isInteger,
|
|
23
24
|
} from "../../types/is.mjs";
|
|
24
25
|
import { extractKeys } from "./extract-keys.mjs";
|
|
25
26
|
|
|
@@ -58,60 +59,62 @@ export { initOptionsFromAttributes };
|
|
|
58
59
|
* @this HTMLElement - The context of the DOM element.
|
|
59
60
|
*/
|
|
60
61
|
function initOptionsFromAttributes(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
element,
|
|
63
|
+
options,
|
|
64
|
+
mapping = {},
|
|
65
|
+
prefix = "data-monster-option-",
|
|
65
66
|
) {
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
if (!(element instanceof HTMLElement)) return options;
|
|
68
|
+
if (!element.hasAttributes()) return options;
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
const keyMap = extractKeys(options);
|
|
71
|
+
const finder = new Pathfinder(options);
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
element.getAttributeNames().forEach((name) => {
|
|
74
|
+
if (!name.startsWith(prefix)) return;
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
// check if the attribute name is a valid option.
|
|
77
|
+
// the mapping between the attribute is simple. The dash is replaced by a dot.
|
|
78
|
+
// e.g. data-monster-url => url
|
|
79
|
+
const optionName = keyMap.get(name.substring(prefix.length).toLowerCase());
|
|
80
|
+
if (!finder.exists(optionName)) return;
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
if (element.hasAttribute(name)) {
|
|
83
|
+
let value = element.getAttribute(name);
|
|
84
|
+
if (
|
|
85
|
+
mapping.hasOwnProperty(optionName) &&
|
|
86
|
+
isFunction(mapping[optionName])
|
|
87
|
+
) {
|
|
88
|
+
value = mapping[optionName](value);
|
|
89
|
+
}
|
|
89
90
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
let optionValue = finder.getVia(optionName);
|
|
92
|
+
if (optionValue === null || optionValue === undefined) {
|
|
93
|
+
optionValue = value;
|
|
94
|
+
}
|
|
94
95
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
96
|
+
//const typeOfOptionValue = typeof optionValue;
|
|
97
|
+
if (optionValue === null || optionValue === undefined) {
|
|
98
|
+
value = null;
|
|
99
|
+
} else if (isBoolean(optionValue)) {
|
|
100
|
+
value = value === "true";
|
|
101
|
+
} else if (isInteger(optionValue)) {
|
|
102
|
+
value = Number(value);
|
|
103
|
+
} else if (isNumber(optionValue)) {
|
|
104
|
+
value = Number(value);
|
|
105
|
+
} else if (isString(optionValue)) {
|
|
106
|
+
value = String(value);
|
|
107
|
+
} else if (isObject(optionValue)) {
|
|
108
|
+
value = JSON.parse(value);
|
|
109
|
+
} else if (isArray(optionValue)) {
|
|
110
|
+
value = value.split("::");
|
|
111
|
+
} else {
|
|
112
|
+
value = optionValue;
|
|
113
|
+
}
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
finder.setVia(optionName, value);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
115
118
|
|
|
116
|
-
|
|
119
|
+
return options;
|
|
117
120
|
}
|
package/source/types/is.mjs
CHANGED
|
@@ -15,18 +15,19 @@
|
|
|
15
15
|
import { proxyInstanceMarker } from "../constants.mjs";
|
|
16
16
|
|
|
17
17
|
export {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
isIterable,
|
|
19
|
+
isPrimitive,
|
|
20
|
+
isSymbol,
|
|
21
|
+
isBoolean,
|
|
22
|
+
isString,
|
|
23
|
+
isObject,
|
|
24
|
+
isInstance,
|
|
25
|
+
isArray,
|
|
26
|
+
isFunction,
|
|
27
|
+
isInteger,
|
|
28
|
+
isNumber,
|
|
29
|
+
isProxy,
|
|
30
|
+
isElement,
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
/**
|
|
@@ -35,7 +36,7 @@ export {
|
|
|
35
36
|
* @returns {boolean}
|
|
36
37
|
*/
|
|
37
38
|
function isElement(value) {
|
|
38
|
-
|
|
39
|
+
return value instanceof Element;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
/**
|
|
@@ -45,7 +46,7 @@ function isElement(value) {
|
|
|
45
46
|
* @returns {boolean}
|
|
46
47
|
*/
|
|
47
48
|
function isProxy(value) {
|
|
48
|
-
|
|
49
|
+
return value?.[proxyInstanceMarker] === proxyInstanceMarker;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
/**
|
|
@@ -63,9 +64,9 @@ function isProxy(value) {
|
|
|
63
64
|
* @copyright schukai GmbH
|
|
64
65
|
*/
|
|
65
66
|
function isIterable(value) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
if (value === undefined) return false;
|
|
68
|
+
if (value === null) return false;
|
|
69
|
+
return typeof value?.[Symbol.iterator] === "function";
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
/**
|
|
@@ -81,24 +82,24 @@ function isIterable(value) {
|
|
|
81
82
|
* @copyright schukai GmbH
|
|
82
83
|
*/
|
|
83
84
|
function isPrimitive(value) {
|
|
84
|
-
|
|
85
|
+
var type;
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
if (value === undefined || value === null) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
89
90
|
|
|
90
|
-
|
|
91
|
+
type = typeof value;
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
if (
|
|
94
|
+
type === "string" ||
|
|
95
|
+
type === "number" ||
|
|
96
|
+
type === "boolean" ||
|
|
97
|
+
type === "symbol"
|
|
98
|
+
) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
100
101
|
|
|
101
|
-
|
|
102
|
+
return false;
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
/**
|
|
@@ -114,7 +115,7 @@ function isPrimitive(value) {
|
|
|
114
115
|
* @copyright schukai GmbH
|
|
115
116
|
*/
|
|
116
117
|
function isSymbol(value) {
|
|
117
|
-
|
|
118
|
+
return "symbol" === typeof value ? true : false;
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
/**
|
|
@@ -130,11 +131,11 @@ function isSymbol(value) {
|
|
|
130
131
|
* @copyright schukai GmbH
|
|
131
132
|
*/
|
|
132
133
|
function isBoolean(value) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
if (value === true || value === false) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
136
137
|
|
|
137
|
-
|
|
138
|
+
return false;
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
/**
|
|
@@ -150,10 +151,10 @@ function isBoolean(value) {
|
|
|
150
151
|
* @copyright schukai GmbH
|
|
151
152
|
*/
|
|
152
153
|
function isString(value) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
154
|
+
if (value === undefined || typeof value !== "string") {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
157
158
|
}
|
|
158
159
|
|
|
159
160
|
/**
|
|
@@ -169,14 +170,14 @@ function isString(value) {
|
|
|
169
170
|
* @copyright schukai GmbH
|
|
170
171
|
*/
|
|
171
172
|
function isObject(value) {
|
|
172
|
-
|
|
173
|
-
|
|
173
|
+
if (isArray(value)) return false;
|
|
174
|
+
if (isPrimitive(value)) return false;
|
|
174
175
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
if (typeof value === "object") {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
178
179
|
|
|
179
|
-
|
|
180
|
+
return false;
|
|
180
181
|
}
|
|
181
182
|
|
|
182
183
|
/**
|
|
@@ -193,18 +194,18 @@ function isObject(value) {
|
|
|
193
194
|
* @copyright schukai GmbH
|
|
194
195
|
*/
|
|
195
196
|
function isInstance(value, instance) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
197
|
+
if (!isObject(value)) return false;
|
|
198
|
+
if (!isFunction(instance)) return false;
|
|
199
|
+
if (!instance.hasOwnProperty("prototype")) return false;
|
|
200
|
+
if (value instanceof instance) return true;
|
|
200
201
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
202
|
+
let proto = Object.getPrototypeOf(value);
|
|
203
|
+
while (proto != null) {
|
|
204
|
+
if (proto === instance.prototype) return true;
|
|
205
|
+
proto = Object.getPrototypeOf(proto);
|
|
206
|
+
}
|
|
206
207
|
|
|
207
|
-
|
|
208
|
+
return false;
|
|
208
209
|
}
|
|
209
210
|
|
|
210
211
|
/**
|
|
@@ -221,7 +222,7 @@ function isInstance(value, instance) {
|
|
|
221
222
|
* @see https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
|
|
222
223
|
*/
|
|
223
224
|
function isArray(value) {
|
|
224
|
-
|
|
225
|
+
return Array.isArray(value);
|
|
225
226
|
}
|
|
226
227
|
|
|
227
228
|
/**
|
|
@@ -237,14 +238,31 @@ function isArray(value) {
|
|
|
237
238
|
* @copyright schukai GmbH
|
|
238
239
|
*/
|
|
239
240
|
function isFunction(value) {
|
|
240
|
-
|
|
241
|
-
|
|
241
|
+
if (isArray(value)) return false;
|
|
242
|
+
if (isPrimitive(value)) return false;
|
|
242
243
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
if (typeof value === "function") {
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
246
247
|
|
|
247
|
-
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Cechs whether the value passed is a number.
|
|
253
|
+
*
|
|
254
|
+
* This method is used in the library to have consistent names.
|
|
255
|
+
*
|
|
256
|
+
* @externalExample ../../example/types/is-number.mjs
|
|
257
|
+
*
|
|
258
|
+
* @param {*} value
|
|
259
|
+
* @return {boolean}
|
|
260
|
+
*
|
|
261
|
+
* @license AGPLv3
|
|
262
|
+
* @since 4.47.0
|
|
263
|
+
*/
|
|
264
|
+
function isNumber(value) {
|
|
265
|
+
return typeof value === "number" && !isNaN(value);
|
|
248
266
|
}
|
|
249
267
|
|
|
250
268
|
/**
|
|
@@ -260,5 +278,5 @@ function isFunction(value) {
|
|
|
260
278
|
* @copyright schukai GmbH
|
|
261
279
|
*/
|
|
262
280
|
function isInteger(value) {
|
|
263
|
-
|
|
281
|
+
return Number.isInteger(value);
|
|
264
282
|
}
|