webspresso 0.0.109 → 0.0.111
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/core/client/adapter/datastar.js +248 -51
- package/core/client/api.js +328 -22
- package/core/client/controller.js +921 -38
- package/core/client/debug.js +12 -12
- package/core/client/devtool.js +1239 -0
- package/core/client/forms.js +184 -21
- package/core/client/fragments.js +566 -72
- package/core/client/host.js +365 -0
- package/core/client/index.d.ts +37 -0
- package/core/client/index.js +190 -15
- package/core/client/lite.js +112 -4
- package/core/client/server-fragments.js +111 -24
- package/core/client/services.js +588 -0
- package/core/client/storage.js +339 -0
- package/core/client/utils.js +324 -1
- package/core/index.js +4 -0
- package/index.d.ts +523 -39
- package/index.js +7 -0
- package/package.json +7 -8
- package/src/bundle/index.js +175 -14
- package/src/client-runtime/bootstrap-swup.js +9 -0
- package/src/client-runtime/mount.js +6 -18
- package/src/client-runtime/resolve.js +3 -2
- package/src/dev/banner.js +4 -1
- package/src/dev-reload/index.js +29 -1
- package/src/file-router.js +12 -8
- package/src/routing/mount-discovered-routes.js +9 -2
- package/src/server.js +42 -24
- package/views/partials/webspresso-client-runtime.njk +1 -9
- package/src/client-runtime/bootstrap-alpine-swup.js +0 -34
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* external package is not installed in `node_modules`.
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
const { getByPath, setByPath } = require('../utils');
|
|
27
|
+
const { isArray, getByPath, setByPath } = require('../utils');
|
|
28
28
|
|
|
29
29
|
const PluginType = {
|
|
30
30
|
Attribute: 1,
|
|
@@ -124,6 +124,16 @@ function createSignalsEngine() {
|
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
function untracked(fn) {
|
|
128
|
+
const prev = activeEffect;
|
|
129
|
+
activeEffect = null;
|
|
130
|
+
try {
|
|
131
|
+
return fn();
|
|
132
|
+
} finally {
|
|
133
|
+
activeEffect = prev;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
127
137
|
/**
|
|
128
138
|
* Implements Datastar's public `SignalsRoot` contract:
|
|
129
139
|
* exists(path), signal(path), value(path), setValue(path, val),
|
|
@@ -213,6 +223,7 @@ function createSignalsEngine() {
|
|
|
213
223
|
return {
|
|
214
224
|
signals: new CompatibleSignalsRoot(),
|
|
215
225
|
effect,
|
|
226
|
+
untracked,
|
|
216
227
|
};
|
|
217
228
|
}
|
|
218
229
|
|
|
@@ -238,6 +249,123 @@ function resolveOperand(state, token) {
|
|
|
238
249
|
return getByPath(state, t);
|
|
239
250
|
}
|
|
240
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Safely strips balanced enclosing parentheses if the entire expression is wrapped in them:
|
|
254
|
+
* e.g. `(a && b)` -> `a && b`, but `(a && b) || (c && d)` is left unchanged.
|
|
255
|
+
*
|
|
256
|
+
* @param {string} raw
|
|
257
|
+
* @returns {string}
|
|
258
|
+
*/
|
|
259
|
+
function stripOuterParens(raw) {
|
|
260
|
+
let s = raw.trim();
|
|
261
|
+
while (s.startsWith('(') && s.endsWith(')')) {
|
|
262
|
+
let depth = 0;
|
|
263
|
+
let matched = true;
|
|
264
|
+
for (let i = 0; i < s.length - 1; i++) {
|
|
265
|
+
const ch = s[i];
|
|
266
|
+
if (ch === '(') depth++;
|
|
267
|
+
else if (ch === ')') {
|
|
268
|
+
depth--;
|
|
269
|
+
if (depth === 0) {
|
|
270
|
+
matched = false;
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (matched) {
|
|
276
|
+
s = s.slice(1, -1).trim();
|
|
277
|
+
} else {
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return s;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Split an expression by an operator (e.g. '||', '&&') only at the top level
|
|
286
|
+
* (outside single/double quotes and outside balanced parentheses).
|
|
287
|
+
*
|
|
288
|
+
* @param {string} expr
|
|
289
|
+
* @param {string} op
|
|
290
|
+
* @returns {string[]|null}
|
|
291
|
+
*/
|
|
292
|
+
function splitTopLevel(expr, op) {
|
|
293
|
+
const parts = [];
|
|
294
|
+
let inSingleQuote = false;
|
|
295
|
+
let inDoubleQuote = false;
|
|
296
|
+
let depth = 0;
|
|
297
|
+
let lastIndex = 0;
|
|
298
|
+
const opLen = op.length;
|
|
299
|
+
const len = expr.length;
|
|
300
|
+
|
|
301
|
+
for (let i = 0; i < len; i++) {
|
|
302
|
+
const ch = expr[i];
|
|
303
|
+
const prev = i > 0 ? expr[i - 1] : '';
|
|
304
|
+
|
|
305
|
+
if (ch === "'" && !inDoubleQuote && prev !== '\\') {
|
|
306
|
+
inSingleQuote = !inSingleQuote;
|
|
307
|
+
} else if (ch === '"' && !inSingleQuote && prev !== '\\') {
|
|
308
|
+
inDoubleQuote = !inDoubleQuote;
|
|
309
|
+
} else if (!inSingleQuote && !inDoubleQuote) {
|
|
310
|
+
if (ch === '(') {
|
|
311
|
+
depth++;
|
|
312
|
+
} else if (ch === ')') {
|
|
313
|
+
if (depth > 0) depth--;
|
|
314
|
+
} else if (depth === 0 && expr.slice(i, i + opLen) === op) {
|
|
315
|
+
parts.push(expr.slice(lastIndex, i).trim());
|
|
316
|
+
lastIndex = i + opLen;
|
|
317
|
+
i += opLen - 1;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (parts.length > 0) {
|
|
323
|
+
parts.push(expr.slice(lastIndex).trim());
|
|
324
|
+
return parts;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Find the first comparison operator at the top level outside quotes and parentheses.
|
|
332
|
+
*/
|
|
333
|
+
function findTopLevelComparison(expr) {
|
|
334
|
+
const operators = ['===', '!==', '==', '!=', '>=', '<=', '>', '<'];
|
|
335
|
+
let inSingleQuote = false;
|
|
336
|
+
let inDoubleQuote = false;
|
|
337
|
+
let depth = 0;
|
|
338
|
+
const len = expr.length;
|
|
339
|
+
|
|
340
|
+
for (let i = 0; i < len; i++) {
|
|
341
|
+
const ch = expr[i];
|
|
342
|
+
const prev = i > 0 ? expr[i - 1] : '';
|
|
343
|
+
|
|
344
|
+
if (ch === "'" && !inDoubleQuote && prev !== '\\') {
|
|
345
|
+
inSingleQuote = !inSingleQuote;
|
|
346
|
+
} else if (ch === '"' && !inSingleQuote && prev !== '\\') {
|
|
347
|
+
inDoubleQuote = !inDoubleQuote;
|
|
348
|
+
} else if (!inSingleQuote && !inDoubleQuote) {
|
|
349
|
+
if (ch === '(') {
|
|
350
|
+
depth++;
|
|
351
|
+
} else if (ch === ')') {
|
|
352
|
+
if (depth > 0) depth--;
|
|
353
|
+
} else if (depth === 0 && i > 0) {
|
|
354
|
+
for (const op of operators) {
|
|
355
|
+
if (expr.slice(i, i + op.length) === op) {
|
|
356
|
+
return {
|
|
357
|
+
op,
|
|
358
|
+
left: expr.slice(0, i).trim(),
|
|
359
|
+
right: expr.slice(i + op.length).trim(),
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
|
|
241
369
|
/**
|
|
242
370
|
* Safely evaluate a declarative binding expression against controller state without
|
|
243
371
|
* naive regex transformations or `eval`/`new Function`.
|
|
@@ -246,6 +374,8 @@ function resolveOperand(state, token) {
|
|
|
246
374
|
* - Property path: `count`, `user.name`, `items.length`
|
|
247
375
|
* - Negation: `!pending`, `!!error`
|
|
248
376
|
* - Simple comparisons: `status === 'active'`, `count > 0`, `step !== 1`
|
|
377
|
+
* - Logical operators: `isReady && !hasError`, `status === 'a' || status === 'b'`
|
|
378
|
+
* - Parenthesized groups: `(a || b) && c`
|
|
249
379
|
*
|
|
250
380
|
* @param {object} state
|
|
251
381
|
* @param {string} rawExpr
|
|
@@ -253,39 +383,55 @@ function resolveOperand(state, token) {
|
|
|
253
383
|
*/
|
|
254
384
|
function evaluateStateExpression(state, rawExpr) {
|
|
255
385
|
if (typeof rawExpr !== 'string') return undefined;
|
|
256
|
-
const expr = rawExpr.trim();
|
|
386
|
+
const expr = stripOuterParens(rawExpr.trim());
|
|
257
387
|
if (!expr) return undefined;
|
|
258
388
|
|
|
259
|
-
//
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
if (leftRaw && rightRaw) {
|
|
267
|
-
const left = resolveOperand(state, leftRaw);
|
|
268
|
-
const right = resolveOperand(state, rightRaw);
|
|
269
|
-
switch (op) {
|
|
270
|
-
case '===':
|
|
271
|
-
case '==':
|
|
272
|
-
return left === right;
|
|
273
|
-
case '!==':
|
|
274
|
-
case '!=':
|
|
275
|
-
return left !== right;
|
|
276
|
-
case '>=':
|
|
277
|
-
return Number(left) >= Number(right);
|
|
278
|
-
case '<=':
|
|
279
|
-
return Number(left) <= Number(right);
|
|
280
|
-
case '>':
|
|
281
|
-
return Number(left) > Number(right);
|
|
282
|
-
case '<':
|
|
283
|
-
return Number(left) < Number(right);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
389
|
+
// 1. Logical OR (||) - lowest precedence, evaluated first so that A || B && C splits into A and (B && C)
|
|
390
|
+
const orParts = splitTopLevel(expr, '||');
|
|
391
|
+
if (orParts && orParts.length > 1) {
|
|
392
|
+
let result = false;
|
|
393
|
+
for (const part of orParts) {
|
|
394
|
+
result = evaluateStateExpression(state, part);
|
|
395
|
+
if (result) return result;
|
|
286
396
|
}
|
|
397
|
+
return result;
|
|
287
398
|
}
|
|
288
399
|
|
|
400
|
+
// 2. Logical AND (&&) - higher precedence than ||
|
|
401
|
+
const andParts = splitTopLevel(expr, '&&');
|
|
402
|
+
if (andParts && andParts.length > 1) {
|
|
403
|
+
let result = true;
|
|
404
|
+
for (const part of andParts) {
|
|
405
|
+
result = evaluateStateExpression(state, part);
|
|
406
|
+
if (!result) return result;
|
|
407
|
+
}
|
|
408
|
+
return result;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// 3. Comparison operators (===, !==, ==, !=, >=, <=, >, <) outside quotes
|
|
412
|
+
const comp = findTopLevelComparison(expr);
|
|
413
|
+
if (comp && comp.left && comp.right) {
|
|
414
|
+
const left = resolveOperand(state, comp.left);
|
|
415
|
+
const right = resolveOperand(state, comp.right);
|
|
416
|
+
switch (comp.op) {
|
|
417
|
+
case '===':
|
|
418
|
+
case '==':
|
|
419
|
+
return left === right;
|
|
420
|
+
case '!==':
|
|
421
|
+
case '!=':
|
|
422
|
+
return left !== right;
|
|
423
|
+
case '>=':
|
|
424
|
+
return Number(left) >= Number(right);
|
|
425
|
+
case '<=':
|
|
426
|
+
return Number(left) <= Number(right);
|
|
427
|
+
case '>':
|
|
428
|
+
return Number(left) > Number(right);
|
|
429
|
+
case '<':
|
|
430
|
+
return Number(left) < Number(right);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// 4. Negations (!!, !)
|
|
289
435
|
if (expr.startsWith('!!')) {
|
|
290
436
|
return Boolean(evaluateStateExpression(state, expr.slice(2)));
|
|
291
437
|
}
|
|
@@ -293,6 +439,7 @@ function evaluateStateExpression(state, rawExpr) {
|
|
|
293
439
|
return !Boolean(evaluateStateExpression(state, expr.slice(1)));
|
|
294
440
|
}
|
|
295
441
|
|
|
442
|
+
// 5. Literal token or property path lookup
|
|
296
443
|
return resolveOperand(state, expr);
|
|
297
444
|
}
|
|
298
445
|
|
|
@@ -360,11 +507,15 @@ function createIsolatedControllerState(
|
|
|
360
507
|
return Reflect.get(obj, prop, receiver);
|
|
361
508
|
}
|
|
362
509
|
|
|
363
|
-
// Allow accessing tasks on root state
|
|
510
|
+
// Allow accessing tasks and busy status on root state
|
|
364
511
|
if (!basePath && prop === 'tasks') {
|
|
365
512
|
const ctx = getContext();
|
|
366
513
|
return ctx && ctx.tasks ? ctx.tasks : undefined;
|
|
367
514
|
}
|
|
515
|
+
if (!basePath && (prop === '$busy' || prop === 'isBusy') && !Object.prototype.hasOwnProperty.call(obj, prop)) {
|
|
516
|
+
const ctx = getContext();
|
|
517
|
+
return ctx ? Boolean(ctx.isBusy) : false;
|
|
518
|
+
}
|
|
368
519
|
|
|
369
520
|
// Check if accessing a root-level computed property
|
|
370
521
|
if (!basePath && computedDefs && Object.prototype.hasOwnProperty.call(computedDefs, prop)) {
|
|
@@ -376,7 +527,7 @@ function createIsolatedControllerState(
|
|
|
376
527
|
// Track signal dependency in Datastar signals store
|
|
377
528
|
engine.signals.value(signalKeyFor(path));
|
|
378
529
|
// If accessing array length or methods, also subscribe to the array path itself
|
|
379
|
-
if (
|
|
530
|
+
if (isArray(obj) && basePath) {
|
|
380
531
|
engine.signals.value(signalKeyFor(basePath));
|
|
381
532
|
}
|
|
382
533
|
const val = Reflect.get(obj, prop, receiver);
|
|
@@ -415,21 +566,21 @@ function createIsolatedControllerState(
|
|
|
415
566
|
const prevValue = obj[prop];
|
|
416
567
|
const path = basePath ? `${basePath}.${String(prop)}` : String(prop);
|
|
417
568
|
|
|
418
|
-
if (Object.is(prevValue, rawNext) && !
|
|
569
|
+
if (Object.is(prevValue, rawNext) && !isArray(obj)) {
|
|
419
570
|
return true;
|
|
420
571
|
}
|
|
421
572
|
|
|
422
573
|
Reflect.set(obj, prop, rawNext, receiver);
|
|
423
574
|
|
|
424
575
|
// Seed nested keys if setting an object
|
|
425
|
-
if (rawNext !== null && typeof rawNext === 'object' && !
|
|
576
|
+
if (rawNext !== null && typeof rawNext === 'object' && !isArray(rawNext)) {
|
|
426
577
|
for (const [k, v] of Object.entries(rawNext)) {
|
|
427
578
|
engine.signals.setValue(signalKeyFor(`${path}.${k}`), v);
|
|
428
579
|
}
|
|
429
580
|
}
|
|
430
581
|
engine.signals.setValue(signalKeyFor(path), rawNext);
|
|
431
582
|
if (basePath) {
|
|
432
|
-
engine.signals.setValue(signalKeyFor(basePath),
|
|
583
|
+
engine.signals.setValue(signalKeyFor(basePath), isArray(obj) ? [...obj] : { ...obj });
|
|
433
584
|
}
|
|
434
585
|
return true;
|
|
435
586
|
},
|
|
@@ -462,13 +613,13 @@ function createIsolatedControllerState(
|
|
|
462
613
|
for (const [key, val] of Object.entries(initialState)) {
|
|
463
614
|
const cloned =
|
|
464
615
|
val !== null && typeof val === 'object'
|
|
465
|
-
?
|
|
616
|
+
? isArray(val)
|
|
466
617
|
? [...val]
|
|
467
618
|
: { ...val }
|
|
468
619
|
: val;
|
|
469
620
|
rawStore[key] = cloned;
|
|
470
621
|
engine.signals.setValue(signalKeyFor(key), cloned);
|
|
471
|
-
if (cloned !== null && typeof cloned === 'object' && !
|
|
622
|
+
if (cloned !== null && typeof cloned === 'object' && !isArray(cloned)) {
|
|
472
623
|
for (const [subKey, subVal] of Object.entries(cloned)) {
|
|
473
624
|
engine.signals.setValue(signalKeyFor(`${key}.${subKey}`), subVal);
|
|
474
625
|
}
|
|
@@ -587,6 +738,8 @@ function getMorphNodeKey(node) {
|
|
|
587
738
|
if (node.id) return `id:${node.id}`;
|
|
588
739
|
const wKey = node.getAttribute('data-w-key');
|
|
589
740
|
if (wKey) return `wkey:${wKey}`;
|
|
741
|
+
const hostKey = node.getAttribute('data-w-host');
|
|
742
|
+
if (hostKey) return `host:${hostKey}`;
|
|
590
743
|
const fragId = node.getAttribute('data-w-fragment-id');
|
|
591
744
|
if (fragId) return `frag:${fragId}`;
|
|
592
745
|
const formName = node.getAttribute('data-w-form');
|
|
@@ -703,6 +856,11 @@ function morphDomTrees(toEl, fromEl, ctx = {}) {
|
|
|
703
856
|
}
|
|
704
857
|
}
|
|
705
858
|
|
|
859
|
+
// If `toEl` is a client service UI host (`data-w-host`), the service owns its DOM contents
|
|
860
|
+
if (toEl.hasAttribute && toEl.hasAttribute('data-w-host')) {
|
|
861
|
+
return toEl;
|
|
862
|
+
}
|
|
863
|
+
|
|
706
864
|
// If `toEl` has `data-w-text`, client state owns its textContent; do not overwrite from server HTML
|
|
707
865
|
if (ownership.text) {
|
|
708
866
|
return toEl;
|
|
@@ -804,10 +962,13 @@ function morphDomTrees(toEl, fromEl, ctx = {}) {
|
|
|
804
962
|
}
|
|
805
963
|
}
|
|
806
964
|
|
|
807
|
-
// Remove leftover existing children that were not matched
|
|
965
|
+
// Remove leftover existing children that were not matched (preserve client service UI hosts)
|
|
808
966
|
for (let i = 0; i < existingChildren.length; i++) {
|
|
809
967
|
const oldChild = existingChildren[i];
|
|
810
968
|
if (!usedExisting.has(oldChild) && oldChild.parentNode === toEl) {
|
|
969
|
+
if (oldChild.nodeType === 1 && oldChild.hasAttribute && oldChild.hasAttribute('data-w-host')) {
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
811
972
|
if (oldChild.nodeType === 1 && typeof ctx.onBeforeNodeRemove === 'function') {
|
|
812
973
|
ctx.onBeforeNodeRemove(oldChild);
|
|
813
974
|
}
|
|
@@ -977,10 +1138,31 @@ function createDatastarAdapter(options = {}) {
|
|
|
977
1138
|
return bindings;
|
|
978
1139
|
}
|
|
979
1140
|
|
|
1141
|
+
function toggleElementVisibility(el, visible, initialDisplay) {
|
|
1142
|
+
if (visible) {
|
|
1143
|
+
el.removeAttribute('hidden');
|
|
1144
|
+
if (el.style && el.style.display === 'none') {
|
|
1145
|
+
el.style.display = initialDisplay;
|
|
1146
|
+
}
|
|
1147
|
+
} else {
|
|
1148
|
+
el.setAttribute('hidden', '');
|
|
1149
|
+
if (el.style) {
|
|
1150
|
+
el.style.display = 'none';
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
|
|
980
1155
|
/**
|
|
981
1156
|
* Bind V1 declarative attributes inside `rootEl` for a controller instance.
|
|
982
1157
|
*/
|
|
983
|
-
function bindControllerDom({
|
|
1158
|
+
function bindControllerDom({
|
|
1159
|
+
instanceId,
|
|
1160
|
+
rootEl,
|
|
1161
|
+
state,
|
|
1162
|
+
invokeAction,
|
|
1163
|
+
isConnected,
|
|
1164
|
+
isLoadingTargetActive,
|
|
1165
|
+
}) {
|
|
984
1166
|
if (!boundElementsByInstance.has(instanceId)) {
|
|
985
1167
|
boundElementsByInstance.set(instanceId, new WeakSet());
|
|
986
1168
|
}
|
|
@@ -1014,16 +1196,31 @@ function createDatastarAdapter(options = {}) {
|
|
|
1014
1196
|
const initialDisplay = el.style && el.style.display && el.style.display !== 'none' ? el.style.display : '';
|
|
1015
1197
|
const stop = engine.effect(() => {
|
|
1016
1198
|
if (!isConnected()) return;
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1199
|
+
toggleElementVisibility(el, Boolean(evaluateStateExpression(state, expr)), initialDisplay);
|
|
1200
|
+
});
|
|
1201
|
+
disposers.push(stop);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// 2b. data-w-loading & data-w-loading-hide (declarative action/task busy indicators)
|
|
1205
|
+
if (el.hasAttribute('data-w-loading') || el.hasAttribute('data-w-loading-hide')) {
|
|
1206
|
+
const isHide = el.hasAttribute('data-w-loading-hide');
|
|
1207
|
+
const rawSpec = el.getAttribute(isHide ? 'data-w-loading-hide' : 'data-w-loading') || '';
|
|
1208
|
+
const initialDisplay = el.style && el.style.display && el.style.display !== 'none' ? el.style.display : '';
|
|
1209
|
+
const loadingClasses = (el.getAttribute('data-w-loading-class') || '')
|
|
1210
|
+
.trim()
|
|
1211
|
+
.split(/\s+/)
|
|
1212
|
+
.filter(Boolean);
|
|
1213
|
+
const stop = engine.effect(() => {
|
|
1214
|
+
if (!isConnected()) return;
|
|
1215
|
+
const active =
|
|
1216
|
+
typeof isLoadingTargetActive === 'function'
|
|
1217
|
+
? Boolean(isLoadingTargetActive(rawSpec))
|
|
1218
|
+
: Boolean(evaluateStateExpression(state, rawSpec || '$busy'));
|
|
1219
|
+
toggleElementVisibility(el, isHide ? !active : active, initialDisplay);
|
|
1220
|
+
if (loadingClasses.length > 0 && el.classList) {
|
|
1221
|
+
for (let c = 0; c < loadingClasses.length; c++) {
|
|
1222
|
+
if (active) el.classList.add(loadingClasses[c]);
|
|
1223
|
+
else el.classList.remove(loadingClasses[c]);
|
|
1027
1224
|
}
|
|
1028
1225
|
}
|
|
1029
1226
|
});
|
|
@@ -1102,7 +1299,7 @@ function createDatastarAdapter(options = {}) {
|
|
|
1102
1299
|
const currentVal = getByPath(state, modelPath);
|
|
1103
1300
|
|
|
1104
1301
|
if (type === 'checkbox') {
|
|
1105
|
-
if (
|
|
1302
|
+
if (isArray(currentVal)) {
|
|
1106
1303
|
el.checked = currentVal.map(String).includes(String(el.value));
|
|
1107
1304
|
} else {
|
|
1108
1305
|
el.checked = Boolean(currentVal);
|
|
@@ -1110,7 +1307,7 @@ function createDatastarAdapter(options = {}) {
|
|
|
1110
1307
|
} else if (type === 'radio') {
|
|
1111
1308
|
el.checked = String(currentVal) === String(el.value);
|
|
1112
1309
|
} else if (el.tagName === 'SELECT' && el.multiple) {
|
|
1113
|
-
const arr =
|
|
1310
|
+
const arr = isArray(currentVal) ? currentVal.map(String) : [];
|
|
1114
1311
|
const opts = el.options || [];
|
|
1115
1312
|
for (let j = 0; j < opts.length; j++) {
|
|
1116
1313
|
opts[j].selected = arr.includes(String(opts[j].value));
|
|
@@ -1135,7 +1332,7 @@ function createDatastarAdapter(options = {}) {
|
|
|
1135
1332
|
|
|
1136
1333
|
if (type === 'checkbox') {
|
|
1137
1334
|
const cur = getByPath(state, modelPath);
|
|
1138
|
-
if (
|
|
1335
|
+
if (isArray(cur)) {
|
|
1139
1336
|
const next = el.checked
|
|
1140
1337
|
? Array.from(new Set([...cur, el.value]))
|
|
1141
1338
|
: cur.filter((item) => String(item) !== String(el.value));
|