simplyview 3.0.2 → 3.0.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/README.md +2 -5
- package/dist/simply.app.js +126 -735
- package/dist/simply.app.min.js +1 -1
- package/dist/simply.app.min.js.map +4 -4
- package/dist/simply.everything.js +141 -1042
- package/dist/simply.everything.min.js +1 -1
- package/dist/simply.everything.min.js.map +4 -4
- package/package.json +4 -4
- package/src/app.mjs +23 -25
- package/src/bind.mjs +132 -37
- package/src/command.mjs +1 -1
- package/src/everything.mjs +6 -10
- package/src/include.mjs +13 -10
- package/src/key.mjs +74 -21
- package/src/route.mjs +25 -13
- package/src/view.mjs +20 -0
- package/src/changes.md +0 -18
package/dist/simply.app.js
CHANGED
|
@@ -7,13 +7,15 @@
|
|
|
7
7
|
constructor(options = {}) {
|
|
8
8
|
this.root = options.root || "/";
|
|
9
9
|
this.app = options.app;
|
|
10
|
+
this.addMissingSlash = !!options.addMissingSlash;
|
|
11
|
+
this.matchExact = !!options.matchExact;
|
|
10
12
|
this.clear();
|
|
11
13
|
if (options.routes) {
|
|
12
14
|
this.load(options.routes);
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
load(routes2) {
|
|
16
|
-
parseRoutes(routes2, this.routeInfo);
|
|
18
|
+
parseRoutes(routes2, this.routeInfo, this.matchExact);
|
|
17
19
|
}
|
|
18
20
|
clear() {
|
|
19
21
|
this.routeInfo = [];
|
|
@@ -41,13 +43,22 @@
|
|
|
41
43
|
path = getPath(path);
|
|
42
44
|
for (let route of this.routeInfo) {
|
|
43
45
|
matches = route.match.exec(path);
|
|
46
|
+
if (this.addMissingSlash && !matches?.length) {
|
|
47
|
+
if (path && path[path.length - 1] != "/") {
|
|
48
|
+
matches = route.match.exec(path + "/");
|
|
49
|
+
if (matches) {
|
|
50
|
+
path += "/";
|
|
51
|
+
history.replaceState({}, "", getURL(path));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
44
55
|
if (matches && matches.length) {
|
|
45
56
|
var params = {};
|
|
46
|
-
route.params.forEach((key,
|
|
57
|
+
route.params.forEach((key, i2) => {
|
|
47
58
|
if (key == "*") {
|
|
48
59
|
key = "remainder";
|
|
49
60
|
}
|
|
50
|
-
params[key] = matches[
|
|
61
|
+
params[key] = matches[i2 + 1];
|
|
51
62
|
});
|
|
52
63
|
Object.assign(params, options);
|
|
53
64
|
args.route = route;
|
|
@@ -59,9 +70,6 @@
|
|
|
59
70
|
return args.result;
|
|
60
71
|
}
|
|
61
72
|
}
|
|
62
|
-
if (path && path[path.length - 1] != "/") {
|
|
63
|
-
return this.match(path + "/", options);
|
|
64
|
-
}
|
|
65
73
|
return false;
|
|
66
74
|
}
|
|
67
75
|
runListeners(action, params) {
|
|
@@ -88,7 +96,7 @@
|
|
|
88
96
|
this.match(getPath(document.location.pathname, this.root));
|
|
89
97
|
}
|
|
90
98
|
});
|
|
91
|
-
|
|
99
|
+
this.app.container.addEventListener("click", (evt) => {
|
|
92
100
|
if (evt.ctrlKey) {
|
|
93
101
|
return;
|
|
94
102
|
}
|
|
@@ -107,10 +115,11 @@
|
|
|
107
115
|
if (this.has(path)) {
|
|
108
116
|
let params = this.runListeners("goto", { path });
|
|
109
117
|
if (params.path) {
|
|
110
|
-
this.goto(params.path)
|
|
118
|
+
if (this.goto(params.path)) {
|
|
119
|
+
evt.preventDefault();
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
111
122
|
}
|
|
112
|
-
evt.preventDefault();
|
|
113
|
-
return false;
|
|
114
123
|
}
|
|
115
124
|
}
|
|
116
125
|
});
|
|
@@ -171,11 +180,13 @@
|
|
|
171
180
|
}
|
|
172
181
|
return root + path;
|
|
173
182
|
}
|
|
174
|
-
function getRegexpFromRoute(route) {
|
|
183
|
+
function getRegexpFromRoute(route, exact = false) {
|
|
184
|
+
if (exact) {
|
|
185
|
+
return new RegExp("^" + route.replace(/:\w+/g, "([^/]+)").replace(/:\*/, "(.*)") + "(\\?|$)");
|
|
186
|
+
}
|
|
175
187
|
return new RegExp("^" + route.replace(/:\w+/g, "([^/]+)").replace(/:\*/, "(.*)"));
|
|
176
188
|
}
|
|
177
|
-
function parseRoutes(routes2) {
|
|
178
|
-
let routeInfo = [];
|
|
189
|
+
function parseRoutes(routes2, routeInfo, exact = false) {
|
|
179
190
|
const paths = Object.keys(routes2);
|
|
180
191
|
const matchParams = /:(\w+|\*)/g;
|
|
181
192
|
for (let path of paths) {
|
|
@@ -188,7 +199,7 @@
|
|
|
188
199
|
}
|
|
189
200
|
} while (matches);
|
|
190
201
|
routeInfo.push({
|
|
191
|
-
match: getRegexpFromRoute(path),
|
|
202
|
+
match: getRegexpFromRoute(path, exact),
|
|
192
203
|
params,
|
|
193
204
|
action: routes2[path]
|
|
194
205
|
});
|
|
@@ -219,7 +230,7 @@
|
|
|
219
230
|
return;
|
|
220
231
|
}
|
|
221
232
|
const shouldContinue = this[command.name].call(options.app, command.source, command.value);
|
|
222
|
-
if (shouldContinue
|
|
233
|
+
if (shouldContinue !== true) {
|
|
223
234
|
evt.preventDefault();
|
|
224
235
|
evt.stopPropagation();
|
|
225
236
|
return false;
|
|
@@ -331,7 +342,14 @@
|
|
|
331
342
|
}
|
|
332
343
|
|
|
333
344
|
// src/key.mjs
|
|
334
|
-
var
|
|
345
|
+
var KEY = Object.freeze({
|
|
346
|
+
Compose: 229,
|
|
347
|
+
Control: 17,
|
|
348
|
+
Meta: 224,
|
|
349
|
+
Alt: 18,
|
|
350
|
+
Shift: 16
|
|
351
|
+
});
|
|
352
|
+
var SimplyKey = class {
|
|
335
353
|
constructor(options = {}) {
|
|
336
354
|
if (!options.app) {
|
|
337
355
|
options.app = {};
|
|
@@ -341,7 +359,7 @@
|
|
|
341
359
|
}
|
|
342
360
|
Object.assign(this, options.keys);
|
|
343
361
|
const keyHandler = (e) => {
|
|
344
|
-
if (e.isComposing || e.keyCode ===
|
|
362
|
+
if (e.isComposing || e.keyCode === KEY.Compose) {
|
|
345
363
|
return;
|
|
346
364
|
}
|
|
347
365
|
if (e.defaultPrevented) {
|
|
@@ -354,714 +372,88 @@
|
|
|
354
372
|
if (e.target.closest("[data-simply-keyboard]")) {
|
|
355
373
|
selectedKeyboard = e.target.closest("[data-simply-keyboard]").dataset.simplyKeyboard;
|
|
356
374
|
}
|
|
357
|
-
let
|
|
358
|
-
if (e.ctrlKey && e.keyCode !=
|
|
359
|
-
|
|
360
|
-
}
|
|
361
|
-
if (e.metaKey && e.keyCode !=
|
|
362
|
-
|
|
363
|
-
}
|
|
364
|
-
if (e.altKey && e.keyCode !=
|
|
365
|
-
|
|
366
|
-
}
|
|
367
|
-
if (e.shiftKey && e.keyCode !=
|
|
368
|
-
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
}
|
|
388
|
-
var signalHandler = {
|
|
389
|
-
get: (target, property, receiver) => {
|
|
390
|
-
if (property === Symbol.xRay) {
|
|
391
|
-
return target;
|
|
392
|
-
}
|
|
393
|
-
const value = target?.[property];
|
|
394
|
-
notifyGet(receiver, property);
|
|
395
|
-
if (typeof value === "function") {
|
|
396
|
-
if (Array.isArray(target)) {
|
|
397
|
-
return (...args) => {
|
|
398
|
-
let l = target.length;
|
|
399
|
-
let result = value.apply(receiver, args);
|
|
400
|
-
if (l != target.length) {
|
|
401
|
-
notifySet(receiver, makeContext("length", { was: l, now: target.length }));
|
|
402
|
-
}
|
|
403
|
-
return result;
|
|
404
|
-
};
|
|
405
|
-
} else if (target instanceof Set || target instanceof Map) {
|
|
406
|
-
return (...args) => {
|
|
407
|
-
let s = target.size;
|
|
408
|
-
let result = value.apply(target, args);
|
|
409
|
-
if (s != target.size) {
|
|
410
|
-
notifySet(receiver, makeContext("size", { was: s, now: target.size }));
|
|
411
|
-
}
|
|
412
|
-
if (["set", "add", "clear", "delete"].includes(property)) {
|
|
413
|
-
notifySet(receiver, makeContext({ entries: {}, forEach: {}, has: {}, keys: {}, values: {}, [Symbol.iterator]: {} }));
|
|
414
|
-
}
|
|
415
|
-
return result;
|
|
416
|
-
};
|
|
417
|
-
} else if (target instanceof HTMLElement || target instanceof Number || target instanceof String || target instanceof Boolean) {
|
|
418
|
-
return value.bind(target);
|
|
419
|
-
} else {
|
|
420
|
-
return value.bind(receiver);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
if (value && typeof value == "object") {
|
|
424
|
-
return signal(value);
|
|
425
|
-
}
|
|
426
|
-
return value;
|
|
427
|
-
},
|
|
428
|
-
set: (target, property, value, receiver) => {
|
|
429
|
-
value = value?.[Symbol.xRay] || value;
|
|
430
|
-
let current = target[property];
|
|
431
|
-
if (current !== value) {
|
|
432
|
-
target[property] = value;
|
|
433
|
-
notifySet(receiver, makeContext(property, { was: current, now: value }));
|
|
434
|
-
}
|
|
435
|
-
if (typeof current === "undefined") {
|
|
436
|
-
notifySet(receiver, makeContext(iterate, {}));
|
|
437
|
-
}
|
|
438
|
-
return true;
|
|
439
|
-
},
|
|
440
|
-
has: (target, property) => {
|
|
441
|
-
let receiver = signals.get(target);
|
|
442
|
-
if (receiver) {
|
|
443
|
-
notifyGet(receiver, property);
|
|
444
|
-
}
|
|
445
|
-
return Object.hasOwn(target, property);
|
|
446
|
-
},
|
|
447
|
-
deleteProperty: (target, property) => {
|
|
448
|
-
if (typeof target[property] !== "undefined") {
|
|
449
|
-
let current = target[property];
|
|
450
|
-
delete target[property];
|
|
451
|
-
let receiver = signals.get(target);
|
|
452
|
-
notifySet(receiver, makeContext(property, { delete: true, was: current }));
|
|
453
|
-
}
|
|
454
|
-
return true;
|
|
455
|
-
},
|
|
456
|
-
defineProperty: (target, property, descriptor) => {
|
|
457
|
-
if (typeof target[property] === "undefined") {
|
|
458
|
-
let receiver = signals.get(target);
|
|
459
|
-
notifySet(receiver, makeContext(iterate, {}));
|
|
460
|
-
}
|
|
461
|
-
return Object.defineProperty(target, property, descriptor);
|
|
462
|
-
},
|
|
463
|
-
ownKeys: (target) => {
|
|
464
|
-
let receiver = signals.get(target);
|
|
465
|
-
notifyGet(receiver, iterate);
|
|
466
|
-
return Reflect.ownKeys(target);
|
|
467
|
-
}
|
|
468
|
-
};
|
|
469
|
-
var signals = /* @__PURE__ */ new WeakMap();
|
|
470
|
-
function signal(v) {
|
|
471
|
-
if (!signals.has(v)) {
|
|
472
|
-
signals.set(v, new Proxy(v, signalHandler));
|
|
473
|
-
}
|
|
474
|
-
return signals.get(v);
|
|
475
|
-
}
|
|
476
|
-
var batchedListeners = /* @__PURE__ */ new Set();
|
|
477
|
-
var batchMode = 0;
|
|
478
|
-
function notifySet(self, context = {}) {
|
|
479
|
-
let listeners = [];
|
|
480
|
-
context.forEach((change, property) => {
|
|
481
|
-
let propListeners = getListeners(self, property);
|
|
482
|
-
if (propListeners?.length) {
|
|
483
|
-
for (let listener of propListeners) {
|
|
484
|
-
addContext(listener, makeContext(property, change));
|
|
485
|
-
}
|
|
486
|
-
listeners = listeners.concat(propListeners);
|
|
487
|
-
}
|
|
488
|
-
});
|
|
489
|
-
listeners = new Set(listeners.filter(Boolean));
|
|
490
|
-
if (listeners) {
|
|
491
|
-
if (batchMode) {
|
|
492
|
-
batchedListeners = batchedListeners.union(listeners);
|
|
493
|
-
} else {
|
|
494
|
-
const currentEffect = computeStack[computeStack.length - 1];
|
|
495
|
-
for (let listener of Array.from(listeners)) {
|
|
496
|
-
if (listener != currentEffect && listener?.needsUpdate) {
|
|
497
|
-
listener();
|
|
498
|
-
}
|
|
499
|
-
clearContext(listener);
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
function makeContext(property, change) {
|
|
505
|
-
let context = /* @__PURE__ */ new Map();
|
|
506
|
-
if (typeof property === "object") {
|
|
507
|
-
for (let prop in property) {
|
|
508
|
-
context.set(prop, property[prop]);
|
|
509
|
-
}
|
|
510
|
-
} else {
|
|
511
|
-
context.set(property, change);
|
|
512
|
-
}
|
|
513
|
-
return context;
|
|
514
|
-
}
|
|
515
|
-
function addContext(listener, context) {
|
|
516
|
-
if (!listener.context) {
|
|
517
|
-
listener.context = context;
|
|
518
|
-
} else {
|
|
519
|
-
context.forEach((change, property) => {
|
|
520
|
-
listener.context.set(property, change);
|
|
521
|
-
});
|
|
522
|
-
}
|
|
523
|
-
listener.needsUpdate = true;
|
|
524
|
-
}
|
|
525
|
-
function clearContext(listener) {
|
|
526
|
-
delete listener.context;
|
|
527
|
-
delete listener.needsUpdate;
|
|
528
|
-
}
|
|
529
|
-
function notifyGet(self, property) {
|
|
530
|
-
let currentCompute = computeStack[computeStack.length - 1];
|
|
531
|
-
if (currentCompute) {
|
|
532
|
-
setListeners(self, property, currentCompute);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
var listenersMap = /* @__PURE__ */ new WeakMap();
|
|
536
|
-
var computeMap = /* @__PURE__ */ new WeakMap();
|
|
537
|
-
function getListeners(self, property) {
|
|
538
|
-
let listeners = listenersMap.get(self);
|
|
539
|
-
return listeners ? Array.from(listeners.get(property) || []) : [];
|
|
540
|
-
}
|
|
541
|
-
function setListeners(self, property, compute) {
|
|
542
|
-
if (!listenersMap.has(self)) {
|
|
543
|
-
listenersMap.set(self, /* @__PURE__ */ new Map());
|
|
544
|
-
}
|
|
545
|
-
let listeners = listenersMap.get(self);
|
|
546
|
-
if (!listeners.has(property)) {
|
|
547
|
-
listeners.set(property, /* @__PURE__ */ new Set());
|
|
548
|
-
}
|
|
549
|
-
listeners.get(property).add(compute);
|
|
550
|
-
if (!computeMap.has(compute)) {
|
|
551
|
-
computeMap.set(compute, /* @__PURE__ */ new Map());
|
|
552
|
-
}
|
|
553
|
-
let connectedSignals = computeMap.get(compute);
|
|
554
|
-
if (!connectedSignals.has(property)) {
|
|
555
|
-
connectedSignals.set(property, /* @__PURE__ */ new Set());
|
|
556
|
-
}
|
|
557
|
-
connectedSignals.get(property).add(self);
|
|
558
|
-
}
|
|
559
|
-
function clearListeners(compute) {
|
|
560
|
-
let connectedSignals = computeMap.get(compute);
|
|
561
|
-
if (connectedSignals) {
|
|
562
|
-
connectedSignals.forEach((property) => {
|
|
563
|
-
property.forEach((s) => {
|
|
564
|
-
let listeners = listenersMap.get(s);
|
|
565
|
-
if (listeners.has(property)) {
|
|
566
|
-
listeners.get(property).delete(compute);
|
|
375
|
+
let keyCombination = [];
|
|
376
|
+
if (e.ctrlKey && e.keyCode != KEY.Control) {
|
|
377
|
+
keyCombination.push("Control");
|
|
378
|
+
}
|
|
379
|
+
if (e.metaKey && e.keyCode != KEY.Meta) {
|
|
380
|
+
keyCombination.push("Meta");
|
|
381
|
+
}
|
|
382
|
+
if (e.altKey && e.keyCode != KEY.Alt) {
|
|
383
|
+
keyCombination.push("Alt");
|
|
384
|
+
}
|
|
385
|
+
if (e.shiftKey && e.keyCode != KEY.Shift) {
|
|
386
|
+
keyCombination.push("Shift");
|
|
387
|
+
}
|
|
388
|
+
keyCombination.push(e.key.toLowerCase());
|
|
389
|
+
let keyboards = [];
|
|
390
|
+
let keyboardElement = event.target.closest("[data-simply-keyboard]");
|
|
391
|
+
while (keyboardElement) {
|
|
392
|
+
keyboards.push(keyboardElement.dataset.simplyKeyboard);
|
|
393
|
+
keyboardElement = keyboardElement.parentNode.closest("[data-simply-keyboard]");
|
|
394
|
+
}
|
|
395
|
+
keyboards.push("");
|
|
396
|
+
let keyboard, subkeyboard;
|
|
397
|
+
let separators = ["+", "-"];
|
|
398
|
+
for (i in keyboards) {
|
|
399
|
+
keyboard = keyboards[i];
|
|
400
|
+
if (keyboard == "") {
|
|
401
|
+
subkeyboard = "default";
|
|
402
|
+
} else {
|
|
403
|
+
subkeyboard = keyboard;
|
|
404
|
+
keyboard += ".";
|
|
567
405
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
function destroy(connectedSignal) {
|
|
577
|
-
const computeEffect = effectMap.get(connectedSignal)?.deref();
|
|
578
|
-
if (!computeEffect) {
|
|
579
|
-
return;
|
|
580
|
-
}
|
|
581
|
-
clearListeners(computeEffect);
|
|
582
|
-
let fn = computeEffect.fn;
|
|
583
|
-
signals.remove(fn);
|
|
584
|
-
effectMap.delete(connectedSignal);
|
|
585
|
-
}
|
|
586
|
-
function throttledEffect(fn, throttleTime) {
|
|
587
|
-
if (effectStack.findIndex((f) => fn == f) !== -1) {
|
|
588
|
-
throw new Error("Recursive update() call", { cause: fn });
|
|
589
|
-
}
|
|
590
|
-
effectStack.push(fn);
|
|
591
|
-
let connectedSignal = signals.get(fn);
|
|
592
|
-
if (!connectedSignal) {
|
|
593
|
-
connectedSignal = signal({
|
|
594
|
-
current: null
|
|
595
|
-
});
|
|
596
|
-
signals.set(fn, connectedSignal);
|
|
597
|
-
}
|
|
598
|
-
let throttled = false;
|
|
599
|
-
let hasChange = true;
|
|
600
|
-
const computeEffect = function computeEffect2() {
|
|
601
|
-
if (signalStack.findIndex((s) => s == connectedSignal) !== -1) {
|
|
602
|
-
throw new Error("Cyclical dependency in update() call", { cause: fn });
|
|
603
|
-
}
|
|
604
|
-
if (throttled && throttled > Date.now()) {
|
|
605
|
-
hasChange = true;
|
|
606
|
-
return;
|
|
607
|
-
}
|
|
608
|
-
clearListeners(computeEffect2);
|
|
609
|
-
computeStack.push(computeEffect2);
|
|
610
|
-
signalStack.push(connectedSignal);
|
|
611
|
-
let result;
|
|
612
|
-
try {
|
|
613
|
-
result = fn(computeEffect2, computeStack, signalStack);
|
|
614
|
-
} finally {
|
|
615
|
-
hasChange = false;
|
|
616
|
-
computeStack.pop();
|
|
617
|
-
signalStack.pop();
|
|
618
|
-
if (result instanceof Promise) {
|
|
619
|
-
result.then((result2) => {
|
|
620
|
-
connectedSignal.current = result2;
|
|
621
|
-
});
|
|
622
|
-
} else {
|
|
623
|
-
connectedSignal.current = result;
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
throttled = Date.now() + throttleTime;
|
|
627
|
-
globalThis.setTimeout(() => {
|
|
628
|
-
if (hasChange) {
|
|
629
|
-
computeEffect2();
|
|
630
|
-
}
|
|
631
|
-
}, throttleTime);
|
|
632
|
-
};
|
|
633
|
-
computeEffect();
|
|
634
|
-
return connectedSignal;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
// src/bind.mjs
|
|
638
|
-
var SimplyBind = class {
|
|
639
|
-
constructor(options) {
|
|
640
|
-
this.bindings = /* @__PURE__ */ new Map();
|
|
641
|
-
const defaultOptions = {
|
|
642
|
-
container: document.body,
|
|
643
|
-
attribute: "data-bind",
|
|
644
|
-
transformers: [],
|
|
645
|
-
defaultTransformers: [defaultTransformer]
|
|
646
|
-
};
|
|
647
|
-
if (!options?.root) {
|
|
648
|
-
throw new Error("bind needs at least options.root set");
|
|
649
|
-
}
|
|
650
|
-
this.options = Object.assign({}, defaultOptions, options);
|
|
651
|
-
const attribute = this.options.attribute;
|
|
652
|
-
const render = (el) => {
|
|
653
|
-
this.bindings.set(el, throttledEffect(() => {
|
|
654
|
-
const context = {
|
|
655
|
-
templates: el.querySelectorAll(":scope > template"),
|
|
656
|
-
path: this.getBindingPath(el)
|
|
657
|
-
};
|
|
658
|
-
context.value = getValueByPath(this.options.root, context.path);
|
|
659
|
-
context.element = el;
|
|
660
|
-
runTransformers(context);
|
|
661
|
-
}, 100));
|
|
662
|
-
};
|
|
663
|
-
const runTransformers = (context) => {
|
|
664
|
-
let transformers = this.options.defaultTransformers || [];
|
|
665
|
-
if (context.element.dataset.transform) {
|
|
666
|
-
context.element.dataset.transform.split(" ").filter(Boolean).forEach((t) => {
|
|
667
|
-
if (this.options.transformers[t]) {
|
|
668
|
-
transformers.push(this.options.transformers[t]);
|
|
669
|
-
} else {
|
|
670
|
-
console.warn("No transformer with name " + t + " configured", { cause: context.element });
|
|
406
|
+
for (let separator of separators) {
|
|
407
|
+
let keyString = keyCombination.join(separator);
|
|
408
|
+
if (this[subkeyboard] && typeof this[subkeyboard][keyString] == "function") {
|
|
409
|
+
let _continue = this[subkeyboard][keyString].call(this[subkeyboard], e);
|
|
410
|
+
if (!_continue) {
|
|
411
|
+
e.preventDefault();
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
671
414
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
return (context2) => {
|
|
678
|
-
return transformer2.call(this, context2, next2);
|
|
679
|
-
};
|
|
680
|
-
})(next, transformer);
|
|
681
|
-
}
|
|
682
|
-
next(context);
|
|
683
|
-
};
|
|
684
|
-
const applyBindings = (bindings2) => {
|
|
685
|
-
for (let bindingEl of bindings2) {
|
|
686
|
-
render(bindingEl);
|
|
687
|
-
}
|
|
688
|
-
};
|
|
689
|
-
const updateBindings = (changes) => {
|
|
690
|
-
for (const change of changes) {
|
|
691
|
-
if (change.type == "childList" && change.addedNodes) {
|
|
692
|
-
for (let node of change.addedNodes) {
|
|
693
|
-
if (node instanceof HTMLElement) {
|
|
694
|
-
let bindings2 = Array.from(node.querySelectorAll(`[${attribute}]`));
|
|
695
|
-
if (node.matches(`[${attribute}]`)) {
|
|
696
|
-
bindings2.unshift(node);
|
|
697
|
-
}
|
|
698
|
-
if (bindings2.length) {
|
|
699
|
-
applyBindings(bindings2);
|
|
700
|
-
}
|
|
415
|
+
if (typeof this[subkeyboard + keyString] == "function") {
|
|
416
|
+
let _continue = this[subkeyboard + keyString].call(this, e);
|
|
417
|
+
if (!_continue) {
|
|
418
|
+
e.preventDefault();
|
|
419
|
+
return;
|
|
701
420
|
}
|
|
702
421
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
});
|
|
709
|
-
this.observer.observe(options.container, {
|
|
710
|
-
subtree: true,
|
|
711
|
-
childList: true
|
|
712
|
-
});
|
|
713
|
-
const bindings = this.options.container.querySelectorAll("[" + this.options.attribute + "]:not(template)");
|
|
714
|
-
if (bindings.length) {
|
|
715
|
-
applyBindings(bindings);
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
/**
|
|
719
|
-
* Finds the first matching template and creates a new DocumentFragment
|
|
720
|
-
* with the correct data bind attributes in it (prepends the current path)
|
|
721
|
-
*/
|
|
722
|
-
applyTemplate(context) {
|
|
723
|
-
const path = context.path;
|
|
724
|
-
const templates = context.templates;
|
|
725
|
-
const list = context.list;
|
|
726
|
-
const index = context.index;
|
|
727
|
-
const parent = context.parent;
|
|
728
|
-
const value = list ? list[index] : context.value;
|
|
729
|
-
let template = this.findTemplate(templates, value);
|
|
730
|
-
if (!template) {
|
|
731
|
-
let result = new DocumentFragment();
|
|
732
|
-
result.innerHTML = "<!-- no matching template -->";
|
|
733
|
-
return result;
|
|
734
|
-
}
|
|
735
|
-
let clone = template.content.cloneNode(true);
|
|
736
|
-
if (!clone.children?.length) {
|
|
737
|
-
throw new Error("template must contain a single html element", { cause: template });
|
|
738
|
-
}
|
|
739
|
-
if (clone.children.length > 1) {
|
|
740
|
-
throw new Error("template must contain a single root node", { cause: template });
|
|
741
|
-
}
|
|
742
|
-
const bindings = clone.querySelectorAll("[" + this.options.attribute + "]");
|
|
743
|
-
const attribute = this.options.attribute;
|
|
744
|
-
for (let binding of bindings) {
|
|
745
|
-
const bind2 = binding.getAttribute(attribute);
|
|
746
|
-
if (bind2.substring(0, "#root.".length) == "#root.") {
|
|
747
|
-
binding.setAttribute(attribute, bind2.substring("#root.".length));
|
|
748
|
-
} else if (bind2 == "#value" && index != null) {
|
|
749
|
-
binding.setAttribute(attribute, path + "." + index);
|
|
750
|
-
} else if (index != null) {
|
|
751
|
-
binding.setAttribute(attribute, path + "." + index + "." + bind2);
|
|
752
|
-
} else {
|
|
753
|
-
binding.setAttribute(attribute, parent + "." + bind2);
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
if (typeof index !== "undefined") {
|
|
757
|
-
clone.children[0].setAttribute(attribute + "-key", index);
|
|
758
|
-
}
|
|
759
|
-
clone.children[0].$bindTemplate = template;
|
|
760
|
-
return clone;
|
|
761
|
-
}
|
|
762
|
-
getBindingPath(el) {
|
|
763
|
-
return el.getAttribute(this.options.attribute);
|
|
764
|
-
}
|
|
765
|
-
/**
|
|
766
|
-
* Finds the first template from an array of templates that
|
|
767
|
-
* matches the given value.
|
|
768
|
-
*/
|
|
769
|
-
findTemplate(templates, value) {
|
|
770
|
-
const templateMatches = (t) => {
|
|
771
|
-
let path = this.getBindingPath(t);
|
|
772
|
-
let currentItem;
|
|
773
|
-
if (path) {
|
|
774
|
-
if (path.substr(0, 6) == "#root.") {
|
|
775
|
-
currentItem = getValueByPath(this.options.root, path);
|
|
776
|
-
} else {
|
|
777
|
-
currentItem = getValueByPath(value, path);
|
|
778
|
-
}
|
|
779
|
-
} else {
|
|
780
|
-
currentItem = value;
|
|
781
|
-
}
|
|
782
|
-
const strItem = "" + currentItem;
|
|
783
|
-
let matches = t.getAttribute(this.options.attribute + "-match");
|
|
784
|
-
if (matches) {
|
|
785
|
-
if (matches === "#empty" && !currentItem) {
|
|
786
|
-
return t;
|
|
787
|
-
} else if (matches === "#notempty" && currentItem) {
|
|
788
|
-
return t;
|
|
789
|
-
}
|
|
790
|
-
if (strItem.match(matches)) {
|
|
791
|
-
return t;
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
if (!matches) {
|
|
795
|
-
return t;
|
|
796
|
-
}
|
|
797
|
-
};
|
|
798
|
-
let template = Array.from(templates).find(templateMatches);
|
|
799
|
-
let rel = template?.getAttribute("rel");
|
|
800
|
-
if (rel) {
|
|
801
|
-
let replacement = document.querySelector("template#" + rel);
|
|
802
|
-
if (!replacement) {
|
|
803
|
-
throw new Error("Could not find template with id " + rel);
|
|
804
|
-
}
|
|
805
|
-
template = replacement;
|
|
806
|
-
}
|
|
807
|
-
return template;
|
|
808
|
-
}
|
|
809
|
-
destroy() {
|
|
810
|
-
this.bindings.forEach((binding) => {
|
|
811
|
-
destroy(binding);
|
|
812
|
-
});
|
|
813
|
-
this.bindings = /* @__PURE__ */ new Map();
|
|
814
|
-
this.observer.disconnect();
|
|
815
|
-
}
|
|
816
|
-
};
|
|
817
|
-
function bind(options) {
|
|
818
|
-
return new SimplyBind(options);
|
|
819
|
-
}
|
|
820
|
-
function matchValue(a, b) {
|
|
821
|
-
if (a == "#empty" && !b) {
|
|
822
|
-
return true;
|
|
823
|
-
}
|
|
824
|
-
if (b == "#empty" && !a) {
|
|
825
|
-
return true;
|
|
826
|
-
}
|
|
827
|
-
if ("" + a == "" + b) {
|
|
828
|
-
return true;
|
|
829
|
-
}
|
|
830
|
-
return false;
|
|
831
|
-
}
|
|
832
|
-
function getValueByPath(root, path) {
|
|
833
|
-
let parts = path.split(".");
|
|
834
|
-
let curr = root;
|
|
835
|
-
let part, prevPart;
|
|
836
|
-
while (parts.length && curr) {
|
|
837
|
-
part = parts.shift();
|
|
838
|
-
if (part == "#key") {
|
|
839
|
-
return prevPart;
|
|
840
|
-
} else if (part == "#value") {
|
|
841
|
-
return curr;
|
|
842
|
-
} else if (part == "#root") {
|
|
843
|
-
curr = root;
|
|
844
|
-
} else {
|
|
845
|
-
part = decodeURIComponent(part);
|
|
846
|
-
curr = curr[part];
|
|
847
|
-
prevPart = part;
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
return curr;
|
|
851
|
-
}
|
|
852
|
-
function defaultTransformer(context) {
|
|
853
|
-
const el = context.element;
|
|
854
|
-
const templates = context.templates;
|
|
855
|
-
const templatesCount = templates.length;
|
|
856
|
-
const path = context.path;
|
|
857
|
-
const value = context.value;
|
|
858
|
-
const attribute = this.options.attribute;
|
|
859
|
-
if (Array.isArray(value) && templates?.length) {
|
|
860
|
-
transformArrayByTemplates.call(this, context);
|
|
861
|
-
} else if (typeof value == "object" && templates?.length) {
|
|
862
|
-
transformObjectByTemplates.call(this, context);
|
|
863
|
-
} else if (templates?.length) {
|
|
864
|
-
transformLiteralByTemplates.call(this, context);
|
|
865
|
-
} else if (el.tagName == "INPUT") {
|
|
866
|
-
transformInput.call(this, context);
|
|
867
|
-
} else if (el.tagName == "BUTTON") {
|
|
868
|
-
transformButton.call(this, context);
|
|
869
|
-
} else if (el.tagName == "SELECT") {
|
|
870
|
-
transformSelect.call(this, context);
|
|
871
|
-
} else if (el.tagName == "A") {
|
|
872
|
-
transformAnchor.call(this, context);
|
|
873
|
-
} else {
|
|
874
|
-
transformElement.call(this, context);
|
|
875
|
-
}
|
|
876
|
-
return context;
|
|
877
|
-
}
|
|
878
|
-
function transformArrayByTemplates(context) {
|
|
879
|
-
const el = context.element;
|
|
880
|
-
const templates = context.templates;
|
|
881
|
-
const templatesCount = templates.length;
|
|
882
|
-
const path = context.path;
|
|
883
|
-
const value = context.value;
|
|
884
|
-
const attribute = this.options.attribute;
|
|
885
|
-
let items = el.querySelectorAll(":scope > [" + attribute + "-key]");
|
|
886
|
-
let lastKey = 0;
|
|
887
|
-
let skipped = 0;
|
|
888
|
-
context.list = value;
|
|
889
|
-
for (let item2 of items) {
|
|
890
|
-
let currentKey = parseInt(item2.getAttribute(attribute + "-key"));
|
|
891
|
-
if (currentKey > lastKey) {
|
|
892
|
-
context.index = lastKey;
|
|
893
|
-
el.insertBefore(this.applyTemplate(context), item2);
|
|
894
|
-
} else if (currentKey < lastKey) {
|
|
895
|
-
item2.remove();
|
|
896
|
-
} else {
|
|
897
|
-
let bindings = Array.from(item2.querySelectorAll(`[${attribute}]`));
|
|
898
|
-
if (item2.matches(`[${attribute}]`)) {
|
|
899
|
-
bindings.unshift(item2);
|
|
900
|
-
}
|
|
901
|
-
let needsReplacement = bindings.find((b) => {
|
|
902
|
-
let databind = b.getAttribute(attribute);
|
|
903
|
-
return databind.substr(0, 5) !== "#root" && databind.substr(0, path.length) !== path;
|
|
904
|
-
});
|
|
905
|
-
if (!needsReplacement) {
|
|
906
|
-
if (item2.$bindTemplate) {
|
|
907
|
-
let newTemplate = this.findTemplate(templates, value[lastKey]);
|
|
908
|
-
if (newTemplate != item2.$bindTemplate) {
|
|
909
|
-
needsReplacement = true;
|
|
910
|
-
if (!newTemplate) {
|
|
911
|
-
skipped++;
|
|
422
|
+
if (this[selectedKeyboard] && this[selectedKeyboard][keyString]) {
|
|
423
|
+
let targets = options.app.container.querySelectorAll('[data-simply-accesskey="' + keyboard + keyString + '"]');
|
|
424
|
+
if (targets.length) {
|
|
425
|
+
targets.forEach((t) => t.click());
|
|
426
|
+
e.preventDefault();
|
|
912
427
|
}
|
|
913
428
|
}
|
|
914
429
|
}
|
|
915
430
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
el.replaceChild(this.applyTemplate(context), item2);
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
lastKey++;
|
|
922
|
-
if (lastKey >= value.length) {
|
|
923
|
-
break;
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
items = el.querySelectorAll(":scope > [" + attribute + "-key]");
|
|
927
|
-
let length = items.length + skipped;
|
|
928
|
-
if (length > value.length) {
|
|
929
|
-
while (length > value.length) {
|
|
930
|
-
let child = el.querySelectorAll(":scope > :not(template)")?.[length - 1];
|
|
931
|
-
child?.remove();
|
|
932
|
-
length--;
|
|
933
|
-
}
|
|
934
|
-
} else if (length < value.length) {
|
|
935
|
-
while (length < value.length) {
|
|
936
|
-
context.index = length;
|
|
937
|
-
el.appendChild(this.applyTemplate(context));
|
|
938
|
-
length++;
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
function transformObjectByTemplates(context) {
|
|
943
|
-
const el = context.element;
|
|
944
|
-
const templates = context.templates;
|
|
945
|
-
const templatesCount = templates.length;
|
|
946
|
-
const path = context.path;
|
|
947
|
-
const value = context.value;
|
|
948
|
-
const attribute = this.options.attribute;
|
|
949
|
-
context.list = value;
|
|
950
|
-
let items = Array.from(el.querySelectorAll(":scope > [" + attribute + "-key]"));
|
|
951
|
-
for (let key in context.list) {
|
|
952
|
-
context.index = key;
|
|
953
|
-
let item2 = items.shift();
|
|
954
|
-
if (!item2) {
|
|
955
|
-
el.appendChild(this.applyTemplate(context));
|
|
956
|
-
continue;
|
|
957
|
-
}
|
|
958
|
-
if (item2.getAttribute[attribute + "-key"] != key) {
|
|
959
|
-
items.unshift(item2);
|
|
960
|
-
let outOfOrderItem = el.querySelector(":scope > [" + attribute + '-key="' + key + '"]');
|
|
961
|
-
if (!outOfOrderItem) {
|
|
962
|
-
let clone = this.applyTemplate(context);
|
|
963
|
-
if (clone.firstElementChild) {
|
|
964
|
-
el.insertBefore(clone, item2);
|
|
965
|
-
}
|
|
966
|
-
continue;
|
|
967
|
-
} else {
|
|
968
|
-
el.insertBefore(outOfOrderItem, item2);
|
|
969
|
-
item2 = outOfOrderItem;
|
|
970
|
-
items = items.filter((i) => i != outOfOrderItem);
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
let newTemplate = this.findTemplate(templates, value[key]);
|
|
974
|
-
if (newTemplate != item2.$bindTemplate) {
|
|
975
|
-
let clone = this.applyTemplate(context);
|
|
976
|
-
el.replaceChild(clone, item2);
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
while (items.length) {
|
|
980
|
-
item = items.shift();
|
|
981
|
-
item.remove();
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
function transformLiteralByTemplates(context) {
|
|
985
|
-
const el = context.element;
|
|
986
|
-
const templates = context.templates;
|
|
987
|
-
const value = context.value;
|
|
988
|
-
const attribute = this.options.attribute;
|
|
989
|
-
const rendered = el.querySelector(":scope > :not(template)");
|
|
990
|
-
const template = this.findTemplate(templates, value);
|
|
991
|
-
context.parent = el.parentElement?.closest(`[${attribute}]`)?.getAttribute(attribute) || "#root";
|
|
992
|
-
if (rendered) {
|
|
993
|
-
if (template) {
|
|
994
|
-
if (rendered?.$bindTemplate != template) {
|
|
995
|
-
const clone = this.applyTemplate(context);
|
|
996
|
-
el.replaceChild(clone, rendered);
|
|
997
|
-
}
|
|
998
|
-
} else {
|
|
999
|
-
el.removeChild(rendered);
|
|
1000
|
-
}
|
|
1001
|
-
} else if (template) {
|
|
1002
|
-
const clone = this.applyTemplate(context);
|
|
1003
|
-
el.appendChild(clone);
|
|
431
|
+
};
|
|
432
|
+
options.app.container.addEventListener("keydown", keyHandler);
|
|
1004
433
|
}
|
|
434
|
+
};
|
|
435
|
+
function keys(options = {}) {
|
|
436
|
+
return new SimplyKey(options);
|
|
1005
437
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
if (
|
|
1010
|
-
|
|
1011
|
-
|
|
438
|
+
|
|
439
|
+
// src/view.mjs
|
|
440
|
+
function view(options) {
|
|
441
|
+
if (options.app) {
|
|
442
|
+
options.app.view = options.view || {};
|
|
443
|
+
const load = () => {
|
|
444
|
+
const data = options.app.view;
|
|
445
|
+
const path = globalThis.editor.data.getDataPath(options.app.container || document.body);
|
|
446
|
+
options.app.view = globalThis.editor.currentData[path];
|
|
447
|
+
Object.assign(options.app.view, data);
|
|
448
|
+
};
|
|
449
|
+
if (globalThis.editor && globalThis.editor.currentData) {
|
|
450
|
+
load();
|
|
1012
451
|
} else {
|
|
1013
|
-
|
|
1014
|
-
}
|
|
1015
|
-
} else if (!matchValue(el.value, value)) {
|
|
1016
|
-
el.value = "" + value;
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
function transformButton(context) {
|
|
1020
|
-
const el = context.element;
|
|
1021
|
-
const value = context.value;
|
|
1022
|
-
if (!matchValue(el.value, value)) {
|
|
1023
|
-
el.value = "" + value;
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
function transformSelect(context) {
|
|
1027
|
-
const el = context.element;
|
|
1028
|
-
const value = context.value;
|
|
1029
|
-
if (el.multiple) {
|
|
1030
|
-
if (Array.isArray(value)) {
|
|
1031
|
-
for (let option of el.options) {
|
|
1032
|
-
if (value.indexOf(option.value) === false) {
|
|
1033
|
-
option.selected = false;
|
|
1034
|
-
} else {
|
|
1035
|
-
option.selected = true;
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
452
|
+
document.addEventListener("simply-content-loaded", load);
|
|
1038
453
|
}
|
|
454
|
+
return options.app.view;
|
|
1039
455
|
} else {
|
|
1040
|
-
|
|
1041
|
-
if (option) {
|
|
1042
|
-
option.selected = true;
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
function transformAnchor(context) {
|
|
1047
|
-
const el = context.element;
|
|
1048
|
-
const value = context.value;
|
|
1049
|
-
if (value?.innerHTML && !matchValue(el.innerHTML, value.innerHTML)) {
|
|
1050
|
-
el.innerHTML = "" + value.innerHTML;
|
|
1051
|
-
}
|
|
1052
|
-
if (value?.href && !matchValue(el.href, value.href)) {
|
|
1053
|
-
el.href = "" + value.href;
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
function transformElement(context) {
|
|
1057
|
-
const el = context.element;
|
|
1058
|
-
const value = context.value;
|
|
1059
|
-
if (!matchValue(el.innerHTML, value)) {
|
|
1060
|
-
if (typeof value == "undefined" || value == null) {
|
|
1061
|
-
el.innerHTML = "";
|
|
1062
|
-
} else {
|
|
1063
|
-
el.innerHTML = "" + value;
|
|
1064
|
-
}
|
|
456
|
+
return options.view;
|
|
1065
457
|
}
|
|
1066
458
|
}
|
|
1067
459
|
|
|
@@ -1069,30 +461,29 @@
|
|
|
1069
461
|
var SimplyApp = class {
|
|
1070
462
|
constructor(options = {}) {
|
|
1071
463
|
this.container = options.container || document.body;
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
464
|
+
for (let key in options) {
|
|
465
|
+
switch (key) {
|
|
466
|
+
case "commands":
|
|
467
|
+
this.commands = commands({ app: this, container: this.container, commands: options.commands });
|
|
468
|
+
break;
|
|
469
|
+
case "keys":
|
|
470
|
+
case "keyboard":
|
|
471
|
+
this.keys = keys({ app: this, keys: options.keys });
|
|
472
|
+
break;
|
|
473
|
+
case "routes":
|
|
474
|
+
this.routes = routes({ app: this, routes: options.routes });
|
|
475
|
+
break;
|
|
476
|
+
case "actions":
|
|
477
|
+
this.actions = actions({ app: this, actions: options.actions });
|
|
478
|
+
break;
|
|
479
|
+
case "view":
|
|
480
|
+
this.view = view({ app: this, view: options.view });
|
|
481
|
+
break;
|
|
482
|
+
default:
|
|
483
|
+
this[key] = options[key];
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
1094
486
|
}
|
|
1095
|
-
this.bind = bind(bindOptions);
|
|
1096
487
|
}
|
|
1097
488
|
};
|
|
1098
489
|
function app(options = {}) {
|