simplyview 2.1.1 → 3.0.1
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/dist/simply.app.js +1120 -0
- package/dist/simply.app.js.map +7 -0
- package/dist/simply.app.min.js +2 -0
- package/dist/simply.app.min.js.map +7 -0
- package/dist/simply.everything.js +1583 -2013
- package/dist/simply.everything.js.map +7 -0
- package/dist/simply.everything.min.js +2 -0
- package/dist/simply.everything.min.js.map +7 -0
- package/package.json +10 -4
- package/src/action.mjs +12 -0
- package/src/activate.mjs +63 -0
- package/src/app.mjs +40 -0
- package/src/bind.mjs +572 -0
- package/src/changes.md +18 -0
- package/src/command.mjs +125 -0
- package/src/everything.mjs +27 -0
- package/src/include.mjs +191 -0
- package/src/key.mjs +55 -0
- package/src/model.mjs +151 -0
- package/src/route.mjs +222 -0
- package/src/state.mjs +536 -0
- package/js/.eslintrc.json +0 -29
- package/js/simply.action.js +0 -115
- package/js/simply.activate.js +0 -79
- package/js/simply.api.js +0 -228
- package/js/simply.app.js +0 -63
- package/js/simply.collect.js +0 -72
- package/js/simply.command.js +0 -196
- package/js/simply.include.js +0 -216
- package/js/simply.keyboard.js +0 -62
- package/js/simply.modules.js +0 -22
- package/js/simply.observe.js +0 -349
- package/js/simply.path.js +0 -48
- package/js/simply.render.js +0 -125
- package/js/simply.resize.js +0 -80
- package/js/simply.route.js +0 -234
- package/js/simply.view.js +0 -35
- package/js/simply.viewmodel.js +0 -189
- /package/{js/simply.include.next.js → src/include.next.js} +0 -0
|
@@ -1,2088 +1,1658 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
*
|
|
26
|
-
* The sourcePath contains the exact entry that was changed, the value is the
|
|
27
|
-
* value for the path passed to simply.observe.
|
|
28
|
-
* If an array method was called that changes the array in place, the sourcePath
|
|
29
|
-
* also contains that method and its arguments JSON serialized.
|
|
30
|
-
*
|
|
31
|
-
* sourcePath parts are always seperated with '.', even for array indexes.
|
|
32
|
-
* so if foo = [ 'bar' ], the path to 'bar' would be 'foo.0'
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
/*
|
|
36
|
-
FIXME: child properties added after initial observe() call aren't added to the
|
|
37
|
-
childListeners. onMissingChildren can't then find them.
|
|
38
|
-
TODO: onMissingChildren must loop through all fields to get only the direct child
|
|
39
|
-
properties for a given parent, keep seperate index for this?
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
(function (global) {
|
|
43
|
-
'use strict';
|
|
44
|
-
|
|
45
|
-
var changeListeners = new WeakMap();
|
|
46
|
-
var parentListeners = new WeakMap();
|
|
47
|
-
var childListeners = new WeakMap();
|
|
48
|
-
var changesSignalled = {};
|
|
49
|
-
var observersPaused = 0;
|
|
50
|
-
|
|
51
|
-
function signalChange(model, path, value, sourcePath) {
|
|
52
|
-
if (observersPaused) {
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
sourcePath = sourcePath ? sourcePath : path;
|
|
57
|
-
changesSignalled = {};
|
|
58
|
-
|
|
59
|
-
var signalRecursion = function(model, path, value, sourcePath) {
|
|
60
|
-
if (changeListeners.has(model) && changeListeners.get(model)[path]) {
|
|
61
|
-
// changeListeners[model][path] contains callback methods
|
|
62
|
-
changeListeners.get(model)[path].forEach(function(callback) {
|
|
63
|
-
changesSignalled[path] = true;
|
|
64
|
-
callback(value, sourcePath);
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
//TODO: check if this is correct
|
|
70
|
-
//previous version only triggered parentListeners when no changeListeners were
|
|
71
|
-
//triggered. that created problems with arrays. make an exhaustive unit test.
|
|
72
|
-
signalRecursion(model, path, value, sourcePath);
|
|
73
|
-
|
|
74
|
-
if (parentListeners.has(model) && parentListeners.get(model)[path]) {
|
|
75
|
-
// parentListeners[model][path] contains child paths to signal change on
|
|
76
|
-
// if a parent object is changed, this signals the change to the child objects
|
|
77
|
-
parentListeners.get(model)[path].forEach(function(childPath) {
|
|
78
|
-
if (!changesSignalled[childPath]) {
|
|
79
|
-
var value = getByPath(model, childPath);
|
|
80
|
-
if (value) {
|
|
81
|
-
attach(model, childPath);
|
|
82
|
-
}
|
|
83
|
-
signalRecursion(model, childPath, value, sourcePath);
|
|
84
|
-
changesSignalled[childPath] = true;
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (childListeners.has(model) && childListeners.get(model)[path]) {
|
|
90
|
-
// childListeners[model][path] contains parent paths to signal change on
|
|
91
|
-
// if a child object is changed, this signals the change to the parent objects
|
|
92
|
-
childListeners.get(model)[path].forEach(function(parentPath) {
|
|
93
|
-
if (!changesSignalled[parentPath]) {
|
|
94
|
-
var value = getByPath(model, parentPath);
|
|
95
|
-
signalRecursion(model, parentPath, value, sourcePath);
|
|
96
|
-
changesSignalled[parentPath] = true;
|
|
97
|
-
// check if the parent object still has this child property
|
|
98
|
-
//FIXME: add a setter trigger here to restore observers once the child property get set again
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
1
|
+
(() => {
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __export = (target, all) => {
|
|
4
|
+
for (var name in all)
|
|
5
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// src/activate.mjs
|
|
9
|
+
var listeners = /* @__PURE__ */ new Map();
|
|
10
|
+
var activate = {
|
|
11
|
+
addListener: (name, callback) => {
|
|
12
|
+
if (!listeners.has(name)) {
|
|
13
|
+
listeners.set(name, []);
|
|
14
|
+
}
|
|
15
|
+
listeners.get(name).push(callback);
|
|
16
|
+
initialCall(name);
|
|
17
|
+
},
|
|
18
|
+
removeListener: (name, callback) => {
|
|
19
|
+
if (!listeners.has(name)) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
listeners.set(name, listeners.get(name).filter((listener) => {
|
|
23
|
+
return listener != callback;
|
|
24
|
+
}));
|
|
104
25
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return curr;
|
|
26
|
+
};
|
|
27
|
+
function initialCall(name) {
|
|
28
|
+
const nodes = document.querySelectorAll('[data-simply-activate="' + name + '"]');
|
|
29
|
+
if (nodes) {
|
|
30
|
+
for (let node of nodes) {
|
|
31
|
+
callListeners(node);
|
|
32
|
+
}
|
|
113
33
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
34
|
+
}
|
|
35
|
+
function callListeners(node) {
|
|
36
|
+
const activate2 = node?.dataset?.simplyActivate;
|
|
37
|
+
if (activate2 && listeners.has(activate2)) {
|
|
38
|
+
for (let callback of listeners.get(activate2)) {
|
|
39
|
+
callback.call(node);
|
|
40
|
+
}
|
|
119
41
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
42
|
+
}
|
|
43
|
+
function handleChanges(changes) {
|
|
44
|
+
let activateNodes = [];
|
|
45
|
+
for (let change of changes) {
|
|
46
|
+
if (change.type == "childList") {
|
|
47
|
+
for (let node of change.addedNodes) {
|
|
48
|
+
if (node.querySelectorAll) {
|
|
49
|
+
var toActivate = Array.from(node.querySelectorAll("[data-simply-activate]"));
|
|
50
|
+
if (node.matches("[data-simply-activate]")) {
|
|
51
|
+
toActivate.push(node);
|
|
52
|
+
}
|
|
53
|
+
activateNodes = activateNodes.concat(toActivate);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
123
57
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
var parent = '';
|
|
127
|
-
var parentOb = model;
|
|
128
|
-
var parents = path.split('.');
|
|
129
|
-
do {
|
|
130
|
-
var head = parents.shift();
|
|
131
|
-
if (parentOb && typeof parentOb[head] != 'undefined') {
|
|
132
|
-
callback(parentOb, head, (parent ? parent + '.' + head : head));
|
|
133
|
-
parentOb = parentOb[head];
|
|
134
|
-
}
|
|
135
|
-
parent = (parent ? parent + '.' + head : head );
|
|
136
|
-
} while (parents.length);
|
|
58
|
+
for (let node of activateNodes) {
|
|
59
|
+
callListeners(node);
|
|
137
60
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
61
|
+
}
|
|
62
|
+
var observer = new MutationObserver(handleChanges);
|
|
63
|
+
observer.observe(document, {
|
|
64
|
+
subtree: true,
|
|
65
|
+
childList: true
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// src/action.mjs
|
|
69
|
+
var action_exports = {};
|
|
70
|
+
__export(action_exports, {
|
|
71
|
+
actions: () => actions
|
|
72
|
+
});
|
|
73
|
+
function actions(options) {
|
|
74
|
+
if (options.app) {
|
|
75
|
+
const actionHandler = {
|
|
76
|
+
get: (target, property) => {
|
|
77
|
+
return target[property].bind(options.app);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
return new Proxy(options.actions, actionHandler);
|
|
81
|
+
} else {
|
|
82
|
+
return options;
|
|
155
83
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
onMissingChildren(model, path+'.'+key, callback);
|
|
175
|
-
}
|
|
176
|
-
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/route.mjs
|
|
87
|
+
var route_exports = {};
|
|
88
|
+
__export(route_exports, {
|
|
89
|
+
routes: () => routes
|
|
90
|
+
});
|
|
91
|
+
function routes(options) {
|
|
92
|
+
return new SimplyRoute(options);
|
|
93
|
+
}
|
|
94
|
+
var SimplyRoute = class {
|
|
95
|
+
constructor(options = {}) {
|
|
96
|
+
this.root = options.root || "/";
|
|
97
|
+
this.app = options.app;
|
|
98
|
+
this.clear();
|
|
99
|
+
if (options.routes) {
|
|
100
|
+
this.load(options.routes);
|
|
101
|
+
}
|
|
177
102
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
103
|
+
load(routes2) {
|
|
104
|
+
parseRoutes(routes2, this.routeInfo);
|
|
105
|
+
}
|
|
106
|
+
clear() {
|
|
107
|
+
this.routeInfo = [];
|
|
108
|
+
this.listeners = {
|
|
109
|
+
match: {},
|
|
110
|
+
call: {},
|
|
111
|
+
finish: {}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
match(path, options) {
|
|
115
|
+
let args = {
|
|
116
|
+
path,
|
|
117
|
+
options
|
|
118
|
+
};
|
|
119
|
+
args = this.runListeners("match", args);
|
|
120
|
+
path = args.path ? args.path : path;
|
|
121
|
+
let matches;
|
|
122
|
+
if (!path) {
|
|
123
|
+
if (this.match(document.location.pathname + document.location.hash)) {
|
|
124
|
+
return true;
|
|
125
|
+
} else {
|
|
126
|
+
return this.match(document.location.pathname);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
path = getPath(path);
|
|
130
|
+
for (let route of this.routeInfo) {
|
|
131
|
+
matches = route.match.exec(path);
|
|
132
|
+
if (matches && matches.length) {
|
|
133
|
+
var params = {};
|
|
134
|
+
route.params.forEach((key, i) => {
|
|
135
|
+
if (key == "*") {
|
|
136
|
+
key = "remainder";
|
|
137
|
+
}
|
|
138
|
+
params[key] = matches[i + 1];
|
|
139
|
+
});
|
|
140
|
+
Object.assign(params, options);
|
|
141
|
+
args.route = route;
|
|
142
|
+
args.params = params;
|
|
143
|
+
args = this.runListeners("call", args);
|
|
144
|
+
params = args.params ? args.params : params;
|
|
145
|
+
args.result = route.action.call(route, params);
|
|
146
|
+
this.runListeners("finish", args);
|
|
147
|
+
return args.result;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (path && path[path.length - 1] != "/") {
|
|
151
|
+
return this.match(path + "/", options);
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
runListeners(action, params) {
|
|
156
|
+
if (!Object.keys(this.listeners[action])) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
Object.keys(this.listeners[action]).forEach((route) => {
|
|
160
|
+
var routeRe = getRegexpFromRoute(route);
|
|
161
|
+
if (routeRe.exec(params.path)) {
|
|
162
|
+
var result;
|
|
163
|
+
for (let callback of this.listeners[action][route]) {
|
|
164
|
+
result = callback.call(this.app, params);
|
|
165
|
+
if (result) {
|
|
166
|
+
params = result;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
return params;
|
|
172
|
+
}
|
|
173
|
+
handleEvents() {
|
|
174
|
+
globalThis.addEventListener("popstate", () => {
|
|
175
|
+
if (this.match(getPath(document.location.pathname + document.location.hash, this.root)) === false) {
|
|
176
|
+
this.match(getPath(document.location.pathname, this.root));
|
|
182
177
|
}
|
|
183
|
-
|
|
184
|
-
|
|
178
|
+
});
|
|
179
|
+
globalThis.document.addEventListener("click", (evt) => {
|
|
180
|
+
if (evt.ctrlKey) {
|
|
181
|
+
return;
|
|
185
182
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (!parentListeners.has(model)) {
|
|
189
|
-
parentListeners.set(model, {});
|
|
183
|
+
if (evt.which != 1) {
|
|
184
|
+
return;
|
|
190
185
|
}
|
|
191
|
-
var
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
186
|
+
var link = evt.target;
|
|
187
|
+
while (link && link.tagName != "A") {
|
|
188
|
+
link = link.parentElement;
|
|
189
|
+
}
|
|
190
|
+
if (link && link.pathname && link.hostname == globalThis.location.hostname && !link.link && !link.dataset.simplyCommand) {
|
|
191
|
+
let path = getPath(link.pathname + link.hash, this.root);
|
|
192
|
+
if (!this.has(path)) {
|
|
193
|
+
path = getPath(link.pathname, this.root);
|
|
194
|
+
}
|
|
195
|
+
if (this.has(path)) {
|
|
196
|
+
let params = this.runListeners("goto", { path });
|
|
197
|
+
if (params.path) {
|
|
198
|
+
this.goto(params.path);
|
|
199
|
+
}
|
|
200
|
+
evt.preventDefault();
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
201
203
|
}
|
|
202
|
-
|
|
203
|
-
if (!childListeners.get(model)[currPath]) {
|
|
204
|
-
childListeners.get(model)[currPath] = [];
|
|
205
|
-
}
|
|
206
|
-
childListeners.get(model)[currPath].push(path);
|
|
207
|
-
});
|
|
204
|
+
});
|
|
208
205
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
if (changeListeners.get(model)[path]) {
|
|
215
|
-
changeListeners.get(model)[path] = changeListeners.get(model)[path].filter(function(f) {
|
|
216
|
-
return f != callback;
|
|
217
|
-
});
|
|
218
|
-
}
|
|
206
|
+
goto(path) {
|
|
207
|
+
history.pushState({}, "", getURL(path));
|
|
208
|
+
return this.match(path);
|
|
219
209
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
210
|
+
has(path) {
|
|
211
|
+
path = getPath(path, this.root);
|
|
212
|
+
for (let route of this.routeInfo) {
|
|
213
|
+
var matches = route.match.exec(path);
|
|
214
|
+
if (matches && matches.length) {
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return false;
|
|
223
219
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
220
|
+
addListener(action, route, callback) {
|
|
221
|
+
if (["goto", "match", "call", "finish"].indexOf(action) == -1) {
|
|
222
|
+
throw new Error("Unknown action " + action);
|
|
223
|
+
}
|
|
224
|
+
if (!this.listeners[action][route]) {
|
|
225
|
+
this.listeners[action][route] = [];
|
|
226
|
+
}
|
|
227
|
+
this.listeners[action][route].push(callback);
|
|
227
228
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
value: function() {
|
|
239
|
-
pauseObservers();
|
|
240
|
-
var result = Array.prototype[f].apply(this, arguments);
|
|
241
|
-
attach(model, path);
|
|
242
|
-
var args = [].slice.call(arguments).map(function(arg) {
|
|
243
|
-
return JSON.stringify(arg);
|
|
244
|
-
});
|
|
245
|
-
resumeObservers();
|
|
246
|
-
signalChange(model, path, this, path+'.'+f+'('+args.join(',')+')');
|
|
247
|
-
return result;
|
|
248
|
-
},
|
|
249
|
-
readable: false,
|
|
250
|
-
enumerable: false,
|
|
251
|
-
configurable: false
|
|
252
|
-
});
|
|
253
|
-
} catch(e) {
|
|
254
|
-
console.error('simply.observer: Error: Couldn\'t redefine array method '+f+' on '+path, e);
|
|
255
|
-
}
|
|
256
|
-
}(f));
|
|
257
|
-
}
|
|
258
|
-
for (var i=0, l=object.length; i<l; i++) {
|
|
259
|
-
//FIXME: options becomes undefined here somewhere
|
|
260
|
-
// if (options.skipArray) {
|
|
261
|
-
addSetter(object, i, path+'.'+i);
|
|
262
|
-
// } else {
|
|
263
|
-
// attach(model, path+'.'+i, options);
|
|
264
|
-
// }
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
var addSetTrigger = function(object, key, currPath) {
|
|
270
|
-
Object.defineProperty(object, key, {
|
|
271
|
-
set: function(value) {
|
|
272
|
-
addSetter(object, key, currPath);
|
|
273
|
-
object[key] = value;
|
|
274
|
-
},
|
|
275
|
-
configurable: true,
|
|
276
|
-
readable: false,
|
|
277
|
-
enumerable: false
|
|
278
|
-
});
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
var addSetter = function(object, key, currPath) {
|
|
282
|
-
if (Object.getOwnPropertyDescriptor(object, key).configurable) {
|
|
283
|
-
// assume object keys are only unconfigurable if the
|
|
284
|
-
// following code has already been run on this property
|
|
285
|
-
var _value = object[key];
|
|
286
|
-
Object.defineProperty(object, key, {
|
|
287
|
-
set: function(value) {
|
|
288
|
-
_value = value;
|
|
289
|
-
signalChange(model, currPath, value);
|
|
290
|
-
if (value!=null) {
|
|
291
|
-
onChildren(model, currPath, addSetter);
|
|
292
|
-
onMissingChildren(model, currPath, addSetTrigger);
|
|
293
|
-
}
|
|
294
|
-
},
|
|
295
|
-
get: function() {
|
|
296
|
-
return _value;
|
|
297
|
-
},
|
|
298
|
-
configurable: false,
|
|
299
|
-
readable: true,
|
|
300
|
-
enumerable: true
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
if (Array.isArray(object[key])) {
|
|
304
|
-
attachArray(object[key], currPath, options);
|
|
305
|
-
}
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
onParents(model, path, addSetter);
|
|
309
|
-
onChildren(model, path, addSetter);
|
|
229
|
+
removeListener(action, route, callback) {
|
|
230
|
+
if (["match", "call", "finish"].indexOf(action) == -1) {
|
|
231
|
+
throw new Error("Unknown action " + action);
|
|
232
|
+
}
|
|
233
|
+
if (!this.listeners[action][route]) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
this.listeners[action][route] = this.listeners[action][route].filter((listener) => {
|
|
237
|
+
return listener != callback;
|
|
238
|
+
});
|
|
310
239
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
// var model = { foo: { bar: 'baz' } };
|
|
316
|
-
// simply.observer(model, 'foo.bar', ...)
|
|
317
|
-
// model.foo = { }
|
|
318
|
-
// model.foo.bar = 'zab'; // this should trigger the observer but doesn't
|
|
319
|
-
|
|
320
|
-
var observe = function(model, path, callback, options) {
|
|
321
|
-
if (!path) {
|
|
322
|
-
var keys = Object.keys(model);
|
|
323
|
-
keys.forEach(function(key) {
|
|
324
|
-
attach(model, key, options);
|
|
325
|
-
addChangeListener(model, key, callback);
|
|
326
|
-
});
|
|
327
|
-
return function() {
|
|
328
|
-
keys.forEach(function(key) {
|
|
329
|
-
removeChangeListener(model, key, callback);
|
|
330
|
-
});
|
|
331
|
-
};
|
|
332
|
-
} else {
|
|
333
|
-
attach(model, path, options);
|
|
334
|
-
addChangeListener(model, path, callback);
|
|
335
|
-
return function() {
|
|
336
|
-
removeChangeListener(model, path, callback);
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
342
|
-
module.exports = observe;
|
|
343
|
-
} else {
|
|
344
|
-
if (!global.simply) {
|
|
345
|
-
global.simply = {};
|
|
346
|
-
}
|
|
347
|
-
global.simply.observe = observe;
|
|
240
|
+
init(options) {
|
|
241
|
+
if (options.root) {
|
|
242
|
+
this.root = options.root;
|
|
243
|
+
}
|
|
348
244
|
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
if (!options) {
|
|
354
|
-
options = {};
|
|
355
|
-
}
|
|
356
|
-
options = Object.assign({
|
|
357
|
-
attribute: 'data-simply-field',
|
|
358
|
-
selector: '[data-simply-field]',
|
|
359
|
-
twoway: true,
|
|
360
|
-
model: {}
|
|
361
|
-
}, options);
|
|
362
|
-
|
|
363
|
-
options.fieldTypes = Object.assign({
|
|
364
|
-
'*': {
|
|
365
|
-
set: function(value) {
|
|
366
|
-
this.innerHTML = value;
|
|
367
|
-
},
|
|
368
|
-
get: function() {
|
|
369
|
-
return this.innerHTML;
|
|
370
|
-
}
|
|
371
|
-
},
|
|
372
|
-
'input,textarea,select': {
|
|
373
|
-
init: function(binding) {
|
|
374
|
-
this.addEventListener('input', function() {
|
|
375
|
-
if (binding.observing) {
|
|
376
|
-
this.dispatchEvent(new Event('simply.bind.update', {
|
|
377
|
-
bubbles: true,
|
|
378
|
-
cancelable: true
|
|
379
|
-
}));
|
|
380
|
-
}
|
|
381
|
-
});
|
|
382
|
-
},
|
|
383
|
-
set: function(value) {
|
|
384
|
-
this.value = value;
|
|
385
|
-
},
|
|
386
|
-
get: function() {
|
|
387
|
-
return this.value;
|
|
388
|
-
}
|
|
389
|
-
},
|
|
390
|
-
'input[type=radio]': {
|
|
391
|
-
init: function(binding) {
|
|
392
|
-
this.addEventListener('change', function() {
|
|
393
|
-
if (binding.observing) {
|
|
394
|
-
this.dispatchEvent(new Event('simply.bind.update', {
|
|
395
|
-
bubbles: true,
|
|
396
|
-
cancelable: true
|
|
397
|
-
}));
|
|
398
|
-
}
|
|
399
|
-
});
|
|
400
|
-
},
|
|
401
|
-
set: function(value) {
|
|
402
|
-
this.checked = (value==this.value);
|
|
403
|
-
},
|
|
404
|
-
get: function() {
|
|
405
|
-
var checked;
|
|
406
|
-
if (this.form) {
|
|
407
|
-
return this.form[this.name].value;
|
|
408
|
-
} else if (checked=document.body.querySelector('input[name="'+this.name+'"][checked]')) {
|
|
409
|
-
return checked.value;
|
|
410
|
-
} else {
|
|
411
|
-
return null;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
},
|
|
415
|
-
'input[type=checkbox]': {
|
|
416
|
-
init: function(binding) {
|
|
417
|
-
this.addEventListener('change', function() {
|
|
418
|
-
if (binding.observing) {
|
|
419
|
-
this.dispatchEvent(new Event('simply.bind.update', {
|
|
420
|
-
bubbles: true,
|
|
421
|
-
cancelable: true
|
|
422
|
-
}));
|
|
423
|
-
}
|
|
424
|
-
});
|
|
425
|
-
},
|
|
426
|
-
set: function(value) {
|
|
427
|
-
this.checked = (value.checked);
|
|
428
|
-
this.value = value.value;
|
|
429
|
-
},
|
|
430
|
-
get: function() {
|
|
431
|
-
return {
|
|
432
|
-
checked: this.checked,
|
|
433
|
-
value: this.value
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
},
|
|
437
|
-
'select[multiple]': {
|
|
438
|
-
init: function(binding) {
|
|
439
|
-
this.addEventListener('change', function() {
|
|
440
|
-
if (binding.observing) {
|
|
441
|
-
this.dispatchEvent(new Event('simply.bind.update', {
|
|
442
|
-
bubbles: true,
|
|
443
|
-
cancelable: true
|
|
444
|
-
}));
|
|
445
|
-
}
|
|
446
|
-
});
|
|
447
|
-
},
|
|
448
|
-
set: function(value) {
|
|
449
|
-
for (var i=0,l=this.options.length;i<l;i++) {
|
|
450
|
-
this.options[i].selected = (value.indexOf(this.options[i].value)>=0);
|
|
451
|
-
}
|
|
452
|
-
},
|
|
453
|
-
get: function() {
|
|
454
|
-
return this.value;
|
|
455
|
-
}
|
|
456
|
-
},
|
|
457
|
-
// '[data-simply-content="template"]': {
|
|
458
|
-
// allowNesting: true
|
|
459
|
-
// },
|
|
460
|
-
}, options.fieldTypes);
|
|
461
|
-
|
|
462
|
-
return options;
|
|
463
|
-
};
|
|
464
|
-
|
|
465
|
-
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
466
|
-
module.exports = render;
|
|
467
|
-
} else {
|
|
468
|
-
if (!global.simply) {
|
|
469
|
-
global.simply = {};
|
|
470
|
-
}
|
|
471
|
-
global.simply.render = render;
|
|
245
|
+
};
|
|
246
|
+
function getPath(path, root = "/") {
|
|
247
|
+
if (path.substring(0, root.length) == root || root[root.length - 1] == "/" && path.length == root.length - 1 && path == root.substring(0, path.length)) {
|
|
248
|
+
path = path.substring(root.length);
|
|
472
249
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
'us strict';
|
|
476
|
-
|
|
477
|
-
var path = {
|
|
478
|
-
get: function(model, path) {
|
|
479
|
-
if (!path) {
|
|
480
|
-
return model;
|
|
481
|
-
}
|
|
482
|
-
return path.split('.').reduce(function(acc, name) {
|
|
483
|
-
return (acc && acc[name] ? acc[name] : null);
|
|
484
|
-
}, model);
|
|
485
|
-
},
|
|
486
|
-
set: function(model, path, value) {
|
|
487
|
-
var lastName = simply.path.pop(path);
|
|
488
|
-
var parentPath = simply.path.parent(path);
|
|
489
|
-
var parentOb = simply.path.get(model, parentPath);
|
|
490
|
-
parentOb[lastName] = value;
|
|
491
|
-
},
|
|
492
|
-
pop: function(path) {
|
|
493
|
-
return path.split('.').pop();
|
|
494
|
-
},
|
|
495
|
-
push: function(path, name) {
|
|
496
|
-
return (path ? path + '.' : '') + name;
|
|
497
|
-
},
|
|
498
|
-
parent: function(path) {
|
|
499
|
-
var p = path.split('.');
|
|
500
|
-
p.pop();
|
|
501
|
-
return p.join('.');
|
|
502
|
-
},
|
|
503
|
-
parents: function(path) {
|
|
504
|
-
var result = [];
|
|
505
|
-
path.split('.').reduce(function(acc, name) {
|
|
506
|
-
acc.push( (acc.length ? acc[acc.length-1] + '.' : '') + name );
|
|
507
|
-
return acc;
|
|
508
|
-
},result);
|
|
509
|
-
return result;
|
|
510
|
-
}
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
514
|
-
module.exports = path;
|
|
515
|
-
} else {
|
|
516
|
-
if (!global.simply) {
|
|
517
|
-
global.simply = {};
|
|
518
|
-
}
|
|
519
|
-
global.simply.path = path;
|
|
250
|
+
if (path[0] != "/" && path[0] != "#") {
|
|
251
|
+
path = "/" + path;
|
|
520
252
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
goto: {},
|
|
528
|
-
match: {},
|
|
529
|
-
call: {},
|
|
530
|
-
finish: {}
|
|
531
|
-
};
|
|
532
|
-
|
|
533
|
-
function getRegexpFromRoute(route) {
|
|
534
|
-
return new RegExp('^'+route.replace(/:\w+/g, '([^/]+)').replace(/:\*/, '(.*)'));
|
|
253
|
+
return path;
|
|
254
|
+
}
|
|
255
|
+
function getURL(path, root) {
|
|
256
|
+
path = getPath(path, root);
|
|
257
|
+
if (root[root.length - 1] === "/" && path[0] === "/") {
|
|
258
|
+
path = path.substring(1);
|
|
535
259
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
260
|
+
return root + path;
|
|
261
|
+
}
|
|
262
|
+
function getRegexpFromRoute(route) {
|
|
263
|
+
return new RegExp("^" + route.replace(/:\w+/g, "([^/]+)").replace(/:\*/, "(.*)"));
|
|
264
|
+
}
|
|
265
|
+
function parseRoutes(routes2) {
|
|
266
|
+
let routeInfo = [];
|
|
267
|
+
const paths = Object.keys(routes2);
|
|
268
|
+
const matchParams = /:(\w+|\*)/g;
|
|
269
|
+
for (let path of paths) {
|
|
270
|
+
let matches = [];
|
|
271
|
+
let params = [];
|
|
272
|
+
do {
|
|
273
|
+
matches = matchParams.exec(path);
|
|
274
|
+
if (matches) {
|
|
275
|
+
params.push(matches[1]);
|
|
276
|
+
}
|
|
277
|
+
} while (matches);
|
|
278
|
+
routeInfo.push({
|
|
279
|
+
match: getRegexpFromRoute(path),
|
|
280
|
+
params,
|
|
281
|
+
action: routes2[path]
|
|
282
|
+
});
|
|
557
283
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
( options.root[options.root.length-1]=='/'
|
|
599
|
-
&& path.length==(options.root.length-1)
|
|
600
|
-
&& path == options.root.substring(0,path.length)
|
|
601
|
-
)
|
|
602
|
-
) {
|
|
603
|
-
path = path.substring(options.root.length);
|
|
604
|
-
}
|
|
605
|
-
if (path[0]!='/' && path[0]!='#') {
|
|
606
|
-
path = '/'+path;
|
|
607
|
-
}
|
|
608
|
-
return path;
|
|
609
|
-
};
|
|
610
|
-
|
|
611
|
-
var getUrl = function(path) {
|
|
612
|
-
path = getPath(path);
|
|
613
|
-
if (options.root[options.root.length-1]==='/' && path[0]==='/') {
|
|
614
|
-
path = path.substring(1);
|
|
615
|
-
}
|
|
616
|
-
return options.root + path;
|
|
617
|
-
};
|
|
618
|
-
|
|
619
|
-
function runListeners(action, params) {
|
|
620
|
-
if (!Object.keys(listeners[action])) {
|
|
621
|
-
return;
|
|
622
|
-
}
|
|
623
|
-
Object.keys(listeners[action]).forEach(function(route) {
|
|
624
|
-
var routeRe = getRegexpFromRoute(route);
|
|
625
|
-
if (routeRe.exec(params.path)) {
|
|
626
|
-
var result;
|
|
627
|
-
listeners[action][route].forEach(function(callback) {
|
|
628
|
-
result = callback.call(global, params);
|
|
629
|
-
if (result) {
|
|
630
|
-
params = result;
|
|
631
|
-
}
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
});
|
|
635
|
-
return params;
|
|
284
|
+
return routeInfo;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// src/command.mjs
|
|
288
|
+
var command_exports = {};
|
|
289
|
+
__export(command_exports, {
|
|
290
|
+
commands: () => commands
|
|
291
|
+
});
|
|
292
|
+
var SimplyCommands = class {
|
|
293
|
+
constructor(options = {}) {
|
|
294
|
+
if (!options.app) {
|
|
295
|
+
options.app = {};
|
|
296
|
+
}
|
|
297
|
+
if (!options.app.container) {
|
|
298
|
+
options.app.container = document.body;
|
|
299
|
+
}
|
|
300
|
+
this.$handlers = options.handlers || defaultHandlers;
|
|
301
|
+
if (options.commands) {
|
|
302
|
+
Object.assign(this, options.commands);
|
|
303
|
+
}
|
|
304
|
+
const commandHandler = (evt) => {
|
|
305
|
+
const command = getCommand(evt, this.$handlers);
|
|
306
|
+
if (!command) {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (!this[command.name]) {
|
|
310
|
+
console.error("simply.command: undefined command " + command.name, command.source);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const shouldContinue = this[command.name].call(options.app, command.source, command.value);
|
|
314
|
+
if (shouldContinue === false) {
|
|
315
|
+
evt.preventDefault();
|
|
316
|
+
evt.stopPropagation();
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
options.app.container.addEventListener("click", commandHandler);
|
|
321
|
+
options.app.container.addEventListener("submit", commandHandler);
|
|
322
|
+
options.app.container.addEventListener("change", commandHandler);
|
|
323
|
+
options.app.container.addEventListener("input", commandHandler);
|
|
636
324
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
routeInfo = [];
|
|
652
|
-
listeners = {
|
|
653
|
-
match: {},
|
|
654
|
-
call: {},
|
|
655
|
-
finish: {}
|
|
325
|
+
};
|
|
326
|
+
function commands(options = {}) {
|
|
327
|
+
return new SimplyCommands(options);
|
|
328
|
+
}
|
|
329
|
+
function getCommand(evt, handlers) {
|
|
330
|
+
var el = evt.target.closest("[data-simply-command]");
|
|
331
|
+
if (el) {
|
|
332
|
+
for (let handler of handlers) {
|
|
333
|
+
if (el.matches(handler.match)) {
|
|
334
|
+
if (handler.check(el, evt)) {
|
|
335
|
+
return {
|
|
336
|
+
name: el.dataset.simplyCommand,
|
|
337
|
+
source: el,
|
|
338
|
+
value: handler.get(el)
|
|
656
339
|
};
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
var args = {
|
|
660
|
-
path: path,
|
|
661
|
-
options: options
|
|
662
|
-
};
|
|
663
|
-
args = runListeners('match',args);
|
|
664
|
-
path = args.path ? args.path : path;
|
|
665
|
-
|
|
666
|
-
var matches;
|
|
667
|
-
if (!path) {
|
|
668
|
-
if (route.match(document.location.pathname+document.location.hash)) {
|
|
669
|
-
return true;
|
|
670
|
-
} else {
|
|
671
|
-
return route.match(document.location.pathname);
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
path = getPath(path);
|
|
675
|
-
for ( var i=0; i<routeInfo.length; i++) {
|
|
676
|
-
matches = routeInfo[i].match.exec(path);
|
|
677
|
-
if (!matches || !matches.length) {
|
|
678
|
-
if (path && path[path.length-1]!='/') {
|
|
679
|
-
matches = routeInfo[i].match.exec(path+'/');
|
|
680
|
-
if (matches) {
|
|
681
|
-
path+='/';
|
|
682
|
-
history.replaceState({}, '', getUrl(path));
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
if (matches && matches.length) {
|
|
687
|
-
var params = {};
|
|
688
|
-
routeInfo[i].params.forEach(function(key, i) {
|
|
689
|
-
if (key=='*') {
|
|
690
|
-
key = 'remainder';
|
|
691
|
-
}
|
|
692
|
-
params[key] = matches[i+1];
|
|
693
|
-
});
|
|
694
|
-
Object.assign(params, options);
|
|
695
|
-
args.route = route;
|
|
696
|
-
args.params = params;
|
|
697
|
-
args = runListeners('call', args);
|
|
698
|
-
params = args.params ? args.params : params;
|
|
699
|
-
args.result = routeInfo[i].action.call(route, params);
|
|
700
|
-
runListeners('finish', args);
|
|
701
|
-
return args.result;
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
return false;
|
|
705
|
-
},
|
|
706
|
-
goto: function(path) {
|
|
707
|
-
history.pushState({},'',getUrl(path));
|
|
708
|
-
return route.match(path);
|
|
709
|
-
},
|
|
710
|
-
has: function(path) {
|
|
711
|
-
path = getPath(path);
|
|
712
|
-
for ( var i=0; i<routeInfo.length; i++) {
|
|
713
|
-
var matches = routeInfo[i].match.exec(path);
|
|
714
|
-
if (matches && matches.length) {
|
|
715
|
-
return true;
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
return false;
|
|
719
|
-
},
|
|
720
|
-
addListener: function(action, route, callback) {
|
|
721
|
-
if (['goto','match','call','finish'].indexOf(action)==-1) {
|
|
722
|
-
throw new Error('Unknown action '+action);
|
|
723
|
-
}
|
|
724
|
-
if (!listeners[action][route]) {
|
|
725
|
-
listeners[action][route] = [];
|
|
726
|
-
}
|
|
727
|
-
listeners[action][route].push(callback);
|
|
728
|
-
},
|
|
729
|
-
removeListener: function(action, route, callback) {
|
|
730
|
-
if (['match','call','finish'].indexOf(action)==-1) {
|
|
731
|
-
throw new Error('Unknown action '+action);
|
|
732
|
-
}
|
|
733
|
-
if (!listeners[action][route]) {
|
|
734
|
-
return;
|
|
735
|
-
}
|
|
736
|
-
listeners[action][route] = listeners[action][route].filter(function(listener) {
|
|
737
|
-
return listener != callback;
|
|
738
|
-
});
|
|
739
|
-
},
|
|
740
|
-
init: function(params) {
|
|
741
|
-
if (params.root) {
|
|
742
|
-
options.root = params.root;
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
};
|
|
746
|
-
|
|
747
|
-
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
748
|
-
module.exports = route;
|
|
749
|
-
} else {
|
|
750
|
-
if (!global.simply) {
|
|
751
|
-
global.simply = {};
|
|
340
|
+
}
|
|
341
|
+
return null;
|
|
752
342
|
}
|
|
753
|
-
|
|
343
|
+
}
|
|
754
344
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
var defaultHandlers = [
|
|
348
|
+
{
|
|
349
|
+
match: "input,select,textarea",
|
|
350
|
+
get: function(el) {
|
|
351
|
+
if (el.tagName === "SELECT" && el.multiple) {
|
|
352
|
+
let values = [];
|
|
353
|
+
for (let option of el.options) {
|
|
354
|
+
if (option.selected) {
|
|
355
|
+
values.push(option.value);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return values;
|
|
359
|
+
}
|
|
360
|
+
return el.dataset.simplyValue || el.value;
|
|
361
|
+
},
|
|
362
|
+
check: function(el, evt) {
|
|
363
|
+
return evt.type == "change" || el.dataset.simplyImmediate && evt.type == "input";
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
match: "a,button",
|
|
368
|
+
get: function(el) {
|
|
369
|
+
return el.dataset.simplyValue || el.href || el.value;
|
|
370
|
+
},
|
|
371
|
+
check: function(el, evt) {
|
|
372
|
+
return evt.type == "click" && evt.ctrlKey == false && evt.button == 0;
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
match: "form",
|
|
377
|
+
get: function(el) {
|
|
378
|
+
let data = {};
|
|
379
|
+
for (let input of Array.from(el.elements)) {
|
|
380
|
+
if (input.tagName == "INPUT" && (input.type == "checkbox" || input.type == "radio")) {
|
|
381
|
+
if (!input.checked) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (data[input.name] && !Array.isArray(data[input.name])) {
|
|
386
|
+
data[input.name] = [data[input.name]];
|
|
387
|
+
}
|
|
388
|
+
if (Array.isArray(data[input.name])) {
|
|
389
|
+
data[input.name].push(input.value);
|
|
390
|
+
} else {
|
|
391
|
+
data[input.name] = input.value;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return data;
|
|
395
|
+
},
|
|
396
|
+
check: function(el, evt) {
|
|
397
|
+
return evt.type == "submit";
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
match: "*",
|
|
402
|
+
get: function(el) {
|
|
403
|
+
return el.dataset.simplyValue;
|
|
404
|
+
},
|
|
405
|
+
check: function(el, evt) {
|
|
406
|
+
return evt.type == "click" && evt.ctrlKey == false && evt.button == 0;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
];
|
|
410
|
+
|
|
411
|
+
// src/key.mjs
|
|
412
|
+
var key_exports = {};
|
|
413
|
+
__export(key_exports, {
|
|
414
|
+
keys: () => keys
|
|
415
|
+
});
|
|
416
|
+
var SimplyKeys = class {
|
|
417
|
+
constructor(options = {}) {
|
|
418
|
+
if (!options.app) {
|
|
419
|
+
options.app = {};
|
|
420
|
+
}
|
|
421
|
+
if (!options.app.container) {
|
|
422
|
+
options.app.container = document.body;
|
|
423
|
+
}
|
|
424
|
+
Object.assign(this, options.keys);
|
|
425
|
+
const keyHandler = (e) => {
|
|
426
|
+
if (e.isComposing || e.keyCode === 229) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
if (e.defaultPrevented) {
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
if (!e.target) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
let selectedKeyboard = "default";
|
|
436
|
+
if (e.target.closest("[data-simply-keyboard]")) {
|
|
437
|
+
selectedKeyboard = e.target.closest("[data-simply-keyboard]").dataset.simplyKeyboard;
|
|
438
|
+
}
|
|
439
|
+
let key = "";
|
|
440
|
+
if (e.ctrlKey && e.keyCode != 17) {
|
|
441
|
+
key += "Control+";
|
|
442
|
+
}
|
|
443
|
+
if (e.metaKey && e.keyCode != 224) {
|
|
444
|
+
key += "Meta+";
|
|
445
|
+
}
|
|
446
|
+
if (e.altKey && e.keyCode != 18) {
|
|
447
|
+
key += "Alt+";
|
|
448
|
+
}
|
|
449
|
+
if (e.shiftKey && e.keyCode != 16) {
|
|
450
|
+
key += "Shift+";
|
|
451
|
+
}
|
|
452
|
+
key += e.key;
|
|
453
|
+
if (this[selectedKeyboard] && this[selectedKeyboard][key]) {
|
|
454
|
+
let keyboard = this[selectedKeyboard];
|
|
455
|
+
keyboard[key].call(options.app, e);
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
options.app.container.addEventListener("keydown", keyHandler);
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
function keys(options = {}) {
|
|
462
|
+
return new SimplyKeys(options);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// src/state.mjs
|
|
466
|
+
var state_exports = {};
|
|
467
|
+
__export(state_exports, {
|
|
468
|
+
batch: () => batch,
|
|
469
|
+
clockEffect: () => clockEffect,
|
|
470
|
+
destroy: () => destroy,
|
|
471
|
+
effect: () => effect,
|
|
472
|
+
signal: () => signal,
|
|
473
|
+
throttledEffect: () => throttledEffect,
|
|
474
|
+
untracked: () => untracked
|
|
475
|
+
});
|
|
476
|
+
var iterate = Symbol("iterate");
|
|
477
|
+
if (!Symbol.xRay) {
|
|
478
|
+
Symbol.xRay = Symbol("xRay");
|
|
479
|
+
}
|
|
480
|
+
var signalHandler = {
|
|
481
|
+
get: (target, property, receiver) => {
|
|
482
|
+
if (property === Symbol.xRay) {
|
|
483
|
+
return target;
|
|
484
|
+
}
|
|
485
|
+
const value = target?.[property];
|
|
486
|
+
notifyGet(receiver, property);
|
|
487
|
+
if (typeof value === "function") {
|
|
488
|
+
if (Array.isArray(target)) {
|
|
489
|
+
return (...args) => {
|
|
490
|
+
let l = target.length;
|
|
491
|
+
let result = value.apply(receiver, args);
|
|
492
|
+
if (l != target.length) {
|
|
493
|
+
notifySet(receiver, makeContext("length", { was: l, now: target.length }));
|
|
765
494
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
495
|
+
return result;
|
|
496
|
+
};
|
|
497
|
+
} else if (target instanceof Set || target instanceof Map) {
|
|
498
|
+
return (...args) => {
|
|
499
|
+
let s = target.size;
|
|
500
|
+
let result = value.apply(target, args);
|
|
501
|
+
if (s != target.size) {
|
|
502
|
+
notifySet(receiver, makeContext("size", { was: s, now: target.size }));
|
|
772
503
|
}
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
};
|
|
778
|
-
|
|
779
|
-
var initialCall = function(name) {
|
|
780
|
-
var nodes = document.querySelectorAll('[data-simply-activate="'+name+'"]');
|
|
781
|
-
if (nodes) {
|
|
782
|
-
[].forEach.call(nodes, function(node) {
|
|
783
|
-
callListeners(node);
|
|
784
|
-
});
|
|
785
|
-
}
|
|
786
|
-
};
|
|
787
|
-
|
|
788
|
-
var callListeners = function(node) {
|
|
789
|
-
if (node && node.dataset.simplyActivate
|
|
790
|
-
&& listeners[node.dataset.simplyActivate]
|
|
791
|
-
) {
|
|
792
|
-
listeners[node.dataset.simplyActivate].forEach(function(callback) {
|
|
793
|
-
callback.call(node);
|
|
794
|
-
});
|
|
795
|
-
}
|
|
796
|
-
};
|
|
797
|
-
|
|
798
|
-
var handleChanges = function(changes) {
|
|
799
|
-
var activateNodes = [];
|
|
800
|
-
for (var change of changes) {
|
|
801
|
-
if (change.type=='childList') {
|
|
802
|
-
[].forEach.call(change.addedNodes, function(node) {
|
|
803
|
-
if (node.querySelectorAll) {
|
|
804
|
-
var toActivate = [].slice.call(node.querySelectorAll('[data-simply-activate]'));
|
|
805
|
-
if (node.matches('[data-simply-activate]')) {
|
|
806
|
-
toActivate.push(node);
|
|
807
|
-
}
|
|
808
|
-
activateNodes = activateNodes.concat(toActivate);
|
|
809
|
-
}
|
|
810
|
-
});
|
|
504
|
+
if (["set", "add", "clear", "delete"].includes(property)) {
|
|
505
|
+
notifySet(receiver, makeContext({ entries: {}, forEach: {}, has: {}, keys: {}, values: {}, [Symbol.iterator]: {} }));
|
|
811
506
|
}
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
507
|
+
return result;
|
|
508
|
+
};
|
|
509
|
+
} else if (target instanceof HTMLElement || target instanceof Number || target instanceof String || target instanceof Boolean) {
|
|
510
|
+
return value.bind(target);
|
|
511
|
+
} else {
|
|
512
|
+
return value.bind(receiver);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if (value && typeof value == "object") {
|
|
516
|
+
return signal(value);
|
|
517
|
+
}
|
|
518
|
+
return value;
|
|
519
|
+
},
|
|
520
|
+
set: (target, property, value, receiver) => {
|
|
521
|
+
value = value?.[Symbol.xRay] || value;
|
|
522
|
+
let current = target[property];
|
|
523
|
+
if (current !== value) {
|
|
524
|
+
target[property] = value;
|
|
525
|
+
notifySet(receiver, makeContext(property, { was: current, now: value }));
|
|
526
|
+
}
|
|
527
|
+
if (typeof current === "undefined") {
|
|
528
|
+
notifySet(receiver, makeContext(iterate, {}));
|
|
529
|
+
}
|
|
530
|
+
return true;
|
|
531
|
+
},
|
|
532
|
+
has: (target, property) => {
|
|
533
|
+
let receiver = signals.get(target);
|
|
534
|
+
if (receiver) {
|
|
535
|
+
notifyGet(receiver, property);
|
|
536
|
+
}
|
|
537
|
+
return Object.hasOwn(target, property);
|
|
538
|
+
},
|
|
539
|
+
deleteProperty: (target, property) => {
|
|
540
|
+
if (typeof target[property] !== "undefined") {
|
|
541
|
+
let current = target[property];
|
|
542
|
+
delete target[property];
|
|
543
|
+
let receiver = signals.get(target);
|
|
544
|
+
notifySet(receiver, makeContext(property, { delete: true, was: current }));
|
|
545
|
+
}
|
|
546
|
+
return true;
|
|
547
|
+
},
|
|
548
|
+
defineProperty: (target, property, descriptor) => {
|
|
549
|
+
if (typeof target[property] === "undefined") {
|
|
550
|
+
let receiver = signals.get(target);
|
|
551
|
+
notifySet(receiver, makeContext(iterate, {}));
|
|
552
|
+
}
|
|
553
|
+
return Object.defineProperty(target, property, descriptor);
|
|
554
|
+
},
|
|
555
|
+
ownKeys: (target) => {
|
|
556
|
+
let receiver = signals.get(target);
|
|
557
|
+
notifyGet(receiver, iterate);
|
|
558
|
+
return Reflect.ownKeys(target);
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
var signals = /* @__PURE__ */ new WeakMap();
|
|
562
|
+
function signal(v) {
|
|
563
|
+
if (!signals.has(v)) {
|
|
564
|
+
signals.set(v, new Proxy(v, signalHandler));
|
|
565
|
+
}
|
|
566
|
+
return signals.get(v);
|
|
567
|
+
}
|
|
568
|
+
var batchedListeners = /* @__PURE__ */ new Set();
|
|
569
|
+
var batchMode = 0;
|
|
570
|
+
function notifySet(self, context = {}) {
|
|
571
|
+
let listeners2 = [];
|
|
572
|
+
context.forEach((change, property) => {
|
|
573
|
+
let propListeners = getListeners(self, property);
|
|
574
|
+
if (propListeners?.length) {
|
|
575
|
+
for (let listener of propListeners) {
|
|
576
|
+
addContext(listener, makeContext(property, change));
|
|
577
|
+
}
|
|
578
|
+
listeners2 = listeners2.concat(propListeners);
|
|
579
|
+
}
|
|
824
580
|
});
|
|
825
|
-
|
|
826
|
-
if (
|
|
827
|
-
|
|
581
|
+
listeners2 = new Set(listeners2.filter(Boolean));
|
|
582
|
+
if (listeners2) {
|
|
583
|
+
if (batchMode) {
|
|
584
|
+
batchedListeners = batchedListeners.union(listeners2);
|
|
585
|
+
} else {
|
|
586
|
+
const currentEffect = computeStack[computeStack.length - 1];
|
|
587
|
+
for (let listener of Array.from(listeners2)) {
|
|
588
|
+
if (listener != currentEffect && listener?.needsUpdate) {
|
|
589
|
+
listener();
|
|
590
|
+
}
|
|
591
|
+
clearContext(listener);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
function makeContext(property, change) {
|
|
597
|
+
let context = /* @__PURE__ */ new Map();
|
|
598
|
+
if (typeof property === "object") {
|
|
599
|
+
for (let prop in property) {
|
|
600
|
+
context.set(prop, property[prop]);
|
|
601
|
+
}
|
|
828
602
|
} else {
|
|
829
|
-
|
|
830
|
-
global.simply = {};
|
|
831
|
-
}
|
|
832
|
-
global.simply.activate = activate;
|
|
603
|
+
context.set(property, change);
|
|
833
604
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
var collect = {
|
|
841
|
-
addListener: function(name, callback) {
|
|
842
|
-
if (!knownCollections[name]) {
|
|
843
|
-
knownCollections[name] = [];
|
|
844
|
-
}
|
|
845
|
-
if (knownCollections[name].indexOf(callback) == -1) {
|
|
846
|
-
knownCollections[name].push(callback);
|
|
847
|
-
}
|
|
848
|
-
},
|
|
849
|
-
removeListener: function(name, callback) {
|
|
850
|
-
if (knownCollections[name]) {
|
|
851
|
-
var index = knownCollections[name].indexOf(callback);
|
|
852
|
-
if (index>=0) {
|
|
853
|
-
knownCollections[name].splice(index, 1);
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
},
|
|
857
|
-
update: function(element, value) {
|
|
858
|
-
element.value = value;
|
|
859
|
-
element.dispatchEvent(new Event('change', {
|
|
860
|
-
bubbles: true,
|
|
861
|
-
cancelable: true
|
|
862
|
-
}));
|
|
863
|
-
}
|
|
864
|
-
};
|
|
865
|
-
|
|
866
|
-
function findCollection(el) {
|
|
867
|
-
while (el && !el.dataset.simplyCollection) {
|
|
868
|
-
el = el.parentElement;
|
|
869
|
-
}
|
|
870
|
-
return el;
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
global.addEventListener('change', function(evt) {
|
|
874
|
-
var root = null;
|
|
875
|
-
var name = '';
|
|
876
|
-
if (evt.target.dataset.simplyElement) {
|
|
877
|
-
root = findCollection(evt.target);
|
|
878
|
-
if (root && root.dataset) {
|
|
879
|
-
name = root.dataset.simplyCollection;
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
if (name && knownCollections[name]) {
|
|
883
|
-
var inputs = root.querySelectorAll('[data-simply-element]');
|
|
884
|
-
var elements = [].reduce.call(inputs, function(elements, input) {
|
|
885
|
-
elements[input.dataset.simplyElement] = input;
|
|
886
|
-
return elements;
|
|
887
|
-
}, {});
|
|
888
|
-
for (var i=knownCollections[name].length-1; i>=0; i--) {
|
|
889
|
-
var result = knownCollections[name][i].call(evt.target.form, elements);
|
|
890
|
-
if (result === false) {
|
|
891
|
-
break;
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}, true);
|
|
896
|
-
|
|
897
|
-
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
898
|
-
module.exports = collect;
|
|
605
|
+
return context;
|
|
606
|
+
}
|
|
607
|
+
function addContext(listener, context) {
|
|
608
|
+
if (!listener.context) {
|
|
609
|
+
listener.context = context;
|
|
899
610
|
} else {
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
global.simply.collect = collect;
|
|
611
|
+
context.forEach((change, property) => {
|
|
612
|
+
listener.context.set(property, change);
|
|
613
|
+
});
|
|
904
614
|
}
|
|
905
|
-
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
}
|
|
916
|
-
},
|
|
917
|
-
'simply-show': function(el, value) {
|
|
918
|
-
var target = this.app.get(value);
|
|
919
|
-
if (target) {
|
|
920
|
-
this.action('simply-show',target);
|
|
921
|
-
}
|
|
922
|
-
},
|
|
923
|
-
'simply-select': function(el, value) {
|
|
924
|
-
var group = el.dataset.simplyGroup;
|
|
925
|
-
var target = this.app.get(value);
|
|
926
|
-
var targetGroup = (target ? target.dataset.simplyGroup : null);
|
|
927
|
-
this.action('simply-select', el, group, target, targetGroup);
|
|
928
|
-
},
|
|
929
|
-
'simply-toggle-select': function(el, value) {
|
|
930
|
-
var group = el.dataset.simplyGroup;
|
|
931
|
-
var target = this.app.get(value);
|
|
932
|
-
var targetGroup = (target ? target.dataset.simplyTarget : null);
|
|
933
|
-
this.action('simply-toggle-select',el,group,target,targetGroup);
|
|
934
|
-
},
|
|
935
|
-
'simply-toggle-class': function(el, value) {
|
|
936
|
-
var target = this.app.get(el.dataset.simplyTarget);
|
|
937
|
-
this.action('simply-toggle-class',el,value,target);
|
|
938
|
-
},
|
|
939
|
-
'simply-deselect': function(el, value) {
|
|
940
|
-
var target = this.app.get(value);
|
|
941
|
-
this.action('simply-deselect',el,target);
|
|
942
|
-
},
|
|
943
|
-
'simply-fullscreen': function(el, value) {
|
|
944
|
-
var target = this.app.get(value);
|
|
945
|
-
this.action('simply-fullscreen',target);
|
|
946
|
-
}
|
|
947
|
-
};
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
var handlers = [
|
|
951
|
-
{
|
|
952
|
-
match: 'input,select,textarea',
|
|
953
|
-
get: function(el) {
|
|
954
|
-
if (el.tagName==='SELECT' && el.multiple) {
|
|
955
|
-
var values = [], opt;
|
|
956
|
-
for (var i=0,l=el.options.length;i<l;i++) {
|
|
957
|
-
var opt = el.options[i];
|
|
958
|
-
if (opt.selected) {
|
|
959
|
-
values.push(opt.value);
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
return values;
|
|
963
|
-
}
|
|
964
|
-
return el.dataset.simplyValue || el.value;
|
|
965
|
-
},
|
|
966
|
-
check: function(el, evt) {
|
|
967
|
-
return evt.type=='change' || (el.dataset.simplyImmediate && evt.type=='input');
|
|
968
|
-
}
|
|
969
|
-
},
|
|
970
|
-
{
|
|
971
|
-
match: 'a,button',
|
|
972
|
-
get: function(el) {
|
|
973
|
-
return el.dataset.simplyValue || el.href || el.value;
|
|
974
|
-
},
|
|
975
|
-
check: function(el,evt) {
|
|
976
|
-
return evt.type=='click' && evt.ctrlKey==false && evt.button==0;
|
|
977
|
-
}
|
|
978
|
-
},
|
|
979
|
-
{
|
|
980
|
-
match: 'form',
|
|
981
|
-
get: function(el) {
|
|
982
|
-
var data = {};
|
|
983
|
-
[].forEach.call(el.elements, function(el) {
|
|
984
|
-
if (el.tagName=='INPUT' && (el.type=='checkbox' || el.type=='radio')) {
|
|
985
|
-
if (!el.checked) {
|
|
986
|
-
return;
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
if (data[el.name] && !Array.isArray(data[el.name])) {
|
|
990
|
-
data[el.name] = [data[el.name]];
|
|
991
|
-
}
|
|
992
|
-
if (Array.isArray(data[el.name])) {
|
|
993
|
-
data[el.name].push(el.value);
|
|
994
|
-
} else {
|
|
995
|
-
data[el.name] = el.value;
|
|
996
|
-
}
|
|
997
|
-
});
|
|
998
|
-
return data;//new FormData(el);
|
|
999
|
-
},
|
|
1000
|
-
check: function(el,evt) {
|
|
1001
|
-
return evt.type=='submit';
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
];
|
|
1005
|
-
|
|
1006
|
-
var fallbackHandler = {
|
|
1007
|
-
get: function(el) {
|
|
1008
|
-
return el.dataset.simplyValue;
|
|
1009
|
-
},
|
|
1010
|
-
check: function(el, evt) {
|
|
1011
|
-
return evt.type=='click' && evt.ctrlKey==false && evt.button==0;
|
|
1012
|
-
}
|
|
1013
|
-
};
|
|
1014
|
-
|
|
1015
|
-
function getCommand(evt) {
|
|
1016
|
-
var el = evt.target.closest('[data-simply-command]');
|
|
1017
|
-
if (el) {
|
|
1018
|
-
var matched = false;
|
|
1019
|
-
for (var i=handlers.length-1; i>=0; i--) {
|
|
1020
|
-
if (el.matches(handlers[i].match)) {
|
|
1021
|
-
matched = true;
|
|
1022
|
-
if (handlers[i].check(el, evt)) {
|
|
1023
|
-
return {
|
|
1024
|
-
name: el.dataset.simplyCommand,
|
|
1025
|
-
source: el,
|
|
1026
|
-
value: handlers[i].get(el)
|
|
1027
|
-
};
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
if (!matched && fallbackHandler.check(el,evt)) {
|
|
1032
|
-
return {
|
|
1033
|
-
name: el.dataset.simplyCommand,
|
|
1034
|
-
source: el,
|
|
1035
|
-
value: fallbackHandler.get(el)
|
|
1036
|
-
};
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
return null;
|
|
615
|
+
listener.needsUpdate = true;
|
|
616
|
+
}
|
|
617
|
+
function clearContext(listener) {
|
|
618
|
+
delete listener.context;
|
|
619
|
+
delete listener.needsUpdate;
|
|
620
|
+
}
|
|
621
|
+
function notifyGet(self, property) {
|
|
622
|
+
let currentCompute = computeStack[computeStack.length - 1];
|
|
623
|
+
if (currentCompute) {
|
|
624
|
+
setListeners(self, property, currentCompute);
|
|
1040
625
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
commands.action = function(name) {
|
|
1052
|
-
var params = Array.prototype.slice.call(arguments);
|
|
1053
|
-
params.shift();
|
|
1054
|
-
return app.actions[name].apply(app.actions,params);
|
|
1055
|
-
};
|
|
1056
|
-
|
|
1057
|
-
commands.call = function(name) {
|
|
1058
|
-
var params = Array.prototype.slice.call(arguments);
|
|
1059
|
-
params.shift();
|
|
1060
|
-
return this[name].apply(this,params);
|
|
1061
|
-
};
|
|
1062
|
-
|
|
1063
|
-
commands.appendHandler = function(handler) {
|
|
1064
|
-
handlers.push(handler);
|
|
1065
|
-
};
|
|
1066
|
-
|
|
1067
|
-
commands.prependHandler = function(handler) {
|
|
1068
|
-
handlers.unshift(handler);
|
|
1069
|
-
};
|
|
1070
|
-
|
|
1071
|
-
var commandHandler = function(evt) {
|
|
1072
|
-
var command = getCommand(evt);
|
|
1073
|
-
if ( command ) {
|
|
1074
|
-
if (!commands[command.name]) {
|
|
1075
|
-
console.error('simply.command: undefined command '+command.name, command.source);
|
|
1076
|
-
} else {
|
|
1077
|
-
commands.call(command.name, command.source, command.value);
|
|
1078
|
-
evt.preventDefault();
|
|
1079
|
-
evt.stopPropagation();
|
|
1080
|
-
return false;
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
};
|
|
1084
|
-
|
|
1085
|
-
app.container.addEventListener('click', commandHandler);
|
|
1086
|
-
app.container.addEventListener('submit', commandHandler);
|
|
1087
|
-
app.container.addEventListener('change', commandHandler);
|
|
1088
|
-
app.container.addEventListener('input', commandHandler);
|
|
1089
|
-
|
|
1090
|
-
return commands;
|
|
1091
|
-
};
|
|
1092
|
-
|
|
1093
|
-
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
1094
|
-
module.exports = command;
|
|
1095
|
-
} else {
|
|
1096
|
-
if (!global.simply) {
|
|
1097
|
-
global.simply = {};
|
|
1098
|
-
}
|
|
1099
|
-
global.simply.command = command;
|
|
626
|
+
}
|
|
627
|
+
var listenersMap = /* @__PURE__ */ new WeakMap();
|
|
628
|
+
var computeMap = /* @__PURE__ */ new WeakMap();
|
|
629
|
+
function getListeners(self, property) {
|
|
630
|
+
let listeners2 = listenersMap.get(self);
|
|
631
|
+
return listeners2 ? Array.from(listeners2.get(property) || []) : [];
|
|
632
|
+
}
|
|
633
|
+
function setListeners(self, property, compute) {
|
|
634
|
+
if (!listenersMap.has(self)) {
|
|
635
|
+
listenersMap.set(self, /* @__PURE__ */ new Map());
|
|
1100
636
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
(
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
let selectedKeyboard = 'default';
|
|
1127
|
-
if (e.target.closest('[data-simply-keyboard]')) {
|
|
1128
|
-
selectedKeyboard = e.target.closest('[data-simply-keyboard]').dataset.simplyKeyboard;
|
|
1129
|
-
}
|
|
1130
|
-
let key = '';
|
|
1131
|
-
if (e.ctrlKey && e.keyCode!=17) {
|
|
1132
|
-
key+='Control+';
|
|
1133
|
-
}
|
|
1134
|
-
if (e.metaKey && e.keyCode!=224) {
|
|
1135
|
-
key+='Meta+';
|
|
1136
|
-
}
|
|
1137
|
-
if (e.altKey && e.keyCode!=18) {
|
|
1138
|
-
key+='Alt+';
|
|
1139
|
-
}
|
|
1140
|
-
if (e.shiftKey && e.keyCode!=16) {
|
|
1141
|
-
key+='Shift+';
|
|
1142
|
-
}
|
|
1143
|
-
key+=e.key;
|
|
1144
|
-
|
|
1145
|
-
if (keys[selectedKeyboard] && keys[selectedKeyboard][key]) {
|
|
1146
|
-
let keyboard = keys[selectedKeyboard]
|
|
1147
|
-
keyboard.app = app;
|
|
1148
|
-
keyboard[key].call(keyboard,e);
|
|
1149
|
-
}
|
|
637
|
+
let listeners2 = listenersMap.get(self);
|
|
638
|
+
if (!listeners2.has(property)) {
|
|
639
|
+
listeners2.set(property, /* @__PURE__ */ new Set());
|
|
640
|
+
}
|
|
641
|
+
listeners2.get(property).add(compute);
|
|
642
|
+
if (!computeMap.has(compute)) {
|
|
643
|
+
computeMap.set(compute, /* @__PURE__ */ new Map());
|
|
644
|
+
}
|
|
645
|
+
let connectedSignals = computeMap.get(compute);
|
|
646
|
+
if (!connectedSignals.has(property)) {
|
|
647
|
+
connectedSignals.set(property, /* @__PURE__ */ new Set());
|
|
648
|
+
}
|
|
649
|
+
connectedSignals.get(property).add(self);
|
|
650
|
+
}
|
|
651
|
+
function clearListeners(compute) {
|
|
652
|
+
let connectedSignals = computeMap.get(compute);
|
|
653
|
+
if (connectedSignals) {
|
|
654
|
+
connectedSignals.forEach((property) => {
|
|
655
|
+
property.forEach((s) => {
|
|
656
|
+
let listeners2 = listenersMap.get(s);
|
|
657
|
+
if (listeners2.has(property)) {
|
|
658
|
+
listeners2.get(property).delete(compute);
|
|
659
|
+
}
|
|
1150
660
|
});
|
|
1151
|
-
|
|
1152
|
-
return keys;
|
|
661
|
+
});
|
|
1153
662
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
global.simply.keyboard = keyboard;
|
|
663
|
+
}
|
|
664
|
+
var computeStack = [];
|
|
665
|
+
var effectStack = [];
|
|
666
|
+
var effectMap = /* @__PURE__ */ new WeakMap();
|
|
667
|
+
var signalStack = [];
|
|
668
|
+
function effect(fn) {
|
|
669
|
+
if (effectStack.findIndex((f) => fn == f) !== -1) {
|
|
670
|
+
throw new Error("Recursive update() call", { cause: fn });
|
|
1163
671
|
}
|
|
1164
|
-
|
|
1165
|
-
(
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
this.call('simply-deselect',el,target);
|
|
1192
|
-
}
|
|
1193
|
-
return Promise.resolve();
|
|
1194
|
-
},
|
|
1195
|
-
'simply-toggle-class': function(el,className,target) {
|
|
1196
|
-
if (!target) {
|
|
1197
|
-
target = el;
|
|
1198
|
-
}
|
|
1199
|
-
return Promise.resolve(target.classList.toggle(className));
|
|
1200
|
-
},
|
|
1201
|
-
'simply-deselect': function(el,target) {
|
|
1202
|
-
if ( typeof el.length=='number' && typeof el.item=='function') {
|
|
1203
|
-
el = Array.prototype.slice.call(el);
|
|
1204
|
-
}
|
|
1205
|
-
if ( Array.isArray(el) ) {
|
|
1206
|
-
for (var i=0,l=el.length; i<l; i++) {
|
|
1207
|
-
this.call('simply-deselect',el[i],target);
|
|
1208
|
-
target = null;
|
|
1209
|
-
}
|
|
1210
|
-
} else {
|
|
1211
|
-
el.classList.remove('simply-selected');
|
|
1212
|
-
if (target) {
|
|
1213
|
-
this.call('simply-deselect',target);
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
return Promise.resolve();
|
|
1217
|
-
},
|
|
1218
|
-
'simply-fullscreen': function(target) {
|
|
1219
|
-
var methods = {
|
|
1220
|
-
'requestFullscreen':{exit:'exitFullscreen',event:'fullscreenchange',el:'fullscreenElement'},
|
|
1221
|
-
'webkitRequestFullScreen':{exit:'webkitCancelFullScreen',event:'webkitfullscreenchange',el:'webkitFullscreenElement'},
|
|
1222
|
-
'msRequestFullscreen':{exit:'msExitFullscreen',event:'MSFullscreenChange',el:'msFullscreenElement'},
|
|
1223
|
-
'mozRequestFullScreen':{exit:'mozCancelFullScreen',event:'mozfullscreenchange',el:'mozFullScreenElement'}
|
|
1224
|
-
};
|
|
1225
|
-
for ( var i in methods ) {
|
|
1226
|
-
if ( typeof document.documentElement[i] != 'undefined' ) {
|
|
1227
|
-
var requestMethod = i;
|
|
1228
|
-
var cancelMethod = methods[i].exit;
|
|
1229
|
-
var event = methods[i].event;
|
|
1230
|
-
var element = methods[i].el;
|
|
1231
|
-
break;
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
if ( !requestMethod ) {
|
|
1235
|
-
return;
|
|
1236
|
-
}
|
|
1237
|
-
if (!target.classList.contains('simply-fullscreen')) {
|
|
1238
|
-
target.classList.add('simply-fullscreen');
|
|
1239
|
-
target[requestMethod]();
|
|
1240
|
-
var exit = function() {
|
|
1241
|
-
if ( !document[element] ) {
|
|
1242
|
-
target.classList.remove('simply-fullscreen');
|
|
1243
|
-
document.removeEventListener(event,exit);
|
|
1244
|
-
}
|
|
1245
|
-
};
|
|
1246
|
-
document.addEventListener(event,exit);
|
|
1247
|
-
} else {
|
|
1248
|
-
target.classList.remove('simply-fullscreen');
|
|
1249
|
-
document[cancelMethod]();
|
|
1250
|
-
}
|
|
1251
|
-
return Promise.resolve();
|
|
672
|
+
effectStack.push(fn);
|
|
673
|
+
let connectedSignal = signals.get(fn);
|
|
674
|
+
if (!connectedSignal) {
|
|
675
|
+
connectedSignal = signal({
|
|
676
|
+
current: null
|
|
677
|
+
});
|
|
678
|
+
signals.set(fn, connectedSignal);
|
|
679
|
+
}
|
|
680
|
+
const computeEffect = function computeEffect2() {
|
|
681
|
+
if (signalStack.findIndex((s) => s == connectedSignal) !== -1) {
|
|
682
|
+
throw new Error("Cyclical dependency in update() call", { cause: fn });
|
|
683
|
+
}
|
|
684
|
+
clearListeners(computeEffect2);
|
|
685
|
+
computeStack.push(computeEffect2);
|
|
686
|
+
signalStack.push(connectedSignal);
|
|
687
|
+
let result;
|
|
688
|
+
try {
|
|
689
|
+
result = fn(computeEffect2, computeStack, signalStack);
|
|
690
|
+
} finally {
|
|
691
|
+
computeStack.pop();
|
|
692
|
+
signalStack.pop();
|
|
693
|
+
if (result instanceof Promise) {
|
|
694
|
+
result.then((result2) => {
|
|
695
|
+
connectedSignal.current = result2;
|
|
696
|
+
});
|
|
697
|
+
} else {
|
|
698
|
+
connectedSignal.current = result;
|
|
1252
699
|
}
|
|
700
|
+
}
|
|
1253
701
|
};
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
var params = Array.prototype.slice.call(arguments);
|
|
1264
|
-
params.shift();
|
|
1265
|
-
return this[name].apply(this, params);
|
|
1266
|
-
};
|
|
1267
|
-
return actions;
|
|
1268
|
-
};
|
|
1269
|
-
|
|
1270
|
-
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
1271
|
-
module.exports = action;
|
|
1272
|
-
} else {
|
|
1273
|
-
if (!global.simply) {
|
|
1274
|
-
global.simply = {};
|
|
1275
|
-
}
|
|
1276
|
-
global.simply.action = action;
|
|
702
|
+
computeEffect.fn = fn;
|
|
703
|
+
effectMap.set(connectedSignal, computeEffect);
|
|
704
|
+
computeEffect();
|
|
705
|
+
return connectedSignal;
|
|
706
|
+
}
|
|
707
|
+
function destroy(connectedSignal) {
|
|
708
|
+
const computeEffect = effectMap.get(connectedSignal)?.deref();
|
|
709
|
+
if (!computeEffect) {
|
|
710
|
+
return;
|
|
1277
711
|
}
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
(
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
if ( lastSize==size ) {
|
|
1301
|
-
return;
|
|
1302
|
-
}
|
|
1303
|
-
lastSize = size;
|
|
1304
|
-
var sizes = Object.keys(config.sizes);
|
|
1305
|
-
var match = sizes.pop();
|
|
1306
|
-
while (match) {
|
|
1307
|
-
if ( size<config.sizes[match] ) {
|
|
1308
|
-
if ( app.container.classList.contains(match)) {
|
|
1309
|
-
app.container.classList.remove(match);
|
|
1310
|
-
}
|
|
1311
|
-
} else {
|
|
1312
|
-
if ( !app.container.classList.contains(match) ) {
|
|
1313
|
-
app.container.classList.add(match);
|
|
1314
|
-
match = sizes.pop(); // skip to next match to remove these
|
|
1315
|
-
}
|
|
1316
|
-
break;
|
|
1317
|
-
}
|
|
1318
|
-
match = sizes.pop();
|
|
1319
|
-
}
|
|
1320
|
-
while (match) {
|
|
1321
|
-
if ( app.container.classList.contains(match)) {
|
|
1322
|
-
app.container.classList.remove(match);
|
|
1323
|
-
}
|
|
1324
|
-
match = sizes.pop();
|
|
1325
|
-
}
|
|
1326
|
-
var toolbars = app.container.querySelectorAll('.simply-toolbar');
|
|
1327
|
-
[].forEach.call(toolbars, function(toolbar) {
|
|
1328
|
-
toolbar.style.transform = '';
|
|
1329
|
-
});
|
|
712
|
+
clearListeners(computeEffect);
|
|
713
|
+
let fn = computeEffect.fn;
|
|
714
|
+
signals.remove(fn);
|
|
715
|
+
effectMap.delete(connectedSignal);
|
|
716
|
+
}
|
|
717
|
+
function batch(fn) {
|
|
718
|
+
batchMode++;
|
|
719
|
+
let result;
|
|
720
|
+
try {
|
|
721
|
+
result = fn();
|
|
722
|
+
} finally {
|
|
723
|
+
if (result instanceof Promise) {
|
|
724
|
+
result.then(() => {
|
|
725
|
+
batchMode--;
|
|
726
|
+
if (!batchMode) {
|
|
727
|
+
runBatchedListeners();
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
} else {
|
|
731
|
+
batchMode--;
|
|
732
|
+
if (!batchMode) {
|
|
733
|
+
runBatchedListeners();
|
|
1330
734
|
}
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return result;
|
|
738
|
+
}
|
|
739
|
+
function runBatchedListeners() {
|
|
740
|
+
let copyBatchedListeners = Array.from(batchedListeners);
|
|
741
|
+
batchedListeners = /* @__PURE__ */ new Set();
|
|
742
|
+
const currentEffect = computeStack[computeStack.length - 1];
|
|
743
|
+
for (let listener of copyBatchedListeners) {
|
|
744
|
+
if (listener != currentEffect && listener?.needsUpdate) {
|
|
745
|
+
listener();
|
|
746
|
+
}
|
|
747
|
+
clearContext(listener);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
function throttledEffect(fn, throttleTime) {
|
|
751
|
+
if (effectStack.findIndex((f) => fn == f) !== -1) {
|
|
752
|
+
throw new Error("Recursive update() call", { cause: fn });
|
|
753
|
+
}
|
|
754
|
+
effectStack.push(fn);
|
|
755
|
+
let connectedSignal = signals.get(fn);
|
|
756
|
+
if (!connectedSignal) {
|
|
757
|
+
connectedSignal = signal({
|
|
758
|
+
current: null
|
|
759
|
+
});
|
|
760
|
+
signals.set(fn, connectedSignal);
|
|
761
|
+
}
|
|
762
|
+
let throttled = false;
|
|
763
|
+
let hasChange = true;
|
|
764
|
+
const computeEffect = function computeEffect2() {
|
|
765
|
+
if (signalStack.findIndex((s) => s == connectedSignal) !== -1) {
|
|
766
|
+
throw new Error("Cyclical dependency in update() call", { cause: fn });
|
|
767
|
+
}
|
|
768
|
+
if (throttled && throttled > Date.now()) {
|
|
769
|
+
hasChange = true;
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
clearListeners(computeEffect2);
|
|
773
|
+
computeStack.push(computeEffect2);
|
|
774
|
+
signalStack.push(connectedSignal);
|
|
775
|
+
let result;
|
|
776
|
+
try {
|
|
777
|
+
result = fn(computeEffect2, computeStack, signalStack);
|
|
778
|
+
} finally {
|
|
779
|
+
hasChange = false;
|
|
780
|
+
computeStack.pop();
|
|
781
|
+
signalStack.pop();
|
|
782
|
+
if (result instanceof Promise) {
|
|
783
|
+
result.then((result2) => {
|
|
784
|
+
connectedSignal.current = result2;
|
|
785
|
+
});
|
|
1334
786
|
} else {
|
|
1335
|
-
|
|
787
|
+
connectedSignal.current = result;
|
|
1336
788
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
if (simply.toolbar.scroll) {
|
|
1343
|
-
simply.toolbar.scroll(toolbar);
|
|
1344
|
-
}
|
|
1345
|
-
});
|
|
789
|
+
}
|
|
790
|
+
throttled = Date.now() + throttleTime;
|
|
791
|
+
globalThis.setTimeout(() => {
|
|
792
|
+
if (hasChange) {
|
|
793
|
+
computeEffect2();
|
|
1346
794
|
}
|
|
1347
|
-
|
|
1348
|
-
return resizeSniffer;
|
|
795
|
+
}, throttleTime);
|
|
1349
796
|
};
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
797
|
+
computeEffect();
|
|
798
|
+
return connectedSignal;
|
|
799
|
+
}
|
|
800
|
+
function clockEffect(fn, clock) {
|
|
801
|
+
let connectedSignal = signals.get(fn);
|
|
802
|
+
if (!connectedSignal) {
|
|
803
|
+
connectedSignal = signal({
|
|
804
|
+
current: null
|
|
805
|
+
});
|
|
806
|
+
signals.set(fn, connectedSignal);
|
|
1358
807
|
}
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
808
|
+
let lastTick = -1;
|
|
809
|
+
let hasChanged = true;
|
|
810
|
+
const computeEffect = function computeEffect2() {
|
|
811
|
+
if (lastTick < clock.time) {
|
|
812
|
+
if (hasChanged) {
|
|
813
|
+
clearListeners(computeEffect2);
|
|
814
|
+
computeStack.push(computeEffect2);
|
|
815
|
+
lastTick = clock.time;
|
|
816
|
+
let result;
|
|
817
|
+
try {
|
|
818
|
+
result = fn(computeEffect2, computeStack);
|
|
819
|
+
} finally {
|
|
820
|
+
computeStack.pop();
|
|
821
|
+
if (result instanceof Promise) {
|
|
822
|
+
result.then((result2) => {
|
|
823
|
+
connectedSignal.current = result2;
|
|
824
|
+
});
|
|
1369
825
|
} else {
|
|
1370
|
-
|
|
1371
|
-
callbackFunction.apply(me, myArguments);
|
|
1372
|
-
eventId = 0;
|
|
1373
|
-
}, intervalTime );
|
|
826
|
+
connectedSignal.current = result;
|
|
1374
827
|
}
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
if (global.requestIdleCallback) {
|
|
1380
|
-
return function(callback) {
|
|
1381
|
-
global.requestIdleCallback(callback, {timeout: 500});
|
|
1382
|
-
};
|
|
1383
|
-
}
|
|
1384
|
-
return global.requestAnimationFrame;
|
|
1385
|
-
})();
|
|
1386
|
-
|
|
1387
|
-
var rebaseHref = function(relative, base) {
|
|
1388
|
-
let url = new URL(relative, base)
|
|
1389
|
-
if (include.cacheBuster) {
|
|
1390
|
-
url.searchParams.set('cb',include.cacheBuster)
|
|
828
|
+
hasChanged = false;
|
|
829
|
+
}
|
|
830
|
+
} else {
|
|
831
|
+
lastTick = clock.time;
|
|
1391
832
|
}
|
|
1392
|
-
|
|
833
|
+
} else {
|
|
834
|
+
hasChanged = true;
|
|
835
|
+
}
|
|
1393
836
|
};
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
})();
|
|
1405
|
-
var currentScriptURL = getScriptURL();
|
|
1406
|
-
} else {
|
|
1407
|
-
var currentScriptURL = currentScript.src;
|
|
837
|
+
computeEffect();
|
|
838
|
+
return connectedSignal;
|
|
839
|
+
}
|
|
840
|
+
function untracked(fn) {
|
|
841
|
+
const remember = computeStack.slice();
|
|
842
|
+
computeStack = [];
|
|
843
|
+
try {
|
|
844
|
+
return fn();
|
|
845
|
+
} finally {
|
|
846
|
+
computeStack = remember;
|
|
1408
847
|
}
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
});
|
|
1446
|
-
clone.removeAttribute('data-simply-location');
|
|
1447
|
-
if (!clone.src) {
|
|
1448
|
-
// this is an inline script, so copy the content and wait for previous scripts to run
|
|
1449
|
-
clone.innerHTML = script.innerHTML;
|
|
1450
|
-
waitForPreviousScripts()
|
|
1451
|
-
.then(function() {
|
|
1452
|
-
var node = scriptLocations[script.dataset.simplyLocation];
|
|
1453
|
-
node.parentNode.insertBefore(clone, node);
|
|
1454
|
-
node.parentNode.removeChild(node);
|
|
1455
|
-
importScript();
|
|
1456
|
-
});
|
|
1457
|
-
} else {
|
|
1458
|
-
clone.src = rebaseHref(clone.src, base);
|
|
1459
|
-
if (!clone.hasAttribute('async') && !clone.hasAttribute('defer')) {
|
|
1460
|
-
clone.async = false; //important! do not use clone.setAttribute('async', false) - it has no effect
|
|
1461
|
-
}
|
|
1462
|
-
var node = scriptLocations[script.dataset.simplyLocation];
|
|
1463
|
-
node.parentNode.insertBefore(clone, node);
|
|
1464
|
-
node.parentNode.removeChild(node);
|
|
1465
|
-
loaded[clone.src]=true;
|
|
1466
|
-
importScript();
|
|
1467
|
-
}
|
|
1468
|
-
};
|
|
1469
|
-
if (arr.length) {
|
|
1470
|
-
importScript();
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
// src/bind.mjs
|
|
851
|
+
var SimplyBind = class {
|
|
852
|
+
constructor(options) {
|
|
853
|
+
this.bindings = /* @__PURE__ */ new Map();
|
|
854
|
+
const defaultOptions = {
|
|
855
|
+
container: document.body,
|
|
856
|
+
attribute: "data-bind",
|
|
857
|
+
transformers: [],
|
|
858
|
+
defaultTransformers: [defaultTransformer]
|
|
859
|
+
};
|
|
860
|
+
if (!options?.root) {
|
|
861
|
+
throw new Error("bind needs at least options.root set");
|
|
862
|
+
}
|
|
863
|
+
this.options = Object.assign({}, defaultOptions, options);
|
|
864
|
+
const attribute = this.options.attribute;
|
|
865
|
+
const render = (el) => {
|
|
866
|
+
this.bindings.set(el, throttledEffect(() => {
|
|
867
|
+
const context = {
|
|
868
|
+
templates: el.querySelectorAll(":scope > template"),
|
|
869
|
+
path: this.getBindingPath(el)
|
|
870
|
+
};
|
|
871
|
+
context.value = getValueByPath(this.options.root, context.path);
|
|
872
|
+
context.element = el;
|
|
873
|
+
runTransformers(context);
|
|
874
|
+
}, 100));
|
|
875
|
+
};
|
|
876
|
+
const runTransformers = (context) => {
|
|
877
|
+
let transformers = this.options.defaultTransformers || [];
|
|
878
|
+
if (context.element.dataset.transform) {
|
|
879
|
+
context.element.dataset.transform.split(" ").filter(Boolean).forEach((t) => {
|
|
880
|
+
if (this.options.transformers[t]) {
|
|
881
|
+
transformers.push(this.options.transformers[t]);
|
|
882
|
+
} else {
|
|
883
|
+
console.warn("No transformer with name " + t + " configured", { cause: context.element });
|
|
1471
884
|
}
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
let next;
|
|
888
|
+
for (let transformer of transformers) {
|
|
889
|
+
next = /* @__PURE__ */ ((next2, transformer2) => {
|
|
890
|
+
return (context2) => {
|
|
891
|
+
return transformer2.call(this, context2, next2);
|
|
892
|
+
};
|
|
893
|
+
})(next, transformer);
|
|
894
|
+
}
|
|
895
|
+
next(context);
|
|
896
|
+
};
|
|
897
|
+
const applyBindings = (bindings2) => {
|
|
898
|
+
for (let bindingEl of bindings2) {
|
|
899
|
+
render(bindingEl);
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
const updateBindings = (changes) => {
|
|
903
|
+
for (const change of changes) {
|
|
904
|
+
if (change.type == "childList" && change.addedNodes) {
|
|
905
|
+
for (let node of change.addedNodes) {
|
|
906
|
+
if (node instanceof HTMLElement) {
|
|
907
|
+
let bindings2 = Array.from(node.querySelectorAll(`[${attribute}]`));
|
|
908
|
+
if (node.matches(`[${attribute}]`)) {
|
|
909
|
+
bindings2.unshift(node);
|
|
1480
910
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
// remove the scripts from the fragment, as they will not run in the
|
|
1484
|
-
// order in which they are defined
|
|
1485
|
-
var scriptsFragment = global.document.createDocumentFragment();
|
|
1486
|
-
// FIXME: this loses the original position of the script
|
|
1487
|
-
// should add a placeholder so we can reinsert the clone
|
|
1488
|
-
var scripts = fragment.querySelectorAll('script');
|
|
1489
|
-
[].forEach.call(scripts, function(script) {
|
|
1490
|
-
var placeholder = global.document.createComment(script.src || 'inline script');
|
|
1491
|
-
script.parentNode.insertBefore(placeholder, script);
|
|
1492
|
-
script.dataset.simplyLocation = scriptLocations.length;
|
|
1493
|
-
scriptLocations.push(placeholder);
|
|
1494
|
-
scriptsFragment.appendChild(script);
|
|
1495
|
-
});
|
|
1496
|
-
// add the remainder before the include link
|
|
1497
|
-
link.parentNode.insertBefore(fragment, link ? link : null);
|
|
1498
|
-
global.setTimeout(function() {
|
|
1499
|
-
if (global.editor && global.editor.data && fragment.querySelector('[data-simply-field],[data-simply-list]')) {
|
|
1500
|
-
//TODO: remove this dependency and let simply.bind listen for dom node insertions (and simply-edit.js use simply.bind)
|
|
1501
|
-
global.editor.data.apply(global.editor.currentData, global.document);
|
|
911
|
+
if (bindings2.length) {
|
|
912
|
+
applyBindings(bindings2);
|
|
1502
913
|
}
|
|
1503
|
-
|
|
1504
|
-
}, 10);
|
|
1505
|
-
}
|
|
1506
|
-
};
|
|
1507
|
-
|
|
1508
|
-
var included = {};
|
|
1509
|
-
var includeLinks = function(links) {
|
|
1510
|
-
// mark them as in progress, so handleChanges doesn't find them again
|
|
1511
|
-
var remainingLinks = [].reduce.call(links, function(remainder, link) {
|
|
1512
|
-
if (link.rel=='simply-include-once' && included[link.href]) {
|
|
1513
|
-
link.parentNode.removeChild(link);
|
|
1514
|
-
} else {
|
|
1515
|
-
included[link.href]=true;
|
|
1516
|
-
link.rel = 'simply-include-loading';
|
|
1517
|
-
remainder.push(link);
|
|
914
|
+
}
|
|
1518
915
|
}
|
|
1519
|
-
|
|
1520
|
-
}, []);
|
|
1521
|
-
[].forEach.call(remainingLinks, function(link) {
|
|
1522
|
-
if (!link.href) {
|
|
1523
|
-
return;
|
|
1524
|
-
}
|
|
1525
|
-
// fetch the html
|
|
1526
|
-
fetch(link.href)
|
|
1527
|
-
.then(function(response) {
|
|
1528
|
-
if (response.ok) {
|
|
1529
|
-
console.log('simply-include: loaded '+link.href);
|
|
1530
|
-
return response.text();
|
|
1531
|
-
} else {
|
|
1532
|
-
console.log('simply-include: failed to load '+link.href);
|
|
1533
|
-
}
|
|
1534
|
-
})
|
|
1535
|
-
.then(function(html) {
|
|
1536
|
-
// if succesfull import the html
|
|
1537
|
-
simply.include.html(html, link);
|
|
1538
|
-
// remove the include link
|
|
1539
|
-
link.parentNode.removeChild(link);
|
|
1540
|
-
});
|
|
1541
|
-
});
|
|
1542
|
-
};
|
|
1543
|
-
|
|
1544
|
-
var handleChanges = throttle(function() {
|
|
1545
|
-
runWhenIdle(function() {
|
|
1546
|
-
var links = global.document.querySelectorAll('link[rel="simply-include"],link[rel="simply-include-once"]');
|
|
1547
|
-
if (links.length) {
|
|
1548
|
-
includeLinks(links);
|
|
1549
|
-
}
|
|
1550
|
-
});
|
|
1551
|
-
});
|
|
1552
|
-
|
|
1553
|
-
var observe = function() {
|
|
1554
|
-
observer = new MutationObserver(handleChanges);
|
|
1555
|
-
observer.observe(global.document, {
|
|
1556
|
-
subtree: true,
|
|
1557
|
-
childList: true,
|
|
1558
|
-
});
|
|
1559
|
-
};
|
|
1560
|
-
|
|
1561
|
-
observe();
|
|
1562
|
-
handleChanges(); // check if there are include links in the dom already
|
|
1563
|
-
|
|
1564
|
-
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
1565
|
-
module.exports = include;
|
|
1566
|
-
} else {
|
|
1567
|
-
if (!global.simply) {
|
|
1568
|
-
global.simply = {};
|
|
916
|
+
}
|
|
1569
917
|
}
|
|
1570
|
-
|
|
918
|
+
};
|
|
919
|
+
this.observer = new MutationObserver((changes) => {
|
|
920
|
+
updateBindings(changes);
|
|
921
|
+
});
|
|
922
|
+
this.observer.observe(options.container, {
|
|
923
|
+
subtree: true,
|
|
924
|
+
childList: true
|
|
925
|
+
});
|
|
926
|
+
const bindings = this.options.container.querySelectorAll("[" + this.options.attribute + "]:not(template)");
|
|
927
|
+
if (bindings.length) {
|
|
928
|
+
applyBindings(bindings);
|
|
929
|
+
}
|
|
1571
930
|
}
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
931
|
+
/**
|
|
932
|
+
* Finds the first matching template and creates a new DocumentFragment
|
|
933
|
+
* with the correct data bind attributes in it (prepends the current path)
|
|
934
|
+
*/
|
|
935
|
+
applyTemplate(context) {
|
|
936
|
+
const path = context.path;
|
|
937
|
+
const templates = context.templates;
|
|
938
|
+
const list = context.list;
|
|
939
|
+
const index = context.index;
|
|
940
|
+
const parent = context.parent;
|
|
941
|
+
const value = list ? list[index] : context.value;
|
|
942
|
+
let template = this.findTemplate(templates, value);
|
|
943
|
+
if (!template) {
|
|
944
|
+
let result = new DocumentFragment();
|
|
945
|
+
result.innerHTML = "<!-- no matching template -->";
|
|
946
|
+
return result;
|
|
947
|
+
}
|
|
948
|
+
let clone = template.content.cloneNode(true);
|
|
949
|
+
if (!clone.children?.length) {
|
|
950
|
+
throw new Error("template must contain a single html element", { cause: template });
|
|
951
|
+
}
|
|
952
|
+
if (clone.children.length > 1) {
|
|
953
|
+
throw new Error("template must contain a single root node", { cause: template });
|
|
954
|
+
}
|
|
955
|
+
const bindings = clone.querySelectorAll("[" + this.options.attribute + "]");
|
|
956
|
+
const attribute = this.options.attribute;
|
|
957
|
+
for (let binding of bindings) {
|
|
958
|
+
const bind2 = binding.getAttribute(attribute);
|
|
959
|
+
if (bind2.substring(0, "#root.".length) == "#root.") {
|
|
960
|
+
binding.setAttribute(attribute, bind2.substring("#root.".length));
|
|
961
|
+
} else if (bind2 == "#value" && index != null) {
|
|
962
|
+
binding.setAttribute(attribute, path + "." + index);
|
|
963
|
+
} else if (index != null) {
|
|
964
|
+
binding.setAttribute(attribute, path + "." + index + "." + bind2);
|
|
1592
965
|
} else {
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
1602
|
-
module.exports = view;
|
|
1603
|
-
} else {
|
|
1604
|
-
if (!global.simply) {
|
|
1605
|
-
global.simply = {};
|
|
1606
|
-
}
|
|
1607
|
-
global.simply.view = view;
|
|
966
|
+
binding.setAttribute(attribute, parent + "." + bind2);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
if (typeof index !== "undefined") {
|
|
970
|
+
clone.children[0].setAttribute(attribute + "-key", index);
|
|
971
|
+
}
|
|
972
|
+
clone.children[0].$bindTemplate = template;
|
|
973
|
+
return clone;
|
|
1608
974
|
}
|
|
1609
|
-
|
|
1610
|
-
(
|
|
1611
|
-
'use strict';
|
|
1612
|
-
|
|
1613
|
-
function etag() {
|
|
1614
|
-
let d = '';
|
|
1615
|
-
while (d.length < 32) d += Math.random().toString(16).substr(2);
|
|
1616
|
-
const vr = ((parseInt(d.substr(16, 1), 16) & 0x3) | 0x8).toString(16);
|
|
1617
|
-
return `${d.substr(0, 8)}-${d.substr(8, 4)}-4${d.substr(13, 3)}-${vr}${d.substr(17, 3)}-${d.substr(20, 12)}`;
|
|
1618
|
-
}
|
|
1619
|
-
|
|
1620
|
-
function ViewModel(name, data, options) {
|
|
1621
|
-
this.name = name;
|
|
1622
|
-
this.data = data || [];
|
|
1623
|
-
this.data.etag = etag();
|
|
1624
|
-
this.view = {
|
|
1625
|
-
options: {},
|
|
1626
|
-
data: [] //Array.from(this.data).slice()
|
|
1627
|
-
};
|
|
1628
|
-
this.options = options || {};
|
|
1629
|
-
this.plugins = {
|
|
1630
|
-
start: [],
|
|
1631
|
-
select: [],
|
|
1632
|
-
order: [],
|
|
1633
|
-
render: [],
|
|
1634
|
-
finish: []
|
|
1635
|
-
};
|
|
975
|
+
getBindingPath(el) {
|
|
976
|
+
return el.getAttribute(this.options.attribute);
|
|
1636
977
|
}
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
978
|
+
/**
|
|
979
|
+
* Finds the first template from an array of templates that
|
|
980
|
+
* matches the given value.
|
|
981
|
+
*/
|
|
982
|
+
findTemplate(templates, value) {
|
|
983
|
+
const templateMatches = (t) => {
|
|
984
|
+
let path = this.getBindingPath(t);
|
|
985
|
+
let currentItem;
|
|
986
|
+
if (path) {
|
|
987
|
+
if (path.substr(0, 6) == "#root.") {
|
|
988
|
+
currentItem = getValueByPath(this.options.root, path);
|
|
989
|
+
} else {
|
|
990
|
+
currentItem = getValueByPath(value, path);
|
|
991
|
+
}
|
|
992
|
+
} else {
|
|
993
|
+
currentItem = value;
|
|
994
|
+
}
|
|
995
|
+
const strItem = "" + currentItem;
|
|
996
|
+
let matches = t.getAttribute(this.options.attribute + "-match");
|
|
997
|
+
if (matches) {
|
|
998
|
+
if (matches === "#empty" && !currentItem) {
|
|
999
|
+
return t;
|
|
1000
|
+
} else if (matches === "#notempty" && currentItem) {
|
|
1001
|
+
return t;
|
|
1002
|
+
}
|
|
1003
|
+
if (strItem.match(matches)) {
|
|
1004
|
+
return t;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
if (!matches) {
|
|
1008
|
+
if (currentItem) {
|
|
1009
|
+
return t;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
let template = Array.from(templates).find(templateMatches);
|
|
1014
|
+
let rel = template?.getAttribute("rel");
|
|
1015
|
+
if (rel) {
|
|
1016
|
+
let replacement = document.querySelector("template#" + rel);
|
|
1017
|
+
if (!replacement) {
|
|
1018
|
+
throw new Error("Could not find template with id " + rel);
|
|
1019
|
+
}
|
|
1020
|
+
template = replacement;
|
|
1021
|
+
}
|
|
1022
|
+
return template;
|
|
1023
|
+
}
|
|
1024
|
+
destroy() {
|
|
1025
|
+
this.bindings.forEach((binding) => {
|
|
1026
|
+
destroy(binding);
|
|
1027
|
+
});
|
|
1028
|
+
this.bindings = /* @__PURE__ */ new Map();
|
|
1029
|
+
this.observer.disconnect();
|
|
1030
|
+
}
|
|
1031
|
+
};
|
|
1032
|
+
function bind(options) {
|
|
1033
|
+
return new SimplyBind(options);
|
|
1034
|
+
}
|
|
1035
|
+
function matchValue(a, b) {
|
|
1036
|
+
if (a == "#empty" && !b) {
|
|
1037
|
+
return true;
|
|
1038
|
+
}
|
|
1039
|
+
if (b == "#empty" && !a) {
|
|
1040
|
+
return true;
|
|
1041
|
+
}
|
|
1042
|
+
if ("" + a == "" + b) {
|
|
1043
|
+
return true;
|
|
1044
|
+
}
|
|
1045
|
+
return false;
|
|
1046
|
+
}
|
|
1047
|
+
function getValueByPath(root, path) {
|
|
1048
|
+
let parts = path.split(".");
|
|
1049
|
+
let curr = root;
|
|
1050
|
+
let part, prevPart;
|
|
1051
|
+
while (parts.length && curr) {
|
|
1052
|
+
part = parts.shift();
|
|
1053
|
+
if (part == "#key") {
|
|
1054
|
+
return prevPart;
|
|
1055
|
+
} else if (part == "#value") {
|
|
1056
|
+
return curr;
|
|
1057
|
+
} else if (part == "#root") {
|
|
1058
|
+
curr = root;
|
|
1059
|
+
} else {
|
|
1060
|
+
part = decodeURIComponent(part);
|
|
1061
|
+
curr = curr[part];
|
|
1062
|
+
prevPart = part;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
return curr;
|
|
1066
|
+
}
|
|
1067
|
+
function defaultTransformer(context) {
|
|
1068
|
+
const el = context.element;
|
|
1069
|
+
const templates = context.templates;
|
|
1070
|
+
const templatesCount = templates.length;
|
|
1071
|
+
const path = context.path;
|
|
1072
|
+
const value = context.value;
|
|
1073
|
+
const attribute = this.options.attribute;
|
|
1074
|
+
if (Array.isArray(value) && templates?.length) {
|
|
1075
|
+
transformArrayByTemplates.call(this, context);
|
|
1076
|
+
} else if (typeof value == "object" && templates?.length) {
|
|
1077
|
+
transformObjectByTemplates.call(this, context);
|
|
1078
|
+
} else if (templates?.length) {
|
|
1079
|
+
transformLiteralByTemplates.call(this, context);
|
|
1080
|
+
} else if (el.tagName == "INPUT") {
|
|
1081
|
+
transformInput.call(this, context);
|
|
1082
|
+
} else if (el.tagName == "BUTTON") {
|
|
1083
|
+
transformButton.call(this, context);
|
|
1084
|
+
} else if (el.tagName == "SELECT") {
|
|
1085
|
+
transformSelect.call(this, context);
|
|
1086
|
+
} else if (el.tagName == "A") {
|
|
1087
|
+
transformAnchor.call(this, context);
|
|
1088
|
+
} else {
|
|
1089
|
+
transformElement.call(this, context);
|
|
1090
|
+
}
|
|
1091
|
+
return context;
|
|
1092
|
+
}
|
|
1093
|
+
function transformArrayByTemplates(context) {
|
|
1094
|
+
const el = context.element;
|
|
1095
|
+
const templates = context.templates;
|
|
1096
|
+
const templatesCount = templates.length;
|
|
1097
|
+
const path = context.path;
|
|
1098
|
+
const value = context.value;
|
|
1099
|
+
const attribute = this.options.attribute;
|
|
1100
|
+
let items = el.querySelectorAll(":scope > [" + attribute + "-key]");
|
|
1101
|
+
let lastKey = 0;
|
|
1102
|
+
let skipped = 0;
|
|
1103
|
+
context.list = value;
|
|
1104
|
+
for (let item of items) {
|
|
1105
|
+
let currentKey = parseInt(item.getAttribute(attribute + "-key"));
|
|
1106
|
+
if (currentKey > lastKey) {
|
|
1107
|
+
context.index = lastKey;
|
|
1108
|
+
el.insertBefore(this.applyTemplate(context), item);
|
|
1109
|
+
} else if (currentKey < lastKey) {
|
|
1110
|
+
item.remove();
|
|
1111
|
+
} else {
|
|
1112
|
+
let bindings = Array.from(item.querySelectorAll(`[${attribute}]`));
|
|
1113
|
+
if (item.matches(`[${attribute}]`)) {
|
|
1114
|
+
bindings.unshift(item);
|
|
1115
|
+
}
|
|
1116
|
+
let needsReplacement = bindings.find((b) => {
|
|
1117
|
+
let databind = b.getAttribute(attribute);
|
|
1118
|
+
return databind.substr(0, 5) !== "#root" && databind.substr(0, path.length) !== path;
|
|
1685
1119
|
});
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1120
|
+
if (!needsReplacement) {
|
|
1121
|
+
if (item.$bindTemplate) {
|
|
1122
|
+
let newTemplate = this.findTemplate(templates, value[lastKey]);
|
|
1123
|
+
if (newTemplate != item.$bindTemplate) {
|
|
1124
|
+
needsReplacement = true;
|
|
1125
|
+
if (!newTemplate) {
|
|
1126
|
+
skipped++;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
if (needsReplacement) {
|
|
1132
|
+
context.index = lastKey;
|
|
1133
|
+
el.replaceChild(this.applyTemplate(context), item);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
lastKey++;
|
|
1137
|
+
if (lastKey >= value.length) {
|
|
1138
|
+
break;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
items = el.querySelectorAll(":scope > [" + attribute + "-key]");
|
|
1142
|
+
let length = items.length + skipped;
|
|
1143
|
+
if (length > value.length) {
|
|
1144
|
+
while (length > value.length) {
|
|
1145
|
+
let child = el.querySelectorAll(":scope > :not(template)")?.[length - 1];
|
|
1146
|
+
child?.remove();
|
|
1147
|
+
length--;
|
|
1148
|
+
}
|
|
1149
|
+
} else if (length < value.length) {
|
|
1150
|
+
while (length < value.length) {
|
|
1151
|
+
context.index = length;
|
|
1152
|
+
el.appendChild(this.applyTemplate(context));
|
|
1153
|
+
length++;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
function transformObjectByTemplates(context) {
|
|
1158
|
+
const el = context.element;
|
|
1159
|
+
const templates = context.templates;
|
|
1160
|
+
const templatesCount = templates.length;
|
|
1161
|
+
const path = context.path;
|
|
1162
|
+
const value = context.value;
|
|
1163
|
+
const attribute = this.options.attribute;
|
|
1164
|
+
context.list = value;
|
|
1165
|
+
let list = Object.entries(value);
|
|
1166
|
+
let items = el.querySelectorAll(":scope > [" + attribute + "-key]");
|
|
1167
|
+
let current = 0;
|
|
1168
|
+
let skipped = 0;
|
|
1169
|
+
for (let item of items) {
|
|
1170
|
+
if (current >= list.length) {
|
|
1171
|
+
break;
|
|
1172
|
+
}
|
|
1173
|
+
let key = list[current][0];
|
|
1174
|
+
current++;
|
|
1175
|
+
let keypath = path + "." + key;
|
|
1176
|
+
let needsReplacement;
|
|
1177
|
+
const databind = item.getAttribute(attribute);
|
|
1178
|
+
if (databind && databind.substr(0, keypath.length) != keypath) {
|
|
1179
|
+
needsReplacement = true;
|
|
1180
|
+
} else {
|
|
1181
|
+
let bindings = Array.from(item.querySelectorAll(`[${attribute}]`));
|
|
1182
|
+
needsReplacement = bindings.find((b) => {
|
|
1183
|
+
const db = b.getAttribute(attribute);
|
|
1184
|
+
return db.substr(0, 5) !== "#root" && db.substr(0, keypath.length) !== keypath;
|
|
1691
1185
|
});
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
};
|
|
1710
|
-
};
|
|
1711
|
-
|
|
1712
|
-
var createPaging = function(options) {
|
|
1713
|
-
var defaultOptions = {
|
|
1714
|
-
name: 'paging',
|
|
1715
|
-
page: 1,
|
|
1716
|
-
pageSize: 100,
|
|
1717
|
-
max: 1,
|
|
1718
|
-
prev: 0,
|
|
1719
|
-
next: 0
|
|
1720
|
-
};
|
|
1721
|
-
options = Object.assign(defaultOptions, options || {});
|
|
1722
|
-
|
|
1723
|
-
return function(params) {
|
|
1724
|
-
this.options[options.name] = options;
|
|
1725
|
-
if (this.view.data) {
|
|
1726
|
-
options.max = Math.max(1, Math.ceil(Array.from(this.view.data).length / options.pageSize));
|
|
1727
|
-
} else {
|
|
1728
|
-
options.max = 1;
|
|
1729
|
-
}
|
|
1730
|
-
if (this.view.changed) {
|
|
1731
|
-
options.page = 1; // reset to page 1 when something in the view data has changed
|
|
1732
|
-
}
|
|
1733
|
-
if (params[options.name]) {
|
|
1734
|
-
options = Object.assign(options, params[options.name]);
|
|
1735
|
-
}
|
|
1736
|
-
options.page = Math.max(1, Math.min(options.max, options.page)); // clamp page nr
|
|
1737
|
-
options.prev = options.page - 1; // calculate previous page, 0 is allowed
|
|
1738
|
-
if (options.page<options.max) {
|
|
1739
|
-
options.next = options.page + 1;
|
|
1740
|
-
} else {
|
|
1741
|
-
options.next = 0; // no next page
|
|
1742
|
-
}
|
|
1743
|
-
|
|
1744
|
-
var start = (options.page - 1) * options.pageSize;
|
|
1745
|
-
var end = start + options.pageSize;
|
|
1746
|
-
|
|
1747
|
-
this.view.data = this.view.data.slice(start, end);
|
|
1748
|
-
};
|
|
1749
|
-
};
|
|
1750
|
-
|
|
1751
|
-
var createFilter = function(options) {
|
|
1752
|
-
var defaultOptions = {
|
|
1753
|
-
name: 'filter',
|
|
1754
|
-
label: 'A filter',
|
|
1755
|
-
getMatch: function(entry) {
|
|
1756
|
-
return false;
|
|
1757
|
-
}
|
|
1758
|
-
};
|
|
1759
|
-
options = Object.assign(defaultOptions, options || {});
|
|
1760
|
-
if (options.init) {
|
|
1761
|
-
options.init.call(this, options);
|
|
1762
|
-
}
|
|
1763
|
-
return function(params) {
|
|
1764
|
-
this.options[options.name] = options;
|
|
1765
|
-
if (params[options.name]) {
|
|
1766
|
-
options = Object.assign(options, params[options.name]);
|
|
1767
|
-
}
|
|
1768
|
-
var match = options.getMatch.call(this, options);
|
|
1769
|
-
if (match) {
|
|
1770
|
-
options.enabled = true;
|
|
1771
|
-
this.view.data = this.view.data.filter(match);
|
|
1772
|
-
} else if (options.enabled) {
|
|
1773
|
-
options.enabled = false;
|
|
1774
|
-
}
|
|
1775
|
-
}
|
|
1186
|
+
if (!needsReplacement) {
|
|
1187
|
+
if (item.$bindTemplate) {
|
|
1188
|
+
let newTemplate = this.findTemplate(templates, value[key]);
|
|
1189
|
+
if (newTemplate != item.$bindTemplate) {
|
|
1190
|
+
needsReplacement = true;
|
|
1191
|
+
if (!newTemplate) {
|
|
1192
|
+
skipped++;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
if (needsReplacement) {
|
|
1199
|
+
context.index = key;
|
|
1200
|
+
let clone = this.applyTemplate(context);
|
|
1201
|
+
el.replaceChild(clone, item);
|
|
1202
|
+
}
|
|
1776
1203
|
}
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1204
|
+
items = el.querySelectorAll(":scope > [" + attribute + "-key]");
|
|
1205
|
+
let length = items.length + skipped;
|
|
1206
|
+
if (length > list.length) {
|
|
1207
|
+
while (length > list.length) {
|
|
1208
|
+
let child = el.querySelectorAll(":scope > :not(template)")?.[length - 1];
|
|
1209
|
+
child?.remove();
|
|
1210
|
+
length--;
|
|
1211
|
+
}
|
|
1212
|
+
} else if (length < list.length) {
|
|
1213
|
+
while (length < list.length) {
|
|
1214
|
+
context.index = list[length][0];
|
|
1215
|
+
el.appendChild(this.applyTemplate(context));
|
|
1216
|
+
length++;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
function transformLiteralByTemplates(context) {
|
|
1221
|
+
const el = context.element;
|
|
1222
|
+
const templates = context.templates;
|
|
1223
|
+
const value = context.value;
|
|
1224
|
+
const attribute = this.options.attribute;
|
|
1225
|
+
const rendered = el.querySelector(":scope > :not(template)");
|
|
1226
|
+
const template = this.findTemplate(templates, value);
|
|
1227
|
+
context.parent = el.parentElement?.closest(`[${attribute}]`)?.getAttribute(attribute) || "#root";
|
|
1228
|
+
if (rendered) {
|
|
1229
|
+
if (template) {
|
|
1230
|
+
if (rendered?.$bindTemplate != template) {
|
|
1231
|
+
const clone = this.applyTemplate(context);
|
|
1232
|
+
el.replaceChild(clone, rendered);
|
|
1233
|
+
}
|
|
1234
|
+
} else {
|
|
1235
|
+
el.removeChild(rendered);
|
|
1236
|
+
}
|
|
1237
|
+
} else if (template) {
|
|
1238
|
+
const clone = this.applyTemplate(context);
|
|
1239
|
+
el.appendChild(clone);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
function transformInput(context) {
|
|
1243
|
+
const el = context.element;
|
|
1244
|
+
const value = context.value;
|
|
1245
|
+
if (el.type == "checkbox" || el.type == "radio") {
|
|
1246
|
+
if (matchValue(el.value, value)) {
|
|
1247
|
+
el.checked = true;
|
|
1248
|
+
} else {
|
|
1249
|
+
el.checked = false;
|
|
1250
|
+
}
|
|
1251
|
+
} else if (!matchValue(el.value, value)) {
|
|
1252
|
+
el.value = "" + value;
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
function transformButton(context) {
|
|
1256
|
+
const el = context.element;
|
|
1257
|
+
const value = context.value;
|
|
1258
|
+
if (!matchValue(el.value, value)) {
|
|
1259
|
+
el.value = "" + value;
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
function transformSelect(context) {
|
|
1263
|
+
const el = context.element;
|
|
1264
|
+
const value = context.value;
|
|
1265
|
+
if (el.multiple) {
|
|
1266
|
+
if (Array.isArray(value)) {
|
|
1267
|
+
for (let option of el.options) {
|
|
1268
|
+
if (value.indexOf(option.value) === false) {
|
|
1269
|
+
option.selected = false;
|
|
1270
|
+
} else {
|
|
1271
|
+
option.selected = true;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1791
1275
|
} else {
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1276
|
+
let option = el.options.find((o) => matchValue(o.value, value));
|
|
1277
|
+
if (option) {
|
|
1278
|
+
option.selected = true;
|
|
1279
|
+
}
|
|
1796
1280
|
}
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
* Returns a Proxy object that translates property access to a URL in the api
|
|
1804
|
-
* and method calls to a fetch on that URL.
|
|
1805
|
-
* @param options: a list of options for fetch(),
|
|
1806
|
-
* see the 'init' parameter at https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters
|
|
1807
|
-
* additionally:
|
|
1808
|
-
* - baseURL: (required) the endpoint of the API
|
|
1809
|
-
* - path: the current path in the API, is appended to the baseURL
|
|
1810
|
-
* - verbs: list of http verbs to allow as methods, default ['get','post']
|
|
1811
|
-
* - handlers.fetch: alternative fetch method
|
|
1812
|
-
* - handlers.result: alternative getResult method
|
|
1813
|
-
* - handlers.error: alternative error method
|
|
1814
|
-
* - user (and password): if set, a basic authentication header will be added
|
|
1815
|
-
* - paramsFormat: either 'formData', 'json' or 'search'. Default is search.
|
|
1816
|
-
* - responseFormat: test, formData, blob, json, arrayBuffer or unbuffered. Default is json.
|
|
1817
|
-
* @return Proxy
|
|
1818
|
-
*/
|
|
1819
|
-
proxy: function(options) {
|
|
1820
|
-
var cache = () => {};
|
|
1821
|
-
cache.$options = Object.assign({}, options);
|
|
1822
|
-
return new Proxy( cache, getApiHandler(cache.$options) );
|
|
1823
|
-
},
|
|
1824
|
-
|
|
1825
|
-
/**
|
|
1826
|
-
* Fetches the options.baseURL using the fetch api and returns a promise
|
|
1827
|
-
* Extra options in addition to those of global.fetch():
|
|
1828
|
-
* - user (and password): if set, a basic authentication header will be added
|
|
1829
|
-
* - paramsFormat: either 'formData', 'json' or 'search'
|
|
1830
|
-
* By default params, if set, will be added to the baseURL as searchParams
|
|
1831
|
-
* @param method one of the http verbs, e.g. get, post, etc.
|
|
1832
|
-
* @param options the options for fetch(), with some additions
|
|
1833
|
-
* @param params the parameters to send with the request, as javascript/json data
|
|
1834
|
-
* @return Promise
|
|
1835
|
-
*/
|
|
1836
|
-
fetch: function(method, params, options) {
|
|
1837
|
-
if (!options.url) {
|
|
1838
|
-
if (!options.baseURL) {
|
|
1839
|
-
throw new Error('No url or baseURL in options object');
|
|
1840
|
-
}
|
|
1841
|
-
while (options.baseURL[options.baseURL.length-1]=='/') {
|
|
1842
|
-
options.baseURL = options.baseURL.substr(0, options.baseURL.length-1);
|
|
1843
|
-
}
|
|
1844
|
-
var url = new URL(options.baseURL+options.path);
|
|
1845
|
-
} else {
|
|
1846
|
-
var url = options.url;
|
|
1847
|
-
}
|
|
1848
|
-
var fetchOptions = Object.assign({}, options);
|
|
1849
|
-
if (!fetchOptions.headers) {
|
|
1850
|
-
fetchOptions.headers = {};
|
|
1851
|
-
}
|
|
1852
|
-
if (params) {
|
|
1853
|
-
if (method=='GET') {
|
|
1854
|
-
var paramsFormat = 'search';
|
|
1855
|
-
} else {
|
|
1856
|
-
var paramsFormat = options.paramsFormat;
|
|
1857
|
-
}
|
|
1858
|
-
switch(paramsFormat) {
|
|
1859
|
-
case 'formData':
|
|
1860
|
-
var formData = new FormData();
|
|
1861
|
-
for (const name in params) {
|
|
1862
|
-
formData.append(name, params[name]);
|
|
1863
|
-
}
|
|
1864
|
-
if (!fetchOptions.headers['Content-Type']) {
|
|
1865
|
-
fetchOptions.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
1866
|
-
}
|
|
1867
|
-
break;
|
|
1868
|
-
case 'json':
|
|
1869
|
-
var formData = JSON.stringify(params);
|
|
1870
|
-
if (!fetchOptions.headers['Content-Type']) {
|
|
1871
|
-
fetchOptions.headers['Content-Type'] = 'application/json';
|
|
1872
|
-
}
|
|
1873
|
-
break;
|
|
1874
|
-
case 'search':
|
|
1875
|
-
var searchParams = url.searchParams; //new URLSearchParams(url.search.slice(1));
|
|
1876
|
-
for (const name in params) {
|
|
1877
|
-
searchParams.set(name, params[name]);
|
|
1878
|
-
}
|
|
1879
|
-
url.search = searchParams.toString();
|
|
1880
|
-
break;
|
|
1881
|
-
default:
|
|
1882
|
-
throw Error('Unknown options.paramsFormat '+options.paramsFormat+'. Select one of formData, json or search.');
|
|
1883
|
-
break;
|
|
1884
|
-
}
|
|
1885
|
-
}
|
|
1886
|
-
if (formData) {
|
|
1887
|
-
fetchOptions.body = formData
|
|
1888
|
-
}
|
|
1889
|
-
if (options.user) {
|
|
1890
|
-
fetchOptions.headers['Authorization'] = 'Basic '+btoa(options.user+':'+options.password);
|
|
1891
|
-
}
|
|
1892
|
-
fetchOptions.method = method.toUpperCase();
|
|
1893
|
-
var fetchURL = url.toString()
|
|
1894
|
-
return fetch(fetchURL, fetchOptions);
|
|
1895
|
-
},
|
|
1896
|
-
/**
|
|
1897
|
-
* Creates a function to call one or more graphql queries
|
|
1898
|
-
*/
|
|
1899
|
-
graphqlQuery: function(url, query, options) {
|
|
1900
|
-
options = Object.assign({ paramsFormat: 'json', url: url, responseFormat: 'json' }, options);
|
|
1901
|
-
return function(params, operationName) {
|
|
1902
|
-
let postParams = {
|
|
1903
|
-
query: query
|
|
1904
|
-
};
|
|
1905
|
-
if (operationName) {
|
|
1906
|
-
postParams.operationName = operationName;
|
|
1907
|
-
}
|
|
1908
|
-
postParams.variables = params || {};
|
|
1909
|
-
return simply.api.fetch('POST', postParams, options )
|
|
1910
|
-
.then(function(response) {
|
|
1911
|
-
return simply.api.getResult(response, options);
|
|
1912
|
-
});
|
|
1913
|
-
}
|
|
1914
|
-
},
|
|
1915
|
-
/**
|
|
1916
|
-
* Handles the response and returns a Promise with the response data as specified
|
|
1917
|
-
* @param response Response
|
|
1918
|
-
* @param options
|
|
1919
|
-
* - responseFormat: one of 'text', 'formData', 'blob', 'arrayBuffer', 'unbuffered' or 'json'.
|
|
1920
|
-
* The default is json.
|
|
1921
|
-
*/
|
|
1922
|
-
getResult: function(response, options) {
|
|
1923
|
-
if (response.ok) {
|
|
1924
|
-
switch(options.responseFormat) {
|
|
1925
|
-
case 'text':
|
|
1926
|
-
return response.text();
|
|
1927
|
-
break;
|
|
1928
|
-
case 'formData':
|
|
1929
|
-
return response.formData();
|
|
1930
|
-
break;
|
|
1931
|
-
case 'blob':
|
|
1932
|
-
return response.blob();
|
|
1933
|
-
break;
|
|
1934
|
-
case 'arrayBuffer':
|
|
1935
|
-
return response.arrayBuffer();
|
|
1936
|
-
break;
|
|
1937
|
-
case 'unbuffered':
|
|
1938
|
-
return response.body;
|
|
1939
|
-
break;
|
|
1940
|
-
case 'json':
|
|
1941
|
-
default:
|
|
1942
|
-
return response.json();
|
|
1943
|
-
break;
|
|
1944
|
-
}
|
|
1945
|
-
} else {
|
|
1946
|
-
throw {
|
|
1947
|
-
status: response.status,
|
|
1948
|
-
message: response.statusText,
|
|
1949
|
-
response: response
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
|
-
},
|
|
1953
|
-
logError: function(error, options) {
|
|
1954
|
-
console.error(error.status, error.message);
|
|
1955
|
-
}
|
|
1281
|
+
}
|
|
1282
|
+
function transformAnchor(context) {
|
|
1283
|
+
const el = context.element;
|
|
1284
|
+
const value = context.value;
|
|
1285
|
+
if (value?.innerHTML && !matchValue(el.innerHTML, value.innerHTML)) {
|
|
1286
|
+
el.innerHTML = "" + value.innerHTML;
|
|
1956
1287
|
}
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1288
|
+
if (value?.href && !matchValue(el.href, value.href)) {
|
|
1289
|
+
el.href = "" + value.href;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
function transformElement(context) {
|
|
1293
|
+
const el = context.element;
|
|
1294
|
+
const value = context.value;
|
|
1295
|
+
if (!matchValue(el.innerHTML, value)) {
|
|
1296
|
+
el.innerHTML = "" + value;
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// src/app.mjs
|
|
1301
|
+
var SimplyApp = class {
|
|
1302
|
+
constructor(options = {}) {
|
|
1303
|
+
this.container = options.container || document.body;
|
|
1304
|
+
if (!options.state) {
|
|
1305
|
+
options.state = {};
|
|
1306
|
+
}
|
|
1307
|
+
this.state = signal(options.state);
|
|
1308
|
+
if (options.commands) {
|
|
1309
|
+
this.commands = commands({ app: this, container: this.container, commands: options.commands });
|
|
1310
|
+
}
|
|
1311
|
+
if (options.keys) {
|
|
1312
|
+
this.keys = keys({ app: this, keys: options.keys });
|
|
1313
|
+
}
|
|
1314
|
+
if (options.routes) {
|
|
1315
|
+
this.routes = routes({ app: this, routes: options.routes });
|
|
1316
|
+
}
|
|
1317
|
+
if (options.actions) {
|
|
1318
|
+
this.actions = actions({ app: this, actions: options.actions });
|
|
1319
|
+
}
|
|
1320
|
+
let bindOptions = { container: this.container, root: this.state };
|
|
1321
|
+
if (options.defaultTransformers) {
|
|
1322
|
+
bindOptions.defaultTransformers = options.defaultTransformers;
|
|
1323
|
+
}
|
|
1324
|
+
if (options.transformers) {
|
|
1325
|
+
bindOptions.transformers = options.transformers;
|
|
1326
|
+
}
|
|
1327
|
+
this.bind = bind(bindOptions);
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
function app(options = {}) {
|
|
1331
|
+
return new SimplyApp(options);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// src/include.mjs
|
|
1335
|
+
function throttle(callbackFunction, intervalTime) {
|
|
1336
|
+
let eventId = 0;
|
|
1337
|
+
return () => {
|
|
1338
|
+
const myArguments = arguments;
|
|
1339
|
+
if (eventId) {
|
|
1340
|
+
return;
|
|
1341
|
+
} else {
|
|
1342
|
+
eventId = globalThis.setTimeout(() => {
|
|
1343
|
+
callbackFunction.apply(this, myArguments);
|
|
1344
|
+
eventId = 0;
|
|
1345
|
+
}, intervalTime);
|
|
1346
|
+
}
|
|
1968
1347
|
};
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
return path+encodeURIComponent(name);
|
|
1348
|
+
}
|
|
1349
|
+
var runWhenIdle = (() => {
|
|
1350
|
+
if (globalThis.requestIdleCallback) {
|
|
1351
|
+
return (callback) => {
|
|
1352
|
+
globalThis.requestIdleCallback(callback, { timeout: 500 });
|
|
1353
|
+
};
|
|
1976
1354
|
}
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
return options.handlers.result.call(options, res, options);
|
|
1984
|
-
})
|
|
1985
|
-
.catch(function(error) {
|
|
1986
|
-
return options.handlers.error.call(options, error, options);
|
|
1987
|
-
});
|
|
1355
|
+
return globalThis.requestAnimationFrame;
|
|
1356
|
+
})();
|
|
1357
|
+
function rebaseHref(relative, base) {
|
|
1358
|
+
let url = new URL(relative, base);
|
|
1359
|
+
if (include.cacheBuster) {
|
|
1360
|
+
url.searchParams.set("cb", include.cacheBuster);
|
|
1988
1361
|
}
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
1362
|
+
return url.href;
|
|
1363
|
+
}
|
|
1364
|
+
var observer2;
|
|
1365
|
+
var loaded = {};
|
|
1366
|
+
var head = globalThis.document.querySelector("head");
|
|
1367
|
+
var currentScript = globalThis.document.currentScript;
|
|
1368
|
+
var getScriptURL;
|
|
1369
|
+
var currentScriptURL;
|
|
1370
|
+
if (!currentScript) {
|
|
1371
|
+
getScriptURL = (() => {
|
|
1372
|
+
var scripts = document.getElementsByTagName("script");
|
|
1373
|
+
var index = scripts.length - 1;
|
|
1374
|
+
var myScript = scripts[index];
|
|
1375
|
+
return () => myScript.src;
|
|
1376
|
+
})();
|
|
1377
|
+
currentScriptURL = getScriptURL();
|
|
1378
|
+
} else {
|
|
1379
|
+
currentScriptURL = currentScript.src;
|
|
1380
|
+
}
|
|
1381
|
+
var waitForPreviousScripts = async () => {
|
|
1382
|
+
return new Promise(function(resolve) {
|
|
1383
|
+
var next = globalThis.document.createElement("script");
|
|
1384
|
+
next.src = rebaseHref("simply.include.next.js", currentScriptURL);
|
|
1385
|
+
next.async = false;
|
|
1386
|
+
globalThis.document.addEventListener("simply-include-next", () => {
|
|
1387
|
+
head.removeChild(next);
|
|
1388
|
+
resolve();
|
|
1389
|
+
}, { once: true, passive: true });
|
|
1390
|
+
head.appendChild(next);
|
|
1391
|
+
});
|
|
1392
|
+
};
|
|
1393
|
+
var scriptLocations = [];
|
|
1394
|
+
var include = {
|
|
1395
|
+
cacheBuster: null,
|
|
1396
|
+
scripts: (scripts, base) => {
|
|
1397
|
+
let arr = scripts.slice();
|
|
1398
|
+
const importScript = () => {
|
|
1399
|
+
const script = arr.shift();
|
|
1400
|
+
if (!script) {
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
const attrs = [].map.call(script.attributes, (attr) => {
|
|
1404
|
+
return attr.name;
|
|
1405
|
+
});
|
|
1406
|
+
let clone = globalThis.document.createElement("script");
|
|
1407
|
+
for (const attr of attrs) {
|
|
1408
|
+
clone.setAttribute(attr, script.getAttribute(attr));
|
|
1409
|
+
}
|
|
1410
|
+
clone.removeAttribute("data-simply-location");
|
|
1411
|
+
if (!clone.src) {
|
|
1412
|
+
clone.innerHTML = script.innerHTML;
|
|
1413
|
+
waitForPreviousScripts().then(() => {
|
|
1414
|
+
const node = scriptLocations[script.dataset.simplyLocation];
|
|
1415
|
+
node.parentNode.insertBefore(clone, node);
|
|
1416
|
+
node.parentNode.removeChild(node);
|
|
1417
|
+
importScript();
|
|
1418
|
+
});
|
|
1419
|
+
} else {
|
|
1420
|
+
clone.src = rebaseHref(clone.src, base);
|
|
1421
|
+
if (!clone.hasAttribute("async") && !clone.hasAttribute("defer")) {
|
|
1422
|
+
clone.async = false;
|
|
1423
|
+
}
|
|
1424
|
+
const node = scriptLocations[script.dataset.simplyLocation];
|
|
1425
|
+
node.parentNode.insertBefore(clone, node);
|
|
1426
|
+
node.parentNode.removeChild(node);
|
|
1427
|
+
loaded[clone.src] = true;
|
|
1428
|
+
importScript();
|
|
1429
|
+
}
|
|
1430
|
+
};
|
|
1431
|
+
if (arr.length) {
|
|
1432
|
+
importScript();
|
|
1433
|
+
}
|
|
1434
|
+
},
|
|
1435
|
+
html: (html, link) => {
|
|
1436
|
+
let fragment = globalThis.document.createRange().createContextualFragment(html);
|
|
1437
|
+
const stylesheets = fragment.querySelectorAll('link[rel="stylesheet"],style');
|
|
1438
|
+
for (let stylesheet of stylesheets) {
|
|
1439
|
+
if (stylesheet.href) {
|
|
1440
|
+
stylesheet.href = rebaseHref(stylesheet.href, link.href);
|
|
1441
|
+
}
|
|
1442
|
+
head.appendChild(stylesheet);
|
|
1443
|
+
}
|
|
1444
|
+
let scriptsFragment = globalThis.document.createDocumentFragment();
|
|
1445
|
+
const scripts = fragment.querySelectorAll("script");
|
|
1446
|
+
for (let script of scripts) {
|
|
1447
|
+
let placeholder = globalThis.document.createComment(script.src || "inline script");
|
|
1448
|
+
script.parentNode.insertBefore(placeholder, script);
|
|
1449
|
+
script.dataset.simplyLocation = scriptLocations.length;
|
|
1450
|
+
scriptLocations.push(placeholder);
|
|
1451
|
+
scriptsFragment.appendChild(script);
|
|
1452
|
+
}
|
|
1453
|
+
link.parentNode.insertBefore(fragment, link ? link : null);
|
|
1454
|
+
globalThis.setTimeout(function() {
|
|
1455
|
+
include.scripts(scriptsFragment.childNodes, link ? link.href : globalThis.location.href);
|
|
1456
|
+
}, 10);
|
|
2013
1457
|
}
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
1458
|
+
};
|
|
1459
|
+
var included = {};
|
|
1460
|
+
var includeLinks = async (links) => {
|
|
1461
|
+
let remainingLinks = [].reduce.call(links, (remainder, link) => {
|
|
1462
|
+
if (link.rel == "simply-include-once" && included[link.href]) {
|
|
1463
|
+
link.parentNode.removeChild(link);
|
|
1464
|
+
} else {
|
|
1465
|
+
included[link.href] = true;
|
|
1466
|
+
link.rel = "simply-include-loading";
|
|
1467
|
+
remainder.push(link);
|
|
1468
|
+
}
|
|
1469
|
+
return remainder;
|
|
1470
|
+
}, []);
|
|
1471
|
+
for (let link of remainingLinks) {
|
|
1472
|
+
if (!link.href) {
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1475
|
+
const response = await fetch(link.href);
|
|
1476
|
+
if (!response.ok) {
|
|
1477
|
+
console.log("simply-include: failed to load " + link.href);
|
|
1478
|
+
continue;
|
|
1479
|
+
}
|
|
1480
|
+
console.log("simply-include: loaded " + link.href);
|
|
1481
|
+
const html = await response.text();
|
|
1482
|
+
include.html(html, link);
|
|
1483
|
+
link.parentNode.removeChild(link);
|
|
2023
1484
|
}
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
(
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
1485
|
+
};
|
|
1486
|
+
var handleChanges2 = throttle(() => {
|
|
1487
|
+
runWhenIdle(() => {
|
|
1488
|
+
var links = globalThis.document.querySelectorAll('link[rel="simply-include"],link[rel="simply-include-once"]');
|
|
1489
|
+
if (links.length) {
|
|
1490
|
+
includeLinks(links);
|
|
1491
|
+
}
|
|
1492
|
+
});
|
|
1493
|
+
});
|
|
1494
|
+
var observe = () => {
|
|
1495
|
+
observer2 = new MutationObserver(handleChanges2);
|
|
1496
|
+
observer2.observe(globalThis.document, {
|
|
1497
|
+
subtree: true,
|
|
1498
|
+
childList: true
|
|
1499
|
+
});
|
|
1500
|
+
};
|
|
1501
|
+
observe();
|
|
1502
|
+
handleChanges2();
|
|
1503
|
+
|
|
1504
|
+
// src/model.mjs
|
|
1505
|
+
var model_exports = {};
|
|
1506
|
+
__export(model_exports, {
|
|
1507
|
+
columns: () => columns,
|
|
1508
|
+
filter: () => filter,
|
|
1509
|
+
model: () => model,
|
|
1510
|
+
paging: () => paging,
|
|
1511
|
+
sort: () => sort
|
|
1512
|
+
});
|
|
1513
|
+
var SimplyModel = class {
|
|
1514
|
+
/**
|
|
1515
|
+
* Creates a new datamodel, with a state property that contains
|
|
1516
|
+
* all the data passed to this constructor
|
|
1517
|
+
* @param state Object with all the data for this model
|
|
1518
|
+
*/
|
|
1519
|
+
constructor(state) {
|
|
1520
|
+
this.state = signal(state);
|
|
1521
|
+
if (!this.state.options) {
|
|
1522
|
+
this.state.options = {};
|
|
1523
|
+
}
|
|
1524
|
+
this.effects = [{ current: state.data }];
|
|
1525
|
+
this.view = signal(state.data);
|
|
1526
|
+
}
|
|
1527
|
+
/**
|
|
1528
|
+
* Adds an effect to run whenever a signal it depends on
|
|
1529
|
+
* changes. this.state is the usual signal.
|
|
1530
|
+
* The `fn` function param is not itself an effect, but must return
|
|
1531
|
+
* and effect function. `fn` takes one param, which is the data signal.
|
|
1532
|
+
* This signal will always have at least a `current` property.
|
|
1533
|
+
* The result of the effect function is pushed on to the this.effects
|
|
1534
|
+
* list. And the last effect added is set as this.view
|
|
1535
|
+
*/
|
|
1536
|
+
addEffect(fn) {
|
|
1537
|
+
const dataSignal = this.effects[this.effects.length - 1];
|
|
1538
|
+
this.view = fn.call(this, dataSignal);
|
|
1539
|
+
this.effects.push(this.view);
|
|
1540
|
+
}
|
|
1541
|
+
};
|
|
1542
|
+
function model(options) {
|
|
1543
|
+
return new SimplyModel(options);
|
|
1544
|
+
}
|
|
1545
|
+
function sort(options = {}) {
|
|
1546
|
+
return function(data) {
|
|
1547
|
+
this.state.options.sort = Object.assign({
|
|
1548
|
+
direction: "asc",
|
|
1549
|
+
sortBy: null,
|
|
1550
|
+
sortFn: (a, b) => {
|
|
1551
|
+
const sort2 = this.state.options.sort;
|
|
1552
|
+
const sortBy = sort2.sortBy;
|
|
1553
|
+
if (!sort2.sortBy) {
|
|
1554
|
+
return 0;
|
|
1555
|
+
}
|
|
1556
|
+
const larger = sort2.direction == "asc" ? 1 : -1;
|
|
1557
|
+
const smaller = sort2.direction == "asc" ? -1 : 1;
|
|
1558
|
+
if (typeof a?.[sortBy] === "undefined") {
|
|
1559
|
+
if (typeof b?.[sortBy] === "undefined") {
|
|
1560
|
+
return 0;
|
|
1561
|
+
}
|
|
1562
|
+
return larger;
|
|
1563
|
+
}
|
|
1564
|
+
if (typeof b?.[sortBy] === "undefined") {
|
|
1565
|
+
return smaller;
|
|
1566
|
+
}
|
|
1567
|
+
if (a[sortBy] < b[sortBy]) {
|
|
1568
|
+
return smaller;
|
|
1569
|
+
} else if (a[sortBy] > b[sortBy]) {
|
|
1570
|
+
return larger;
|
|
1571
|
+
} else {
|
|
1572
|
+
return 0;
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
}, options);
|
|
1576
|
+
return effect(() => {
|
|
1577
|
+
const sort2 = this.state.options.sort;
|
|
1578
|
+
if (sort2?.sortBy && sort2?.direction) {
|
|
1579
|
+
return data.current.toSorted(sort2?.sortFn);
|
|
1580
|
+
}
|
|
1581
|
+
return data.current;
|
|
1582
|
+
});
|
|
2077
1583
|
};
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
1584
|
+
}
|
|
1585
|
+
function paging(options = {}) {
|
|
1586
|
+
return function(data) {
|
|
1587
|
+
this.state.options.paging = Object.assign({
|
|
1588
|
+
page: 1,
|
|
1589
|
+
pageSize: 20,
|
|
1590
|
+
max: 1
|
|
1591
|
+
}, options);
|
|
1592
|
+
return effect(() => {
|
|
1593
|
+
return batch(() => {
|
|
1594
|
+
const paging2 = this.state.options.paging;
|
|
1595
|
+
if (!paging2.pageSize) {
|
|
1596
|
+
paging2.pageSize = 20;
|
|
1597
|
+
}
|
|
1598
|
+
paging2.max = Math.ceil(this.state.data.length / paging2.pageSize);
|
|
1599
|
+
paging2.page = Math.max(1, Math.min(paging2.max, paging2.page));
|
|
1600
|
+
const start = (paging2.page - 1) * paging2.pageSize;
|
|
1601
|
+
const end = start + paging2.pageSize;
|
|
1602
|
+
return data.current.slice(start, end);
|
|
1603
|
+
});
|
|
1604
|
+
});
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1607
|
+
function filter(options) {
|
|
1608
|
+
if (!options?.name || typeof options.name !== "string") {
|
|
1609
|
+
throw new Error("filter requires options.name to be a string");
|
|
1610
|
+
}
|
|
1611
|
+
if (!options.matches || typeof options.matches !== "function") {
|
|
1612
|
+
throw new Error("filter requires options.matches to be a function");
|
|
1613
|
+
}
|
|
1614
|
+
return function(data) {
|
|
1615
|
+
this.state.options[options.name] = options;
|
|
1616
|
+
return effect(() => {
|
|
1617
|
+
if (this.state.options[options.name].enabled) {
|
|
1618
|
+
return data.filter(this.state.options.matches);
|
|
2084
1619
|
}
|
|
2085
|
-
|
|
1620
|
+
});
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1623
|
+
function columns(options = {}) {
|
|
1624
|
+
if (!options || typeof options !== "object" || Object.keys(options).length === 0) {
|
|
1625
|
+
throw new Error("columns requires options to be an object with at least one property");
|
|
2086
1626
|
}
|
|
2087
|
-
|
|
2088
|
-
|
|
1627
|
+
return function(data) {
|
|
1628
|
+
this.state.options.columns = options;
|
|
1629
|
+
return effect(() => {
|
|
1630
|
+
return data.current.map((input) => {
|
|
1631
|
+
let result = {};
|
|
1632
|
+
for (let key of Object.keys(this.state.options.columns)) {
|
|
1633
|
+
if (!this.state.options.columns[key].hidden) {
|
|
1634
|
+
result[key] = input[key];
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
return result;
|
|
1638
|
+
});
|
|
1639
|
+
});
|
|
1640
|
+
};
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
// src/everything.mjs
|
|
1644
|
+
var simply = {
|
|
1645
|
+
activate,
|
|
1646
|
+
action: action_exports,
|
|
1647
|
+
app,
|
|
1648
|
+
bind,
|
|
1649
|
+
command: command_exports,
|
|
1650
|
+
include,
|
|
1651
|
+
key: key_exports,
|
|
1652
|
+
model: model_exports,
|
|
1653
|
+
route: route_exports,
|
|
1654
|
+
state: state_exports
|
|
1655
|
+
};
|
|
1656
|
+
window.simply = simply;
|
|
1657
|
+
var everything_default = simply;
|
|
1658
|
+
})();
|