native-document 1.0.94 → 1.0.98
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/{src/devtools/hrm → devtools}/ComponentRegistry.js +2 -2
- package/devtools/index.js +8 -0
- package/{src/devtools/plugin.js → devtools/plugin/dev-tools-plugin.js} +2 -2
- package/{src/devtools/hrm/nd-vite-hot-reload.js → devtools/transformers/nd-vite-devtools.js} +16 -6
- package/devtools/transformers/src/transformComponentForHrm.js +74 -0
- package/devtools/transformers/src/transformJsFile.js +9 -0
- package/devtools/transformers/src/utils.js +79 -0
- package/devtools/widget/Widget.js +48 -0
- package/devtools/widget/widget.css +81 -0
- package/devtools/widget.js +23 -0
- package/dist/native-document.components.min.js +2441 -1191
- package/dist/native-document.dev.js +2710 -1359
- package/dist/native-document.dev.js.map +1 -1
- package/dist/native-document.devtools.min.js +1 -1
- package/dist/native-document.min.js +1 -1
- package/docs/cache.md +1 -1
- package/docs/core-concepts.md +1 -1
- package/docs/native-document-element.md +51 -15
- package/docs/observables.md +310 -306
- package/docs/state-management.md +198 -193
- package/index.def.js +762 -26
- package/package.json +1 -1
- package/readme.md +1 -1
- package/src/core/data/ObservableChecker.js +2 -0
- package/src/core/data/ObservableItem.js +97 -0
- package/src/core/data/ObservableObject.js +182 -0
- package/src/core/data/Store.js +364 -34
- package/src/core/data/observable-helpers/object.js +2 -166
- package/src/core/elements/anchor.js +28 -20
- package/src/core/elements/control/for-each.js +1 -1
- package/src/core/utils/formatters.js +91 -0
- package/src/core/utils/localstorage.js +57 -0
- package/src/core/utils/validator.js +0 -2
- package/src/core/wrappers/DocumentObserver.js +102 -31
- package/src/core/wrappers/ElementCreator.js +5 -0
- package/src/core/wrappers/NDElement.js +32 -1
- package/src/core/wrappers/prototypes/nd-element.transition.extensions.js +83 -0
- package/src/devtools.js +9 -0
- package/src/fetch/NativeFetch.js +5 -2
- package/types/elements.d.ts +580 -2
- package/types/nd-element.d.ts +6 -0
- package/types/observable.d.ts +71 -15
- package/types/plugins-manager.d.ts +1 -1
- package/types/store.d.ts +33 -6
- package/hrm.js +0 -7
- package/src/devtools/app/App.js +0 -66
- package/src/devtools/app/app.css +0 -0
- package/src/devtools/hrm/transformComponent.js +0 -129
- package/src/devtools/index.js +0 -18
- package/src/devtools/widget/DevToolsWidget.js +0 -26
- /package/{src/devtools/hrm → devtools/transformers/templates}/hrm.hook.template.js +0 -0
- /package/{src/devtools/hrm → devtools/transformers/templates}/hrm.orbservable.hook.template.js +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
var NativeDocument = (function (exports) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
let DebugManager = {};
|
|
4
|
+
let DebugManager$1 = {};
|
|
5
5
|
|
|
6
6
|
{
|
|
7
|
-
DebugManager = {
|
|
7
|
+
DebugManager$1 = {
|
|
8
8
|
enabled: false,
|
|
9
9
|
|
|
10
10
|
enable() {
|
|
@@ -35,60 +35,7 @@ var NativeDocument = (function (exports) {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
}
|
|
38
|
-
var DebugManager
|
|
39
|
-
|
|
40
|
-
const MemoryManager = (function() {
|
|
41
|
-
|
|
42
|
-
let $nextObserverId = 0;
|
|
43
|
-
const $observables = new Map();
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
/**
|
|
47
|
-
* Register an observable and return an id.
|
|
48
|
-
*
|
|
49
|
-
* @param {ObservableItem} observable
|
|
50
|
-
* @param {Function} getListeners
|
|
51
|
-
* @returns {number}
|
|
52
|
-
*/
|
|
53
|
-
register(observable) {
|
|
54
|
-
const id = ++$nextObserverId;
|
|
55
|
-
$observables.set(id, new WeakRef(observable));
|
|
56
|
-
return id;
|
|
57
|
-
},
|
|
58
|
-
unregister(id) {
|
|
59
|
-
$observables.delete(id);
|
|
60
|
-
},
|
|
61
|
-
getObservableById(id) {
|
|
62
|
-
return $observables.get(id)?.deref();
|
|
63
|
-
},
|
|
64
|
-
cleanup() {
|
|
65
|
-
for (const [_, weakObservableRef] of $observables) {
|
|
66
|
-
const observable = weakObservableRef.deref();
|
|
67
|
-
if (observable) {
|
|
68
|
-
observable.cleanup();
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
$observables.clear();
|
|
72
|
-
},
|
|
73
|
-
/**
|
|
74
|
-
* Clean observables that are not referenced anymore.
|
|
75
|
-
* @param {number} threshold
|
|
76
|
-
*/
|
|
77
|
-
cleanObservables(threshold) {
|
|
78
|
-
if($observables.size < threshold) return;
|
|
79
|
-
let cleanedCount = 0;
|
|
80
|
-
for (const [id, weakObservableRef] of $observables) {
|
|
81
|
-
if (!weakObservableRef.deref()) {
|
|
82
|
-
$observables.delete(id);
|
|
83
|
-
cleanedCount++;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (cleanedCount > 0) {
|
|
87
|
-
DebugManager$1.log('Memory Auto Clean', `🧹 Cleaned ${cleanedCount} orphaned observables`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
}());
|
|
38
|
+
var DebugManager = DebugManager$1;
|
|
92
39
|
|
|
93
40
|
class NativeDocumentError extends Error {
|
|
94
41
|
constructor(message, context = {}) {
|
|
@@ -191,10 +138,185 @@ var NativeDocument = (function (exports) {
|
|
|
191
138
|
return this.observable.cleanup();
|
|
192
139
|
};
|
|
193
140
|
|
|
194
|
-
|
|
141
|
+
const DocumentObserver = {
|
|
142
|
+
mounted: new WeakMap(),
|
|
143
|
+
beforeUnmount: new WeakMap(),
|
|
144
|
+
mountedSupposedSize: 0,
|
|
145
|
+
unmounted: new WeakMap(),
|
|
146
|
+
unmountedSupposedSize: 0,
|
|
147
|
+
observer: null,
|
|
148
|
+
|
|
149
|
+
executeMountedCallback(node) {
|
|
150
|
+
const data = DocumentObserver.mounted.get(node);
|
|
151
|
+
if(!data) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
data.inDom = true;
|
|
155
|
+
if(!data.mounted) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if(Array.isArray(data.mounted)) {
|
|
159
|
+
for(const cb of data.mounted) {
|
|
160
|
+
cb(node);
|
|
161
|
+
}
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
data.mounted(node);
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
executeUnmountedCallback(node) {
|
|
168
|
+
const data = DocumentObserver.unmounted.get(node);
|
|
169
|
+
if(!data) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
data.inDom = false;
|
|
173
|
+
if(!data.unmounted) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
let shouldRemove = false;
|
|
178
|
+
if(Array.isArray(data.unmounted)) {
|
|
179
|
+
for(const cb of data.unmounted) {
|
|
180
|
+
if(cb(node) === true) {
|
|
181
|
+
shouldRemove = true;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
shouldRemove = data.unmounted(node) === true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if(shouldRemove) {
|
|
189
|
+
data.disconnect();
|
|
190
|
+
node.nd?.remove();
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
checkMutation: function(mutationsList) {
|
|
195
|
+
for(const mutation of mutationsList) {
|
|
196
|
+
if(DocumentObserver.mountedSupposedSize > 0) {
|
|
197
|
+
for(const node of mutation.addedNodes) {
|
|
198
|
+
DocumentObserver.executeMountedCallback(node);
|
|
199
|
+
if(!node.querySelectorAll) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
const children = node.querySelectorAll('[data--nd-mounted]');
|
|
203
|
+
for(const child of children) {
|
|
204
|
+
DocumentObserver.executeMountedCallback(child);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (DocumentObserver.unmountedSupposedSize > 0) {
|
|
210
|
+
for (const node of mutation.removedNodes) {
|
|
211
|
+
DocumentObserver.executeUnmountedCallback(node);
|
|
212
|
+
if(!node.querySelectorAll) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
const children = node.querySelectorAll('[data--nd-unmounted]');
|
|
216
|
+
for(const child of children) {
|
|
217
|
+
DocumentObserver.executeUnmountedCallback(child);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* @param {HTMLElement} element
|
|
226
|
+
* @param {boolean} inDom
|
|
227
|
+
* @returns {{ disconnect: Function, mounted: Function, unmounted: Function, off: Function }}
|
|
228
|
+
*/
|
|
229
|
+
watch: function(element, inDom = false) {
|
|
230
|
+
let mountedRegistered = false;
|
|
231
|
+
let unmountedRegistered = false;
|
|
232
|
+
|
|
233
|
+
let data = {
|
|
234
|
+
inDom,
|
|
235
|
+
mounted: null,
|
|
236
|
+
unmounted: null,
|
|
237
|
+
disconnect: () => {
|
|
238
|
+
if (mountedRegistered) {
|
|
239
|
+
DocumentObserver.mounted.delete(element);
|
|
240
|
+
DocumentObserver.mountedSupposedSize--;
|
|
241
|
+
}
|
|
242
|
+
if (unmountedRegistered) {
|
|
243
|
+
DocumentObserver.unmounted.delete(element);
|
|
244
|
+
DocumentObserver.unmountedSupposedSize--;
|
|
245
|
+
}
|
|
246
|
+
data = null;
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const addListener = (type, callback) => {
|
|
251
|
+
if (!data[type]) {
|
|
252
|
+
data[type] = callback;
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
if (!Array.isArray(data[type])) {
|
|
256
|
+
data[type] = [data[type], callback];
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
data[type].push(callback);
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const removeListener = (type, callback) => {
|
|
263
|
+
if(!data?.[type]) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if(Array.isArray(data[type])) {
|
|
267
|
+
const index = data[type].indexOf(callback);
|
|
268
|
+
if(index > -1) {
|
|
269
|
+
data[type].splice(index, 1);
|
|
270
|
+
}
|
|
271
|
+
if(data[type].length === 1) {
|
|
272
|
+
data[type] = data[type][0];
|
|
273
|
+
}
|
|
274
|
+
if(data[type].length === 0) {
|
|
275
|
+
data[type] = null;
|
|
276
|
+
}
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
data[type] = null;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
disconnect: () => data?.disconnect(),
|
|
284
|
+
|
|
285
|
+
mounted: (callback) => {
|
|
286
|
+
addListener('mounted', callback);
|
|
287
|
+
DocumentObserver.mounted.set(element, data);
|
|
288
|
+
if (!mountedRegistered) {
|
|
289
|
+
DocumentObserver.mountedSupposedSize++;
|
|
290
|
+
mountedRegistered = true;
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
unmounted: (callback) => {
|
|
295
|
+
addListener('unmounted', callback);
|
|
296
|
+
DocumentObserver.unmounted.set(element, data);
|
|
297
|
+
if (!unmountedRegistered) {
|
|
298
|
+
DocumentObserver.unmountedSupposedSize++;
|
|
299
|
+
unmountedRegistered = true;
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
off: (type, callback) => {
|
|
304
|
+
removeListener(type, callback);
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
DocumentObserver.observer = new MutationObserver(DocumentObserver.checkMutation);
|
|
311
|
+
DocumentObserver.observer.observe(document.body, {
|
|
312
|
+
childList: true,
|
|
313
|
+
subtree: true,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
let PluginsManager$1 = null;
|
|
195
317
|
|
|
196
318
|
{
|
|
197
|
-
PluginsManager = (function() {
|
|
319
|
+
PluginsManager$1 = (function() {
|
|
198
320
|
|
|
199
321
|
const $plugins = new Map();
|
|
200
322
|
const $pluginByEvents = new Map();
|
|
@@ -260,7 +382,7 @@ var NativeDocument = (function (exports) {
|
|
|
260
382
|
try{
|
|
261
383
|
callback.call(plugin, ...data);
|
|
262
384
|
} catch (error) {
|
|
263
|
-
DebugManager
|
|
385
|
+
DebugManager.error('Plugin Manager', `Error in plugin ${plugin.$name} for event ${eventName}`, error);
|
|
264
386
|
}
|
|
265
387
|
}
|
|
266
388
|
}
|
|
@@ -269,1271 +391,1900 @@ var NativeDocument = (function (exports) {
|
|
|
269
391
|
}());
|
|
270
392
|
}
|
|
271
393
|
|
|
272
|
-
var PluginsManager
|
|
394
|
+
var PluginsManager = PluginsManager$1;
|
|
273
395
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
const ObservableWhen = function(observer, value) {
|
|
282
|
-
this.$target = value;
|
|
283
|
-
this.$observer = observer;
|
|
284
|
-
};
|
|
396
|
+
function NDElement(element) {
|
|
397
|
+
this.$element = element;
|
|
398
|
+
this.$observer = null;
|
|
399
|
+
{
|
|
400
|
+
PluginsManager.emit('NDElementCreated', element, this);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
285
403
|
|
|
286
|
-
|
|
404
|
+
NDElement.prototype.__$isNDElement = true;
|
|
287
405
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
*
|
|
291
|
-
* @param {Function} callback - Function called with boolean indicating if values match
|
|
292
|
-
* @returns {Function} Unsubscribe function
|
|
293
|
-
* @example
|
|
294
|
-
* const status = Observable('idle');
|
|
295
|
-
* const isLoading = status.when('loading');
|
|
296
|
-
* isLoading.subscribe(active => console.log('Loading:', active));
|
|
297
|
-
*/
|
|
298
|
-
ObservableWhen.prototype.subscribe = function(callback) {
|
|
299
|
-
return this.$observer.on(this.$target, callback);
|
|
406
|
+
NDElement.prototype.valueOf = function() {
|
|
407
|
+
return this.$element;
|
|
300
408
|
};
|
|
301
409
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
* @returns {boolean} True if observable value matches target value
|
|
306
|
-
*/
|
|
307
|
-
ObservableWhen.prototype.val = function() {
|
|
308
|
-
return this.$observer.$currentValue === this.$target;
|
|
410
|
+
NDElement.prototype.ref = function(target, name) {
|
|
411
|
+
target[name] = this.$element;
|
|
412
|
+
return this;
|
|
309
413
|
};
|
|
310
414
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
* @returns {boolean} True if observable value matches target value
|
|
316
|
-
*/
|
|
317
|
-
ObservableWhen.prototype.isMatch = ObservableWhen.prototype.val;
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Returns true if the observable's current value equals the target value.
|
|
321
|
-
* Alias for val().
|
|
322
|
-
*
|
|
323
|
-
* @returns {boolean} True if observable value matches target value
|
|
324
|
-
*/
|
|
325
|
-
ObservableWhen.prototype.isActive = ObservableWhen.prototype.val;
|
|
326
|
-
|
|
327
|
-
const nextTick = function(fn) {
|
|
328
|
-
let pending = false;
|
|
329
|
-
return function(...args) {
|
|
330
|
-
if (pending) return;
|
|
331
|
-
pending = true;
|
|
415
|
+
NDElement.prototype.refSelf = function(target, name) {
|
|
416
|
+
target[name] = this;
|
|
417
|
+
return this;
|
|
418
|
+
};
|
|
332
419
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
420
|
+
NDElement.prototype.unmountChildren = function() {
|
|
421
|
+
let element = this.$element;
|
|
422
|
+
for(let i = 0, length = element.children.length; i < length; i++) {
|
|
423
|
+
let elementChildren = element.children[i];
|
|
424
|
+
if(!elementChildren.$ndProx) {
|
|
425
|
+
elementChildren.nd?.remove();
|
|
426
|
+
}
|
|
427
|
+
elementChildren = null;
|
|
428
|
+
}
|
|
429
|
+
element = null;
|
|
430
|
+
return this;
|
|
338
431
|
};
|
|
339
432
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const result = val?.[key];
|
|
351
|
-
return Validator.isObservable(result) ? result.val() : (result ?? defaultKey);
|
|
352
|
-
}
|
|
433
|
+
NDElement.prototype.remove = function() {
|
|
434
|
+
let element = this.$element;
|
|
435
|
+
element.nd.unmountChildren();
|
|
436
|
+
element.$ndProx = null;
|
|
437
|
+
delete element.nd?.on?.prevent;
|
|
438
|
+
delete element.nd?.on;
|
|
439
|
+
delete element.nd;
|
|
440
|
+
element = null;
|
|
441
|
+
return this;
|
|
442
|
+
};
|
|
353
443
|
|
|
354
|
-
|
|
355
|
-
|
|
444
|
+
NDElement.prototype.lifecycle = function(states) {
|
|
445
|
+
this.$observer = this.$observer || DocumentObserver.watch(this.$element);
|
|
446
|
+
|
|
447
|
+
if(states.mounted) {
|
|
448
|
+
this.$element.setAttribute('data--nd-mounted', '1');
|
|
449
|
+
this.$observer.mounted(states.mounted);
|
|
450
|
+
}
|
|
451
|
+
if(states.unmounted) {
|
|
452
|
+
this.$element.setAttribute('data--nd-unmounted', '1');
|
|
453
|
+
this.$observer.unmounted(states.unmounted);
|
|
356
454
|
}
|
|
455
|
+
return this;
|
|
456
|
+
};
|
|
357
457
|
|
|
358
|
-
|
|
359
|
-
return
|
|
458
|
+
NDElement.prototype.mounted = function(callback) {
|
|
459
|
+
return this.lifecycle({ mounted: callback });
|
|
360
460
|
};
|
|
361
461
|
|
|
362
|
-
|
|
363
|
-
return
|
|
462
|
+
NDElement.prototype.unmounted = function(callback) {
|
|
463
|
+
return this.lifecycle({ unmounted: callback });
|
|
364
464
|
};
|
|
365
465
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
if (value === null || typeof value !== 'object') {
|
|
369
|
-
return value;
|
|
370
|
-
}
|
|
466
|
+
NDElement.prototype.beforeUnmount = function(id, callback) {
|
|
467
|
+
const el = this.$element;
|
|
371
468
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}
|
|
469
|
+
if(!DocumentObserver.beforeUnmount.has(el)) {
|
|
470
|
+
DocumentObserver.beforeUnmount.set(el, new Map());
|
|
471
|
+
const originalRemove = el.remove.bind(el);
|
|
376
472
|
|
|
377
|
-
|
|
378
|
-
if (Array.isArray(value)) {
|
|
379
|
-
return value.map(item => deepClone(item));
|
|
380
|
-
}
|
|
473
|
+
let $isUnmounting = false;
|
|
381
474
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
475
|
+
el.remove = async () => {
|
|
476
|
+
if($isUnmounting) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
$isUnmounting = true;
|
|
480
|
+
|
|
481
|
+
try {
|
|
482
|
+
const callbacks = DocumentObserver.beforeUnmount.get(el);
|
|
483
|
+
for (const cb of callbacks.values()) {
|
|
484
|
+
await cb.call(this, el);
|
|
485
|
+
}
|
|
486
|
+
} finally {
|
|
487
|
+
originalRemove();
|
|
488
|
+
$isUnmounting = false;
|
|
489
|
+
}
|
|
490
|
+
};
|
|
386
491
|
}
|
|
387
492
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
493
|
+
DocumentObserver.beforeUnmount.get(el).set(id, callback);
|
|
494
|
+
return this;
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
NDElement.prototype.htmlElement = function() {
|
|
498
|
+
return this.$element;
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
NDElement.prototype.node = NDElement.prototype.htmlElement;
|
|
502
|
+
|
|
503
|
+
NDElement.prototype.shadow = function(mode, style = null) {
|
|
504
|
+
const $element = this.$element;
|
|
505
|
+
const children = Array.from($element.childNodes);
|
|
506
|
+
const shadowRoot = $element.attachShadow({ mode });
|
|
507
|
+
if(style) {
|
|
508
|
+
const styleNode = document.createElement("style");
|
|
509
|
+
styleNode.textContent = style;
|
|
510
|
+
shadowRoot.appendChild(styleNode);
|
|
394
511
|
}
|
|
395
|
-
|
|
512
|
+
$element.append = shadowRoot.append.bind(shadowRoot);
|
|
513
|
+
$element.appendChild = shadowRoot.appendChild.bind(shadowRoot);
|
|
514
|
+
shadowRoot.append(...children);
|
|
515
|
+
|
|
516
|
+
return this;
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
NDElement.prototype.openShadow = function(style = null) {
|
|
520
|
+
return this.shadow('open', style);
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
NDElement.prototype.closedShadow = function(style = null) {
|
|
524
|
+
return this.shadow('closed', style);
|
|
396
525
|
};
|
|
397
526
|
|
|
398
527
|
/**
|
|
528
|
+
* Attaches a template binding to the element by hydrating it with the specified method.
|
|
399
529
|
*
|
|
400
|
-
* @param {
|
|
401
|
-
* @param {
|
|
402
|
-
* @
|
|
530
|
+
* @param {string} methodName - Name of the hydration method to call
|
|
531
|
+
* @param {BindingHydrator} bindingHydrator - Template binding with $hydrate method
|
|
532
|
+
* @returns {HTMLElement} The underlying HTML element
|
|
533
|
+
* @example
|
|
534
|
+
* const onClick = $binder.attach((event, data) => console.log(data));
|
|
535
|
+
* element.nd.attach('onClick', onClick);
|
|
403
536
|
*/
|
|
404
|
-
function
|
|
405
|
-
|
|
537
|
+
NDElement.prototype.attach = function(methodName, bindingHydrator) {
|
|
538
|
+
bindingHydrator.$hydrate(this.$element, methodName);
|
|
539
|
+
return this.$element;
|
|
540
|
+
};
|
|
406
541
|
|
|
407
|
-
|
|
408
|
-
|
|
542
|
+
/**
|
|
543
|
+
* Extends the current NDElement instance with custom methods.
|
|
544
|
+
* Methods are bound to the instance and available for chaining.
|
|
545
|
+
*
|
|
546
|
+
* @param {Object} methods - Object containing method definitions
|
|
547
|
+
* @returns {this} The NDElement instance with added methods for chaining
|
|
548
|
+
* @example
|
|
549
|
+
* element.nd.with({
|
|
550
|
+
* highlight() {
|
|
551
|
+
* this.$element.style.background = 'yellow';
|
|
552
|
+
* return this;
|
|
553
|
+
* }
|
|
554
|
+
* }).highlight().onClick(() => console.log('Clicked'));
|
|
555
|
+
*/
|
|
556
|
+
NDElement.prototype.with = function(methods) {
|
|
557
|
+
if (!methods || typeof methods !== 'object') {
|
|
558
|
+
throw new NativeDocumentError('extend() requires an object of methods');
|
|
559
|
+
}
|
|
409
560
|
{
|
|
410
|
-
this.$
|
|
561
|
+
if (!this.$localExtensions) {
|
|
562
|
+
this.$localExtensions = new Map();
|
|
563
|
+
}
|
|
411
564
|
}
|
|
412
565
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
this.$watchers = null;
|
|
416
|
-
|
|
417
|
-
this.$memoryId = null;
|
|
566
|
+
for (const name in methods) {
|
|
567
|
+
const method = methods[name];
|
|
418
568
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
569
|
+
if (typeof method !== 'function') {
|
|
570
|
+
console.warn(`⚠️ extends(): "${name}" is not a function, skipping`);
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
{
|
|
574
|
+
if (this[name] && !this.$localExtensions.has(name)) {
|
|
575
|
+
DebugManager.warn('NDElement.extend', `Method "${name}" already exists and will be overwritten`);
|
|
576
|
+
}
|
|
577
|
+
this.$localExtensions.set(name, method);
|
|
423
578
|
}
|
|
424
|
-
}
|
|
425
|
-
{
|
|
426
|
-
PluginsManager$1.emit('CreateObservable', this);
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
579
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
return this.$currentValue;
|
|
433
|
-
},
|
|
434
|
-
set(value) {
|
|
435
|
-
this.set(value);
|
|
436
|
-
},
|
|
437
|
-
configurable: true,
|
|
438
|
-
});
|
|
580
|
+
this[name] = method.bind(this);
|
|
581
|
+
}
|
|
439
582
|
|
|
440
|
-
|
|
441
|
-
|
|
583
|
+
return this;
|
|
584
|
+
};
|
|
442
585
|
|
|
443
586
|
/**
|
|
444
|
-
*
|
|
445
|
-
*
|
|
587
|
+
* Extends the NDElement prototype with new methods available to all NDElement instances.
|
|
588
|
+
* Use this to add global methods to all NDElements.
|
|
446
589
|
*
|
|
447
|
-
* @param {
|
|
448
|
-
* @returns {
|
|
590
|
+
* @param {Object} methods - Object containing method definitions to add to prototype
|
|
591
|
+
* @returns {typeof NDElement} The NDElement constructor
|
|
592
|
+
* @throws {NativeDocumentError} If methods is not an object or contains non-function values
|
|
449
593
|
* @example
|
|
450
|
-
*
|
|
451
|
-
*
|
|
594
|
+
* NDElement.extend({
|
|
595
|
+
* fadeIn() {
|
|
596
|
+
* this.$element.style.opacity = '1';
|
|
597
|
+
* return this;
|
|
598
|
+
* }
|
|
599
|
+
* });
|
|
600
|
+
* // Now all NDElements have .fadeIn() method
|
|
601
|
+
* Div().nd.fadeIn();
|
|
452
602
|
*/
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
};
|
|
603
|
+
NDElement.extend = function(methods) {
|
|
604
|
+
if (!methods || typeof methods !== 'object') {
|
|
605
|
+
throw new NativeDocumentError('NDElement.extend() requires an object of methods');
|
|
606
|
+
}
|
|
458
607
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
608
|
+
if (Array.isArray(methods)) {
|
|
609
|
+
throw new NativeDocumentError('NDElement.extend() requires an object, not an array');
|
|
610
|
+
}
|
|
462
611
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
612
|
+
const protectedMethods = new Set([
|
|
613
|
+
'constructor', 'valueOf', '$element', '$observer',
|
|
614
|
+
'ref', 'remove', 'cleanup', 'with', 'extend', 'attach',
|
|
615
|
+
'lifecycle', 'mounted', 'unmounted', 'unmountChildren'
|
|
616
|
+
]);
|
|
467
617
|
|
|
468
|
-
for(
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
618
|
+
for (const name in methods) {
|
|
619
|
+
if (!Object.hasOwn(methods, name)) {
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
472
622
|
|
|
473
|
-
|
|
474
|
-
const $watchers = this.$watchers;
|
|
475
|
-
const $previousValue = this.$previousValue;
|
|
476
|
-
const $currentValue = this.$currentValue;
|
|
623
|
+
const method = methods[name];
|
|
477
624
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
625
|
+
if (typeof method !== 'function') {
|
|
626
|
+
DebugManager.warn('NDElement.extend', `"${name}" is not a function, skipping`);
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if (protectedMethods.has(name)) {
|
|
631
|
+
DebugManager.error('NDElement.extend', `Cannot override protected method "${name}"`);
|
|
632
|
+
throw new NativeDocumentError(`Cannot override protected method "${name}"`);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
if (NDElement.prototype[name]) {
|
|
636
|
+
DebugManager.warn('NDElement.extend', `Overwriting existing prototype method "${name}"`);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
NDElement.prototype[name] = method;
|
|
482
640
|
}
|
|
483
|
-
|
|
484
|
-
|
|
641
|
+
{
|
|
642
|
+
PluginsManager.emit('NDElementExtended', methods);
|
|
485
643
|
}
|
|
486
|
-
};
|
|
487
644
|
|
|
488
|
-
|
|
489
|
-
this.triggerWatchers(operations);
|
|
490
|
-
this.triggerListeners(operations);
|
|
645
|
+
return NDElement;
|
|
491
646
|
};
|
|
492
647
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
648
|
+
const COMMON_NODE_TYPES = {
|
|
649
|
+
ELEMENT: 1,
|
|
650
|
+
TEXT: 3,
|
|
651
|
+
COMMENT: 8,
|
|
652
|
+
DOCUMENT_FRAGMENT: 11
|
|
496
653
|
};
|
|
497
654
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
655
|
+
const Validator = {
|
|
656
|
+
isObservable(value) {
|
|
657
|
+
return value?.__$isObservable;
|
|
658
|
+
},
|
|
659
|
+
isTemplateBinding(value) {
|
|
660
|
+
return value?.__$isTemplateBinding;
|
|
661
|
+
},
|
|
662
|
+
isObservableWhenResult(value) {
|
|
663
|
+
return value && (value.__$isObservableWhen || (typeof value === 'object' && '$target' in value && '$observer' in value));
|
|
664
|
+
},
|
|
665
|
+
isArrayObservable(value) {
|
|
666
|
+
return value?.__$isObservableArray;
|
|
667
|
+
},
|
|
668
|
+
isProxy(value) {
|
|
669
|
+
return value?.__isProxy__
|
|
670
|
+
},
|
|
671
|
+
isObservableOrProxy(value) {
|
|
672
|
+
return Validator.isObservable(value) || Validator.isProxy(value);
|
|
673
|
+
},
|
|
674
|
+
isAnchor(value) {
|
|
675
|
+
return value?.__Anchor__
|
|
676
|
+
},
|
|
677
|
+
isObservableChecker(value) {
|
|
678
|
+
return value?.__$isObservableChecker || value instanceof ObservableChecker;
|
|
679
|
+
},
|
|
680
|
+
isArray(value) {
|
|
681
|
+
return Array.isArray(value);
|
|
682
|
+
},
|
|
683
|
+
isString(value) {
|
|
684
|
+
return typeof value === 'string';
|
|
685
|
+
},
|
|
686
|
+
isNumber(value) {
|
|
687
|
+
return typeof value === 'number';
|
|
688
|
+
},
|
|
689
|
+
isBoolean(value) {
|
|
690
|
+
return typeof value === 'boolean';
|
|
691
|
+
},
|
|
692
|
+
isFunction(value) {
|
|
693
|
+
return typeof value === 'function';
|
|
694
|
+
},
|
|
695
|
+
isAsyncFunction(value) {
|
|
696
|
+
return typeof value === 'function' && value.constructor.name === 'AsyncFunction';
|
|
697
|
+
},
|
|
698
|
+
isObject(value) {
|
|
699
|
+
return typeof value === 'object' && value !== null;
|
|
700
|
+
},
|
|
701
|
+
isJson(value) {
|
|
702
|
+
return !(typeof value !== 'object' || value === null || Array.isArray(value) || value.constructor.name !== 'Object')
|
|
703
|
+
},
|
|
704
|
+
isElement(value) {
|
|
705
|
+
return value && (
|
|
706
|
+
value.nodeType === COMMON_NODE_TYPES.ELEMENT ||
|
|
707
|
+
value.nodeType === COMMON_NODE_TYPES.TEXT ||
|
|
708
|
+
value.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT ||
|
|
709
|
+
value.nodeType === COMMON_NODE_TYPES.COMMENT
|
|
710
|
+
);
|
|
711
|
+
},
|
|
712
|
+
isFragment(value) {
|
|
713
|
+
return value?.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT;
|
|
714
|
+
},
|
|
715
|
+
isStringOrObservable(value) {
|
|
716
|
+
return this.isString(value) || this.isObservable(value);
|
|
717
|
+
},
|
|
718
|
+
isValidChild(child) {
|
|
719
|
+
return child === null ||
|
|
720
|
+
this.isElement(child) ||
|
|
721
|
+
this.isObservable(child) ||
|
|
722
|
+
this.isNDElement(child) ||
|
|
723
|
+
['string', 'number', 'boolean'].includes(typeof child);
|
|
724
|
+
},
|
|
725
|
+
isNDElement(child) {
|
|
726
|
+
return child?.__$isNDElement || child instanceof NDElement;
|
|
727
|
+
},
|
|
728
|
+
isValidChildren(children) {
|
|
729
|
+
if (!Array.isArray(children)) {
|
|
730
|
+
children = [children];
|
|
508
731
|
}
|
|
509
|
-
|
|
510
|
-
|
|
732
|
+
|
|
733
|
+
const invalid = children.filter(child => !this.isValidChild(child));
|
|
734
|
+
return invalid.length === 0;
|
|
735
|
+
},
|
|
736
|
+
validateChildren(children) {
|
|
737
|
+
if (!Array.isArray(children)) {
|
|
738
|
+
children = [children];
|
|
511
739
|
}
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
if(this.$watchers?.size) {
|
|
515
|
-
this.trigger = this.triggerWatchers;
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
this.trigger = noneTrigger;
|
|
519
|
-
};
|
|
520
|
-
ObservableItem.prototype.trigger = noneTrigger;
|
|
521
740
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
{
|
|
535
|
-
|
|
741
|
+
const invalid = children.filter(child => !this.isValidChild(child));
|
|
742
|
+
if (invalid.length > 0) {
|
|
743
|
+
throw new NativeDocumentError(`Invalid children detected: ${invalid.map(i => typeof i).join(', ')}`);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
return children;
|
|
747
|
+
},
|
|
748
|
+
/**
|
|
749
|
+
* Check if the data contains observables.
|
|
750
|
+
* @param {Array|Object} data
|
|
751
|
+
* @returns {boolean}
|
|
752
|
+
*/
|
|
753
|
+
containsObservables(data) {
|
|
754
|
+
if(!data) {
|
|
755
|
+
return false;
|
|
756
|
+
}
|
|
757
|
+
return Validator.isObject(data)
|
|
758
|
+
&& Object.values(data).some(value => Validator.isObservable(value));
|
|
759
|
+
},
|
|
760
|
+
/**
|
|
761
|
+
* Check if the data contains an observable reference.
|
|
762
|
+
* @param {string} data
|
|
763
|
+
* @returns {boolean}
|
|
764
|
+
*/
|
|
765
|
+
containsObservableReference(data) {
|
|
766
|
+
if(!data || typeof data !== 'string') {
|
|
767
|
+
return false;
|
|
768
|
+
}
|
|
769
|
+
return /\{\{#ObItem::\([0-9]+\)\}\}/.test(data);
|
|
770
|
+
},
|
|
771
|
+
validateAttributes(attributes) {},
|
|
772
|
+
|
|
773
|
+
validateEventCallback(callback) {
|
|
774
|
+
if (typeof callback !== 'function') {
|
|
775
|
+
throw new NativeDocumentError('Event callback must be a function');
|
|
776
|
+
}
|
|
536
777
|
}
|
|
537
778
|
};
|
|
779
|
+
{
|
|
780
|
+
Validator.validateAttributes = function(attributes) {
|
|
781
|
+
if (!attributes || typeof attributes !== 'object') {
|
|
782
|
+
return attributes;
|
|
783
|
+
}
|
|
538
784
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
*/
|
|
542
|
-
ObservableItem.prototype.$setWithInterceptor = function(data) {
|
|
543
|
-
let newValue = (typeof data === 'function') ? data(this.$currentValue) : data;
|
|
544
|
-
const result = this.$interceptor(newValue, this.$currentValue);
|
|
785
|
+
const reserved = [];
|
|
786
|
+
const foundReserved = Object.keys(attributes).filter(key => reserved.includes(key));
|
|
545
787
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
788
|
+
if (foundReserved.length > 0) {
|
|
789
|
+
DebugManager.warn('Validator', `Reserved attributes found: ${foundReserved.join(', ')}`);
|
|
790
|
+
}
|
|
549
791
|
|
|
550
|
-
|
|
551
|
-
|
|
792
|
+
return attributes;
|
|
793
|
+
};
|
|
794
|
+
}
|
|
552
795
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
ObservableItem.prototype.$basicSet = function(data) {
|
|
557
|
-
let newValue = (typeof data === 'function') ? data(this.$currentValue) : data;
|
|
558
|
-
this.$updateWithNewValue(newValue);
|
|
559
|
-
};
|
|
796
|
+
function Anchor(name, isUniqueChild = false) {
|
|
797
|
+
const anchorFragment = document.createDocumentFragment();
|
|
798
|
+
anchorFragment.__Anchor__ = true;
|
|
560
799
|
|
|
561
|
-
|
|
800
|
+
const anchorStart = document.createComment('Anchor Start : '+name);
|
|
801
|
+
const anchorEnd = document.createComment('/ Anchor End '+name);
|
|
562
802
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
};
|
|
803
|
+
anchorFragment.appendChild(anchorStart);
|
|
804
|
+
anchorFragment.appendChild(anchorEnd);
|
|
566
805
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
806
|
+
anchorFragment.nativeInsertBefore = anchorFragment.insertBefore;
|
|
807
|
+
anchorFragment.nativeAppendChild = anchorFragment.appendChild;
|
|
808
|
+
anchorFragment.nativeAppend = anchorFragment.append;
|
|
809
|
+
|
|
810
|
+
const isParentUniqueChild = (parent) => (isUniqueChild || (parent.firstChild === anchorStart && parent.lastChild === anchorEnd));
|
|
811
|
+
|
|
812
|
+
const insertBefore = function(parent, child, target) {
|
|
813
|
+
const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
|
|
814
|
+
if(parent === anchorFragment) {
|
|
815
|
+
parent.nativeInsertBefore(childElement, target);
|
|
816
|
+
return;
|
|
576
817
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
818
|
+
if(isParentUniqueChild(parent) && target === anchorEnd) {
|
|
819
|
+
parent.append(childElement, target);
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
parent.insertBefore(childElement, target);
|
|
823
|
+
};
|
|
583
824
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
*/
|
|
594
|
-
ObservableItem.prototype.onCleanup = function(callback) {
|
|
595
|
-
this.$cleanupListeners = this.$cleanupListeners ?? [];
|
|
596
|
-
this.$cleanupListeners.push(callback);
|
|
597
|
-
};
|
|
825
|
+
anchorFragment.appendElement = function(child, before = null) {
|
|
826
|
+
const parentNode = anchorStart.parentNode;
|
|
827
|
+
const targetBefore = before || anchorEnd;
|
|
828
|
+
if(parentNode === anchorFragment) {
|
|
829
|
+
parentNode.nativeInsertBefore(child, targetBefore);
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
parentNode?.insertBefore(child, targetBefore);
|
|
833
|
+
};
|
|
598
834
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
835
|
+
anchorFragment.appendChild = function(child, before = null) {
|
|
836
|
+
const parent = anchorEnd.parentNode;
|
|
837
|
+
if(!parent) {
|
|
838
|
+
DebugManager.error('Anchor', 'Anchor : parent not found', child);
|
|
839
|
+
return;
|
|
603
840
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
this.disconnectAll();
|
|
608
|
-
{
|
|
609
|
-
this.$isCleanedUp = true;
|
|
610
|
-
}
|
|
611
|
-
delete this.$value;
|
|
612
|
-
};
|
|
841
|
+
before = before ?? anchorEnd;
|
|
842
|
+
insertBefore(parent, child, before);
|
|
843
|
+
};
|
|
613
844
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
845
|
+
anchorFragment.append = function(...args ) {
|
|
846
|
+
return anchorFragment.appendChild(args);
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
anchorFragment.removeChildren = async function() {
|
|
850
|
+
const parent = anchorEnd.parentNode;
|
|
851
|
+
if(parent === anchorFragment) {
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
// if(isParentUniqueChild(parent)) {
|
|
855
|
+
// parent.replaceChildren(anchorStart, anchorEnd);
|
|
856
|
+
// return;
|
|
857
|
+
// }
|
|
858
|
+
|
|
859
|
+
let itemToRemove = anchorStart.nextSibling, tempItem;
|
|
860
|
+
const removes = [];
|
|
861
|
+
while(itemToRemove && itemToRemove !== anchorEnd) {
|
|
862
|
+
tempItem = itemToRemove.nextSibling;
|
|
863
|
+
removes.push(itemToRemove.remove());
|
|
864
|
+
itemToRemove = tempItem;
|
|
865
|
+
}
|
|
866
|
+
await Promise.all(removes);
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
anchorFragment.remove = async function() {
|
|
870
|
+
const parent = anchorEnd.parentNode;
|
|
871
|
+
if(parent === anchorFragment) {
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
let itemToRemove = anchorStart.nextSibling, tempItem;
|
|
875
|
+
const allItemToRemove = [];
|
|
876
|
+
const removes = [];
|
|
877
|
+
while(itemToRemove && itemToRemove !== anchorEnd) {
|
|
878
|
+
tempItem = itemToRemove.nextSibling;
|
|
879
|
+
allItemToRemove.push(itemToRemove);
|
|
880
|
+
removes.push(itemToRemove.remove());
|
|
881
|
+
itemToRemove = tempItem;
|
|
882
|
+
}
|
|
883
|
+
await Promise.all(removes);
|
|
884
|
+
anchorFragment.nativeAppend(...allItemToRemove);
|
|
885
|
+
};
|
|
886
|
+
|
|
887
|
+
anchorFragment.removeWithAnchors = async function() {
|
|
888
|
+
await anchorFragment.removeChildren();
|
|
889
|
+
anchorStart.remove();
|
|
890
|
+
anchorEnd.remove();
|
|
891
|
+
};
|
|
892
|
+
|
|
893
|
+
anchorFragment.replaceContent = async function(child) {
|
|
894
|
+
const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
|
|
895
|
+
const parent = anchorEnd.parentNode;
|
|
896
|
+
if(!parent) {
|
|
623
897
|
return;
|
|
624
898
|
}
|
|
625
|
-
if
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
899
|
+
// if(isParentUniqueChild(parent)) {
|
|
900
|
+
// parent.replaceChildren(anchorStart, childElement, anchorEnd);
|
|
901
|
+
// return;
|
|
902
|
+
// }
|
|
903
|
+
await anchorFragment.removeChildren();
|
|
904
|
+
parent.insertBefore(childElement, anchorEnd);
|
|
905
|
+
};
|
|
630
906
|
|
|
631
|
-
|
|
632
|
-
this.assocTrigger();
|
|
633
|
-
{
|
|
634
|
-
PluginsManager$1.emit('ObservableSubscribe', this);
|
|
635
|
-
}
|
|
636
|
-
};
|
|
907
|
+
anchorFragment.setContent = anchorFragment.replaceContent;
|
|
637
908
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
*
|
|
642
|
-
* @param {*} value - The value to watch for
|
|
643
|
-
* @param {(value) => void|ObservableItem} callback - Callback function or observable to set when value matches
|
|
644
|
-
* @example
|
|
645
|
-
* const status = Observable('idle');
|
|
646
|
-
* status.on('loading', () => console.log('Started loading'));
|
|
647
|
-
* status.on('error', isError); // Set another observable
|
|
648
|
-
*/
|
|
649
|
-
ObservableItem.prototype.on = function(value, callback) {
|
|
650
|
-
this.$watchers = this.$watchers ?? new Map();
|
|
909
|
+
anchorFragment.insertBefore = function(child, anchor = null) {
|
|
910
|
+
anchorFragment.appendChild(child, anchor);
|
|
911
|
+
};
|
|
651
912
|
|
|
652
|
-
let watchValueList = this.$watchers.get(value);
|
|
653
913
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
}
|
|
914
|
+
anchorFragment.endElement = function() {
|
|
915
|
+
return anchorEnd;
|
|
916
|
+
};
|
|
657
917
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
callback.list = watchValueList;
|
|
669
|
-
this.$watchers.set(value, callback);
|
|
670
|
-
} else {
|
|
671
|
-
watchValueList.list.push(callback);
|
|
672
|
-
}
|
|
918
|
+
anchorFragment.startElement = function() {
|
|
919
|
+
return anchorStart;
|
|
920
|
+
};
|
|
921
|
+
anchorFragment.restore = function() {
|
|
922
|
+
anchorFragment.appendChild(anchorFragment);
|
|
923
|
+
};
|
|
924
|
+
anchorFragment.clear = anchorFragment.remove;
|
|
925
|
+
anchorFragment.detach = anchorFragment.remove;
|
|
673
926
|
|
|
674
|
-
|
|
675
|
-
|
|
927
|
+
anchorFragment.getByIndex = function(index) {
|
|
928
|
+
let currentNode = anchorStart;
|
|
929
|
+
for(let i = 0; i <= index; i++) {
|
|
930
|
+
if(!currentNode.nextSibling) {
|
|
931
|
+
return null;
|
|
932
|
+
}
|
|
933
|
+
currentNode = currentNode.nextSibling;
|
|
934
|
+
}
|
|
935
|
+
return currentNode !== anchorStart ? currentNode : null;
|
|
936
|
+
};
|
|
676
937
|
|
|
938
|
+
return anchorFragment;
|
|
939
|
+
}
|
|
677
940
|
/**
|
|
678
|
-
* Removes a watcher for a specific value. If no callback is provided, removes all watchers for that value.
|
|
679
941
|
*
|
|
680
|
-
* @param {
|
|
681
|
-
* @param {
|
|
682
|
-
* @
|
|
683
|
-
* const status = Observable('idle');
|
|
684
|
-
* const handler = () => console.log('Loading');
|
|
685
|
-
* status.on('loading', handler);
|
|
686
|
-
* status.off('loading', handler); // Remove specific handler
|
|
687
|
-
* status.off('loading'); // Remove all handlers for 'loading'
|
|
942
|
+
* @param {HTMLElement|DocumentFragment|Text|String|Array} children
|
|
943
|
+
* @param {{ parent?: HTMLElement, name?: String}} configs
|
|
944
|
+
* @returns {DocumentFragment}
|
|
688
945
|
*/
|
|
689
|
-
|
|
690
|
-
|
|
946
|
+
function createPortal(children, { parent, name = 'unnamed' } = {}) {
|
|
947
|
+
const anchor = Anchor('Portal '+name);
|
|
948
|
+
anchor.appendChild(ElementCreator.getChild(children));
|
|
691
949
|
|
|
692
|
-
|
|
693
|
-
|
|
950
|
+
(parent || document.body).appendChild(anchor);
|
|
951
|
+
return anchor;
|
|
952
|
+
}
|
|
694
953
|
|
|
695
|
-
|
|
696
|
-
this.$watchers?.delete(value);
|
|
697
|
-
this.assocTrigger();
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
const index = watchValueList.indexOf(callback);
|
|
701
|
-
watchValueList?.splice(index, 1);
|
|
702
|
-
if(watchValueList.length === 1) {
|
|
703
|
-
this.$watchers.set(value, watchValueList[0]);
|
|
704
|
-
}
|
|
705
|
-
else if(watchValueList.length === 0) {
|
|
706
|
-
this.$watchers?.delete(value);
|
|
707
|
-
}
|
|
708
|
-
this.assocTrigger();
|
|
709
|
-
};
|
|
954
|
+
DocumentFragment.prototype.setAttribute = () => {};
|
|
710
955
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
956
|
+
const BOOLEAN_ATTRIBUTES = new Set([
|
|
957
|
+
'checked',
|
|
958
|
+
'selected',
|
|
959
|
+
'disabled',
|
|
960
|
+
'readonly',
|
|
961
|
+
'required',
|
|
962
|
+
'autofocus',
|
|
963
|
+
'multiple',
|
|
964
|
+
'autocomplete',
|
|
965
|
+
'hidden',
|
|
966
|
+
'contenteditable',
|
|
967
|
+
'spellcheck',
|
|
968
|
+
'translate',
|
|
969
|
+
'draggable',
|
|
970
|
+
'async',
|
|
971
|
+
'defer',
|
|
972
|
+
'autoplay',
|
|
973
|
+
'controls',
|
|
974
|
+
'loop',
|
|
975
|
+
'muted',
|
|
976
|
+
'download',
|
|
977
|
+
'reversed',
|
|
978
|
+
'open',
|
|
979
|
+
'default',
|
|
980
|
+
'formnovalidate',
|
|
981
|
+
'novalidate',
|
|
982
|
+
'scoped',
|
|
983
|
+
'itemscope',
|
|
984
|
+
'allowfullscreen',
|
|
985
|
+
'allowpaymentrequest',
|
|
986
|
+
'playsinline'
|
|
987
|
+
]);
|
|
723
988
|
|
|
724
|
-
|
|
725
|
-
if (fn(val)) {
|
|
726
|
-
this.unsubscribe(handler);
|
|
727
|
-
callback(val);
|
|
728
|
-
}
|
|
729
|
-
};
|
|
730
|
-
this.subscribe(handler);
|
|
731
|
-
};
|
|
989
|
+
const MemoryManager = (function() {
|
|
732
990
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
* @param {Function} callback
|
|
736
|
-
*/
|
|
737
|
-
ObservableItem.prototype.unsubscribe = function(callback) {
|
|
738
|
-
if(!this.$listeners) return;
|
|
739
|
-
const index = this.$listeners.indexOf(callback);
|
|
740
|
-
if (index > -1) {
|
|
741
|
-
this.$listeners.splice(index, 1);
|
|
742
|
-
}
|
|
743
|
-
this.assocTrigger();
|
|
744
|
-
{
|
|
745
|
-
PluginsManager$1.emit('ObservableUnsubscribe', this);
|
|
746
|
-
}
|
|
747
|
-
};
|
|
991
|
+
let $nextObserverId = 0;
|
|
992
|
+
const $observables = new Map();
|
|
748
993
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
994
|
+
return {
|
|
995
|
+
/**
|
|
996
|
+
* Register an observable and return an id.
|
|
997
|
+
*
|
|
998
|
+
* @param {ObservableItem} observable
|
|
999
|
+
* @param {Function} getListeners
|
|
1000
|
+
* @returns {number}
|
|
1001
|
+
*/
|
|
1002
|
+
register(observable) {
|
|
1003
|
+
const id = ++$nextObserverId;
|
|
1004
|
+
$observables.set(id, new WeakRef(observable));
|
|
1005
|
+
return id;
|
|
1006
|
+
},
|
|
1007
|
+
unregister(id) {
|
|
1008
|
+
$observables.delete(id);
|
|
1009
|
+
},
|
|
1010
|
+
getObservableById(id) {
|
|
1011
|
+
return $observables.get(id)?.deref();
|
|
1012
|
+
},
|
|
1013
|
+
cleanup() {
|
|
1014
|
+
for (const [_, weakObservableRef] of $observables) {
|
|
1015
|
+
const observable = weakObservableRef.deref();
|
|
1016
|
+
if (observable) {
|
|
1017
|
+
observable.cleanup();
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
$observables.clear();
|
|
1021
|
+
},
|
|
1022
|
+
/**
|
|
1023
|
+
* Clean observables that are not referenced anymore.
|
|
1024
|
+
* @param {number} threshold
|
|
1025
|
+
*/
|
|
1026
|
+
cleanObservables(threshold) {
|
|
1027
|
+
if($observables.size < threshold) return;
|
|
1028
|
+
let cleanedCount = 0;
|
|
1029
|
+
for (const [id, weakObservableRef] of $observables) {
|
|
1030
|
+
if (!weakObservableRef.deref()) {
|
|
1031
|
+
$observables.delete(id);
|
|
1032
|
+
cleanedCount++;
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
if (cleanedCount > 0) {
|
|
1036
|
+
DebugManager.log('Memory Auto Clean', `🧹 Cleaned ${cleanedCount} orphaned observables`);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
};
|
|
1040
|
+
}());
|
|
757
1041
|
|
|
758
1042
|
/**
|
|
759
|
-
*
|
|
760
|
-
* If the property is an observable, returns its value.
|
|
1043
|
+
* Creates an ObservableWhen that tracks whether an observable equals a specific value.
|
|
761
1044
|
*
|
|
762
|
-
* @param {
|
|
763
|
-
* @
|
|
764
|
-
* @
|
|
765
|
-
* const user = Observable({ name: 'John', age: Observable(25) });
|
|
766
|
-
* user.get('name'); // 'John'
|
|
767
|
-
* user.get('age'); // 25 (unwrapped from observable)
|
|
1045
|
+
* @param {ObservableItem} observer - The observable to watch
|
|
1046
|
+
* @param {*} value - The value to compare against
|
|
1047
|
+
* @class ObservableWhen
|
|
768
1048
|
*/
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1049
|
+
const ObservableWhen = function(observer, value) {
|
|
1050
|
+
this.$target = value;
|
|
1051
|
+
this.$observer = observer;
|
|
772
1052
|
};
|
|
773
1053
|
|
|
1054
|
+
ObservableWhen.prototype.__$isObservableWhen = true;
|
|
1055
|
+
|
|
774
1056
|
/**
|
|
775
|
-
*
|
|
776
|
-
* Returns an object that can be subscribed to and will emit true/false.
|
|
1057
|
+
* Subscribes to changes in the match status (true when observable equals target value).
|
|
777
1058
|
*
|
|
778
|
-
* @param {
|
|
779
|
-
* @returns {
|
|
1059
|
+
* @param {Function} callback - Function called with boolean indicating if values match
|
|
1060
|
+
* @returns {Function} Unsubscribe function
|
|
780
1061
|
* @example
|
|
781
1062
|
* const status = Observable('idle');
|
|
782
1063
|
* const isLoading = status.when('loading');
|
|
783
1064
|
* isLoading.subscribe(active => console.log('Loading:', active));
|
|
784
|
-
* status.set('loading'); // Logs: "Loading: true"
|
|
785
1065
|
*/
|
|
786
|
-
|
|
787
|
-
return
|
|
1066
|
+
ObservableWhen.prototype.subscribe = function(callback) {
|
|
1067
|
+
return this.$observer.on(this.$target, callback);
|
|
788
1068
|
};
|
|
789
1069
|
|
|
790
1070
|
/**
|
|
791
|
-
*
|
|
1071
|
+
* Returns true if the observable's current value equals the target value.
|
|
792
1072
|
*
|
|
793
|
-
* @
|
|
794
|
-
* @returns {boolean} True if values are equal
|
|
795
|
-
* @example
|
|
796
|
-
* const a = Observable(5);
|
|
797
|
-
* const b = Observable(5);
|
|
798
|
-
* a.equals(5); // true
|
|
799
|
-
* a.equals(b); // true
|
|
800
|
-
* a.equals(10); // false
|
|
1073
|
+
* @returns {boolean} True if observable value matches target value
|
|
801
1074
|
*/
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
return this.$currentValue === other.$currentValue;
|
|
805
|
-
}
|
|
806
|
-
return this.$currentValue === other;
|
|
1075
|
+
ObservableWhen.prototype.val = function() {
|
|
1076
|
+
return this.$observer.$currentValue === this.$target;
|
|
807
1077
|
};
|
|
808
1078
|
|
|
809
1079
|
/**
|
|
810
|
-
*
|
|
1080
|
+
* Returns true if the observable's current value equals the target value.
|
|
1081
|
+
* Alias for val().
|
|
811
1082
|
*
|
|
812
|
-
* @returns {boolean}
|
|
813
|
-
* @example
|
|
814
|
-
* const count = Observable(0);
|
|
815
|
-
* count.toBool(); // false
|
|
816
|
-
* count.set(5);
|
|
817
|
-
* count.toBool(); // true
|
|
1083
|
+
* @returns {boolean} True if observable value matches target value
|
|
818
1084
|
*/
|
|
819
|
-
|
|
820
|
-
return !!this.$currentValue;
|
|
821
|
-
};
|
|
1085
|
+
ObservableWhen.prototype.isMatch = ObservableWhen.prototype.val;
|
|
822
1086
|
|
|
823
1087
|
/**
|
|
824
|
-
*
|
|
1088
|
+
* Returns true if the observable's current value equals the target value.
|
|
1089
|
+
* Alias for val().
|
|
825
1090
|
*
|
|
826
|
-
* @
|
|
827
|
-
* const isOpen = Observable(false);
|
|
828
|
-
* isOpen.toggle(); // Now true
|
|
829
|
-
* isOpen.toggle(); // Now false
|
|
1091
|
+
* @returns {boolean} True if observable value matches target value
|
|
830
1092
|
*/
|
|
831
|
-
|
|
832
|
-
|
|
1093
|
+
ObservableWhen.prototype.isActive = ObservableWhen.prototype.val;
|
|
1094
|
+
|
|
1095
|
+
const nextTick = function(fn) {
|
|
1096
|
+
let pending = false;
|
|
1097
|
+
return function(...args) {
|
|
1098
|
+
if (pending) return;
|
|
1099
|
+
pending = true;
|
|
1100
|
+
|
|
1101
|
+
Promise.resolve().then(() => {
|
|
1102
|
+
fn.apply(this, args);
|
|
1103
|
+
pending = false;
|
|
1104
|
+
});
|
|
1105
|
+
};
|
|
833
1106
|
};
|
|
834
1107
|
|
|
835
1108
|
/**
|
|
836
|
-
* Resets the observable to its initial value.
|
|
837
|
-
* Only works if the observable was created with { reset: true } config.
|
|
838
1109
|
*
|
|
839
|
-
* @
|
|
840
|
-
*
|
|
841
|
-
*
|
|
842
|
-
*
|
|
1110
|
+
* @param {*} item
|
|
1111
|
+
* @param {string|null} defaultKey
|
|
1112
|
+
* @param {?Function} key
|
|
1113
|
+
* @returns {*}
|
|
843
1114
|
*/
|
|
844
|
-
|
|
845
|
-
if(
|
|
846
|
-
|
|
1115
|
+
const getKey = (item, defaultKey, key) => {
|
|
1116
|
+
if (Validator.isString(key)) {
|
|
1117
|
+
const val = Validator.isObservable(item) ? item.val() : item;
|
|
1118
|
+
const result = val?.[key];
|
|
1119
|
+
return Validator.isObservable(result) ? result.val() : (result ?? defaultKey);
|
|
847
1120
|
}
|
|
848
|
-
const resetValue = (Validator.isObject(this.$initialValue))
|
|
849
|
-
? deepClone(this.$initialValue, (observable) => {
|
|
850
|
-
observable.reset();
|
|
851
|
-
})
|
|
852
|
-
: this.$initialValue;
|
|
853
|
-
this.set(resetValue);
|
|
854
|
-
};
|
|
855
1121
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
* @returns {string} String representation of the current value
|
|
860
|
-
*/
|
|
861
|
-
ObservableItem.prototype.toString = function() {
|
|
862
|
-
return String(this.$currentValue);
|
|
863
|
-
};
|
|
1122
|
+
if (Validator.isFunction(key)) {
|
|
1123
|
+
return key(item, defaultKey);
|
|
1124
|
+
}
|
|
864
1125
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
* Called automatically in type coercion contexts.
|
|
868
|
-
*
|
|
869
|
-
* @returns {*} The current value of the observable
|
|
870
|
-
*/
|
|
871
|
-
ObservableItem.prototype.valueOf = function() {
|
|
872
|
-
return this.$currentValue;
|
|
1126
|
+
const val = Validator.isObservable(item) ? item.val() : item;
|
|
1127
|
+
return val ?? defaultKey;
|
|
873
1128
|
};
|
|
874
1129
|
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
unmounted: new WeakMap(),
|
|
879
|
-
unmountedSupposedSize: 0,
|
|
880
|
-
observer: null,
|
|
881
|
-
executeMountedCallback(node) {
|
|
882
|
-
const data = DocumentObserver.mounted.get(node);
|
|
883
|
-
if(!data) {
|
|
884
|
-
return;
|
|
885
|
-
}
|
|
886
|
-
data.inDom = true;
|
|
887
|
-
data.mounted && data.mounted(node);
|
|
888
|
-
},
|
|
889
|
-
executeUnmountedCallback(node) {
|
|
890
|
-
const data = DocumentObserver.unmounted.get(node);
|
|
891
|
-
if(!data) {
|
|
892
|
-
return;
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
data.inDom = false;
|
|
896
|
-
if(data.unmounted && data.unmounted(node) === true) {
|
|
897
|
-
data.disconnect();
|
|
898
|
-
node.nd?.remove();
|
|
899
|
-
}
|
|
900
|
-
},
|
|
901
|
-
checkMutation: function(mutationsList) {
|
|
902
|
-
for(const mutation of mutationsList) {
|
|
903
|
-
if(DocumentObserver.mountedSupposedSize > 0 ) {
|
|
904
|
-
for(const node of mutation.addedNodes) {
|
|
905
|
-
DocumentObserver.executeMountedCallback(node);
|
|
906
|
-
if(!node.querySelectorAll) {
|
|
907
|
-
return;
|
|
908
|
-
}
|
|
909
|
-
const children = node.querySelectorAll('[data--nd-mounted]');
|
|
910
|
-
if(!children.length) {
|
|
911
|
-
return;
|
|
912
|
-
}
|
|
913
|
-
for(const node of children) {
|
|
914
|
-
DocumentObserver.executeMountedCallback(node);
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
}
|
|
1130
|
+
const trim = function(str, char) {
|
|
1131
|
+
return str.replace(new RegExp(`^[${char}]+|[${char}]+$`, 'g'), '');
|
|
1132
|
+
};
|
|
918
1133
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
return;
|
|
924
|
-
}
|
|
925
|
-
const children = node.querySelectorAll('[data--nd-unmounted]');
|
|
926
|
-
if(!children.length) {
|
|
927
|
-
return;
|
|
928
|
-
}
|
|
929
|
-
for(const node of children) {
|
|
930
|
-
DocumentObserver.executeUnmountedCallback(node);
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
}
|
|
1134
|
+
const deepClone = (value, onObservableFound) => {
|
|
1135
|
+
try {
|
|
1136
|
+
if(window.structuredClone !== undefined) {
|
|
1137
|
+
return window.structuredClone(value);
|
|
934
1138
|
}
|
|
935
|
-
}
|
|
936
|
-
/**
|
|
937
|
-
*
|
|
938
|
-
* @param {HTMLElement} element
|
|
939
|
-
* @param {boolean} inDom
|
|
940
|
-
* @returns {{watch: (function(): Map<any, any>), disconnect: (function(): boolean), mounted: (function(*): Set<any>), unmounted: (function(*): Set<any>)}}
|
|
941
|
-
*/
|
|
942
|
-
watch: function(element, inDom = false) {
|
|
943
|
-
let data = {
|
|
944
|
-
inDom,
|
|
945
|
-
mounted: null,
|
|
946
|
-
unmounted: null,
|
|
947
|
-
disconnect: () => {
|
|
948
|
-
DocumentObserver.mounted.delete(element);
|
|
949
|
-
DocumentObserver.unmounted.delete(element);
|
|
950
|
-
DocumentObserver.mountedSupposedSize--;
|
|
951
|
-
DocumentObserver.unmountedSupposedSize--;
|
|
952
|
-
data = null;
|
|
953
|
-
}
|
|
954
|
-
};
|
|
1139
|
+
} catch (e){}
|
|
955
1140
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
mounted: (callback) => {
|
|
959
|
-
data.mounted = callback;
|
|
960
|
-
DocumentObserver.mounted.set(element, data);
|
|
961
|
-
DocumentObserver.mountedSupposedSize++;
|
|
962
|
-
},
|
|
963
|
-
unmounted: (callback) => {
|
|
964
|
-
data.unmounted = callback;
|
|
965
|
-
DocumentObserver.unmounted.set(element, data);
|
|
966
|
-
DocumentObserver.unmountedSupposedSize++;
|
|
967
|
-
}
|
|
968
|
-
};
|
|
1141
|
+
if (value === null || typeof value !== 'object') {
|
|
1142
|
+
return value;
|
|
969
1143
|
}
|
|
970
|
-
};
|
|
971
1144
|
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
subtree: true,
|
|
976
|
-
});
|
|
977
|
-
|
|
978
|
-
function NDElement(element) {
|
|
979
|
-
this.$element = element;
|
|
980
|
-
this.$observer = null;
|
|
981
|
-
{
|
|
982
|
-
PluginsManager$1.emit('NDElementCreated', element, this);
|
|
1145
|
+
// Dates
|
|
1146
|
+
if (value instanceof Date) {
|
|
1147
|
+
return new Date(value.getTime());
|
|
983
1148
|
}
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
NDElement.prototype.__$isNDElement = true;
|
|
987
1149
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
NDElement.prototype.ref = function(target, name) {
|
|
993
|
-
target[name] = this.$element;
|
|
994
|
-
return this;
|
|
995
|
-
};
|
|
1150
|
+
// Arrays
|
|
1151
|
+
if (Array.isArray(value)) {
|
|
1152
|
+
return value.map(item => deepClone(item));
|
|
1153
|
+
}
|
|
996
1154
|
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1155
|
+
// Observables - keep the référence
|
|
1156
|
+
if (Validator.isObservable(value)) {
|
|
1157
|
+
onObservableFound && onObservableFound(value);
|
|
1158
|
+
return value;
|
|
1159
|
+
}
|
|
1001
1160
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
for(
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
elementChildren.nd?.remove();
|
|
1161
|
+
// Objects
|
|
1162
|
+
const cloned = {};
|
|
1163
|
+
for (const key in value) {
|
|
1164
|
+
if (Object.hasOwn(value, key)) {
|
|
1165
|
+
cloned[key] = deepClone(value[key]);
|
|
1008
1166
|
}
|
|
1009
|
-
elementChildren = null;
|
|
1010
1167
|
}
|
|
1011
|
-
|
|
1012
|
-
return this;
|
|
1168
|
+
return cloned;
|
|
1013
1169
|
};
|
|
1014
1170
|
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1171
|
+
const LocalStorage$1 = {
|
|
1172
|
+
getJson(key) {
|
|
1173
|
+
let value = localStorage.getItem(key);
|
|
1174
|
+
try {
|
|
1175
|
+
return JSON.parse(value);
|
|
1176
|
+
} catch (e) {
|
|
1177
|
+
throw new NativeDocumentError('invalid_json:'+key);
|
|
1178
|
+
}
|
|
1179
|
+
},
|
|
1180
|
+
getNumber(key) {
|
|
1181
|
+
return Number(this.get(key));
|
|
1182
|
+
},
|
|
1183
|
+
getBool(key) {
|
|
1184
|
+
const value = this.get(key);
|
|
1185
|
+
return value === 'true' || value === '1';
|
|
1186
|
+
},
|
|
1187
|
+
setJson(key, value) {
|
|
1188
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
1189
|
+
},
|
|
1190
|
+
setBool(key, value) {
|
|
1191
|
+
localStorage.setItem(key, value ? 'true' : 'false');
|
|
1192
|
+
},
|
|
1193
|
+
get(key, defaultValue = null) {
|
|
1194
|
+
return localStorage.getItem(key) || defaultValue;
|
|
1195
|
+
},
|
|
1196
|
+
set(key, value) {
|
|
1197
|
+
return localStorage.setItem(key, value);
|
|
1198
|
+
},
|
|
1199
|
+
remove(key) {
|
|
1200
|
+
localStorage.removeItem(key);
|
|
1201
|
+
},
|
|
1202
|
+
has(key) {
|
|
1203
|
+
return localStorage.getItem(key) != null;
|
|
1204
|
+
}
|
|
1024
1205
|
};
|
|
1025
1206
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
if(states.mounted) {
|
|
1030
|
-
this.$element.setAttribute('data--nd-mounted', '1');
|
|
1031
|
-
this.$observer.mounted(states.mounted);
|
|
1207
|
+
const $getFromStorage$1 = (key, value) => {
|
|
1208
|
+
if(!LocalStorage$1.has(key)) {
|
|
1209
|
+
return value;
|
|
1032
1210
|
}
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1211
|
+
switch (typeof value) {
|
|
1212
|
+
case 'object': return LocalStorage$1.getJson(key) ?? value;
|
|
1213
|
+
case 'boolean': return LocalStorage$1.getBool(key) ?? value;
|
|
1214
|
+
case 'number': return LocalStorage$1.getNumber(key) ?? value;
|
|
1215
|
+
default: return LocalStorage$1.get(key, value) ?? value;
|
|
1036
1216
|
}
|
|
1037
|
-
return this;
|
|
1038
1217
|
};
|
|
1039
1218
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1219
|
+
const $saveToStorage$1 = (value) => {
|
|
1220
|
+
switch (typeof value) {
|
|
1221
|
+
case 'object': return LocalStorage$1.setJson;
|
|
1222
|
+
case 'boolean': return LocalStorage$1.setBool;
|
|
1223
|
+
default: return LocalStorage$1.set;
|
|
1224
|
+
}
|
|
1042
1225
|
};
|
|
1043
1226
|
|
|
1044
|
-
|
|
1045
|
-
return this.lifecycle({ unmounted: callback });
|
|
1046
|
-
};
|
|
1227
|
+
const StoreFactory = function() {
|
|
1047
1228
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
};
|
|
1229
|
+
const $stores = new Map();
|
|
1230
|
+
const $followersCache = new Map();
|
|
1051
1231
|
|
|
1052
|
-
|
|
1232
|
+
/**
|
|
1233
|
+
* Internal helper — retrieves a store entry or throws if not found.
|
|
1234
|
+
*/
|
|
1235
|
+
const $getStoreOrThrow = (method, name) => {
|
|
1236
|
+
const item = $stores.get(name);
|
|
1237
|
+
if (!item) {
|
|
1238
|
+
DebugManager.error('Store', `Store.${method}('${name}') : store not found. Did you call Store.create('${name}') first?`);
|
|
1239
|
+
throw new NativeDocumentError(
|
|
1240
|
+
`Store.${method}('${name}') : store not found.`
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
return item;
|
|
1244
|
+
};
|
|
1053
1245
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
const
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1246
|
+
/**
|
|
1247
|
+
* Internal helper — blocks write operations on a read-only observer.
|
|
1248
|
+
*/
|
|
1249
|
+
const $applyReadOnly = (observer, name, context) => {
|
|
1250
|
+
const readOnlyError = (method) => () => {
|
|
1251
|
+
DebugManager.error('Store', `Store.${context}('${name}') is read-only. '${method}()' is not allowed.`);
|
|
1252
|
+
throw new NativeDocumentError(
|
|
1253
|
+
`Store.${context}('${name}') is read-only.`
|
|
1254
|
+
);
|
|
1255
|
+
};
|
|
1256
|
+
observer.set = readOnlyError('set');
|
|
1257
|
+
observer.toggle = readOnlyError('toggle');
|
|
1258
|
+
observer.reset = readOnlyError('reset');
|
|
1259
|
+
};
|
|
1066
1260
|
|
|
1067
|
-
|
|
1068
|
-
|
|
1261
|
+
const $createObservable = (value, options = {}) => {
|
|
1262
|
+
if(Array.isArray(value)) {
|
|
1263
|
+
return Observable$1.array(value, options);
|
|
1264
|
+
}
|
|
1265
|
+
if(typeof value === 'object') {
|
|
1266
|
+
return Observable$1.object(value, options);
|
|
1267
|
+
}
|
|
1268
|
+
return Observable$1(value, options);
|
|
1269
|
+
};
|
|
1069
1270
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1271
|
+
const $api = {
|
|
1272
|
+
/**
|
|
1273
|
+
* Create a new state and return the observer.
|
|
1274
|
+
* Throws if a store with the same name already exists.
|
|
1275
|
+
*
|
|
1276
|
+
* @param {string} name
|
|
1277
|
+
* @param {*} value
|
|
1278
|
+
* @returns {ObservableItem}
|
|
1279
|
+
*/
|
|
1280
|
+
create(name, value) {
|
|
1281
|
+
if ($stores.has(name)) {
|
|
1282
|
+
DebugManager.warn('Store', `Store.create('${name}') : a store with this name already exists. Use Store.get('${name}') to retrieve it.`);
|
|
1283
|
+
throw new NativeDocumentError(
|
|
1284
|
+
`Store.create('${name}') : a store with this name already exists.`
|
|
1285
|
+
);
|
|
1286
|
+
}
|
|
1287
|
+
const observer = $createObservable(value);
|
|
1288
|
+
$stores.set(name, { observer, subscribers: new Set(), resettable: false, composed: false });
|
|
1289
|
+
return observer;
|
|
1290
|
+
},
|
|
1073
1291
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1292
|
+
/**
|
|
1293
|
+
* Create a new resettable state and return the observer.
|
|
1294
|
+
* The store can be reset to its initial value via Store.reset(name).
|
|
1295
|
+
* Throws if a store with the same name already exists.
|
|
1296
|
+
*
|
|
1297
|
+
* @param {string} name
|
|
1298
|
+
* @param {*} value
|
|
1299
|
+
* @returns {ObservableItem}
|
|
1300
|
+
*/
|
|
1301
|
+
createResettable(name, value) {
|
|
1302
|
+
if ($stores.has(name)) {
|
|
1303
|
+
DebugManager.warn('Store', `Store.createResettable('${name}') : a store with this name already exists.`);
|
|
1304
|
+
throw new NativeDocumentError(
|
|
1305
|
+
`Store.createResettable('${name}') : a store with this name already exists.`
|
|
1306
|
+
);
|
|
1307
|
+
}
|
|
1308
|
+
const observer = $createObservable(value, { reset: true });
|
|
1309
|
+
$stores.set(name, { observer, subscribers: new Set(), resettable: true, composed: false });
|
|
1310
|
+
return observer;
|
|
1311
|
+
},
|
|
1077
1312
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1313
|
+
/**
|
|
1314
|
+
* Create a computed store derived from other stores.
|
|
1315
|
+
* The value is automatically recalculated when any dependency changes.
|
|
1316
|
+
* This store is read-only — Store.use() and Store.set() will throw.
|
|
1317
|
+
* Throws if a store with the same name already exists.
|
|
1318
|
+
*
|
|
1319
|
+
* @param {string} name
|
|
1320
|
+
* @param {() => *} computation - Function that returns the computed value
|
|
1321
|
+
* @param {string[]} dependencies - Names of the stores to watch
|
|
1322
|
+
* @returns {ObservableItem}
|
|
1323
|
+
*
|
|
1324
|
+
* @example
|
|
1325
|
+
* Store.create('products', [{ id: 1, price: 10 }]);
|
|
1326
|
+
* Store.create('cart', [{ productId: 1, quantity: 2 }]);
|
|
1327
|
+
*
|
|
1328
|
+
* Store.createComposed('total', () => {
|
|
1329
|
+
* const products = Store.get('products').val();
|
|
1330
|
+
* const cart = Store.get('cart').val();
|
|
1331
|
+
* return cart.reduce((sum, item) => {
|
|
1332
|
+
* const product = products.find(p => p.id === item.productId);
|
|
1333
|
+
* return sum + (product.price * item.quantity);
|
|
1334
|
+
* }, 0);
|
|
1335
|
+
* }, ['products', 'cart']);
|
|
1336
|
+
*/
|
|
1337
|
+
createComposed(name, computation, dependencies) {
|
|
1338
|
+
if ($stores.has(name)) {
|
|
1339
|
+
DebugManager.warn('Store', `Store.createComposed('${name}') : a store with this name already exists.`);
|
|
1340
|
+
throw new NativeDocumentError(
|
|
1341
|
+
`Store.createComposed('${name}') : a store with this name already exists.`
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
if (typeof computation !== 'function') {
|
|
1345
|
+
throw new NativeDocumentError(
|
|
1346
|
+
`Store.createComposed('${name}') : computation must be a function.`
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
if (!Array.isArray(dependencies) || dependencies.length === 0) {
|
|
1350
|
+
throw new NativeDocumentError(
|
|
1351
|
+
`Store.createComposed('${name}') : dependencies must be a non-empty array of store names.`
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1092
1354
|
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
NDElement.prototype.with = function(methods) {
|
|
1108
|
-
if (!methods || typeof methods !== 'object') {
|
|
1109
|
-
throw new NativeDocumentError('extend() requires an object of methods');
|
|
1110
|
-
}
|
|
1111
|
-
{
|
|
1112
|
-
if (!this.$localExtensions) {
|
|
1113
|
-
this.$localExtensions = new Map();
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1355
|
+
// Resolve dependency observers
|
|
1356
|
+
const depObservers = dependencies.map(depName => {
|
|
1357
|
+
if(typeof depName !== 'string') {
|
|
1358
|
+
return depName;
|
|
1359
|
+
}
|
|
1360
|
+
const depItem = $stores.get(depName);
|
|
1361
|
+
if (!depItem) {
|
|
1362
|
+
DebugManager.error('Store', `Store.createComposed('${name}') : dependency '${depName}' not found. Create it first.`);
|
|
1363
|
+
throw new NativeDocumentError(
|
|
1364
|
+
`Store.createComposed('${name}') : dependency store '${depName}' not found.`
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
return depItem.observer;
|
|
1368
|
+
});
|
|
1116
1369
|
|
|
1117
|
-
|
|
1118
|
-
|
|
1370
|
+
// Create computed observable from dependency observers
|
|
1371
|
+
const observer = Observable$1.computed(computation, depObservers);
|
|
1119
1372
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1373
|
+
$stores.set(name, { observer, subscribers: new Set(), resettable: false, composed: true });
|
|
1374
|
+
return observer;
|
|
1375
|
+
},
|
|
1376
|
+
|
|
1377
|
+
/**
|
|
1378
|
+
* Returns true if a store with the given name exists.
|
|
1379
|
+
*
|
|
1380
|
+
* @param {string} name
|
|
1381
|
+
* @returns {boolean}
|
|
1382
|
+
*/
|
|
1383
|
+
has(name) {
|
|
1384
|
+
return $stores.has(name);
|
|
1385
|
+
},
|
|
1386
|
+
|
|
1387
|
+
/**
|
|
1388
|
+
* Resets a resettable store to its initial value and notifies all subscribers.
|
|
1389
|
+
* Throws if the store was not created with createResettable().
|
|
1390
|
+
*
|
|
1391
|
+
* @param {string} name
|
|
1392
|
+
*/
|
|
1393
|
+
reset(name) {
|
|
1394
|
+
const item = $getStoreOrThrow('reset', name);
|
|
1395
|
+
if (item.composed) {
|
|
1396
|
+
DebugManager.error('Store', `Store.reset('${name}') : composed stores cannot be reset. Their value is derived from dependencies.`);
|
|
1397
|
+
throw new NativeDocumentError(
|
|
1398
|
+
`Store.reset('${name}') : composed stores cannot be reset.`
|
|
1399
|
+
);
|
|
1127
1400
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1401
|
+
if (!item.resettable) {
|
|
1402
|
+
DebugManager.error('Store', `Store.reset('${name}') : this store is not resettable. Use Store.createResettable('${name}', value) instead of Store.create().`);
|
|
1403
|
+
throw new NativeDocumentError(
|
|
1404
|
+
`Store.reset('${name}') : this store is not resettable. Use Store.createResettable('${name}', value) instead of Store.create().`
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1407
|
+
item.observer.reset();
|
|
1408
|
+
},
|
|
1130
1409
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1410
|
+
/**
|
|
1411
|
+
* Returns a two-way synchronized follower of the store.
|
|
1412
|
+
* Writing to the follower propagates the value back to the store and all its subscribers.
|
|
1413
|
+
* Throws if called on a composed store — use Store.follow() instead.
|
|
1414
|
+
* Call follower.destroy() or follower.dispose() to unsubscribe.
|
|
1415
|
+
*
|
|
1416
|
+
* @param {string} name
|
|
1417
|
+
* @returns {ObservableItem}
|
|
1418
|
+
*/
|
|
1419
|
+
use(name) {
|
|
1420
|
+
const item = $getStoreOrThrow('use', name);
|
|
1133
1421
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1422
|
+
if (item.composed) {
|
|
1423
|
+
DebugManager.error('Store', `Store.use('${name}') : composed stores are read-only. Use Store.follow('${name}') instead.`);
|
|
1424
|
+
throw new NativeDocumentError(
|
|
1425
|
+
`Store.use('${name}') : composed stores are read-only. Use Store.follow('${name}') instead.`
|
|
1426
|
+
);
|
|
1427
|
+
}
|
|
1136
1428
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
* Use this to add global methods to all NDElements.
|
|
1140
|
-
*
|
|
1141
|
-
* @param {Object} methods - Object containing method definitions to add to prototype
|
|
1142
|
-
* @returns {typeof NDElement} The NDElement constructor
|
|
1143
|
-
* @throws {NativeDocumentError} If methods is not an object or contains non-function values
|
|
1144
|
-
* @example
|
|
1145
|
-
* NDElement.extend({
|
|
1146
|
-
* fadeIn() {
|
|
1147
|
-
* this.$element.style.opacity = '1';
|
|
1148
|
-
* return this;
|
|
1149
|
-
* }
|
|
1150
|
-
* });
|
|
1151
|
-
* // Now all NDElements have .fadeIn() method
|
|
1152
|
-
* Div().nd.fadeIn();
|
|
1153
|
-
*/
|
|
1154
|
-
NDElement.extend = function(methods) {
|
|
1155
|
-
if (!methods || typeof methods !== 'object') {
|
|
1156
|
-
throw new NativeDocumentError('NDElement.extend() requires an object of methods');
|
|
1157
|
-
}
|
|
1429
|
+
const { observer: originalObserver, subscribers } = item;
|
|
1430
|
+
const observerFollower = $createObservable(originalObserver.val());
|
|
1158
1431
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
}
|
|
1432
|
+
const onStoreChange = value => observerFollower.set(value);
|
|
1433
|
+
const onFollowerChange = value => originalObserver.set(value);
|
|
1162
1434
|
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1435
|
+
originalObserver.subscribe(onStoreChange);
|
|
1436
|
+
observerFollower.subscribe(onFollowerChange);
|
|
1437
|
+
|
|
1438
|
+
observerFollower.destroy = () => {
|
|
1439
|
+
originalObserver.unsubscribe(onStoreChange);
|
|
1440
|
+
observerFollower.unsubscribe(onFollowerChange);
|
|
1441
|
+
subscribers.delete(observerFollower);
|
|
1442
|
+
observerFollower.cleanup();
|
|
1443
|
+
};
|
|
1444
|
+
observerFollower.dispose = observerFollower.destroy;
|
|
1445
|
+
|
|
1446
|
+
subscribers.add(observerFollower);
|
|
1447
|
+
return observerFollower;
|
|
1448
|
+
},
|
|
1449
|
+
|
|
1450
|
+
/**
|
|
1451
|
+
* Returns a read-only follower of the store.
|
|
1452
|
+
* The follower reflects store changes but cannot write back to the store.
|
|
1453
|
+
* Any attempt to call .set(), .toggle() or .reset() will throw.
|
|
1454
|
+
* Call follower.destroy() or follower.dispose() to unsubscribe.
|
|
1455
|
+
*
|
|
1456
|
+
* @param {string} name
|
|
1457
|
+
* @returns {ObservableItem}
|
|
1458
|
+
*/
|
|
1459
|
+
follow(name) {
|
|
1460
|
+
const { observer: originalObserver, subscribers } = $getStoreOrThrow('follow', name);
|
|
1461
|
+
const observerFollower = $createObservable(originalObserver.val());
|
|
1462
|
+
|
|
1463
|
+
const onStoreChange = value => observerFollower.set(value);
|
|
1464
|
+
originalObserver.subscribe(onStoreChange);
|
|
1465
|
+
|
|
1466
|
+
$applyReadOnly(observerFollower, name, 'follow');
|
|
1467
|
+
|
|
1468
|
+
observerFollower.destroy = () => {
|
|
1469
|
+
originalObserver.unsubscribe(onStoreChange);
|
|
1470
|
+
subscribers.delete(observerFollower);
|
|
1471
|
+
observerFollower.cleanup();
|
|
1472
|
+
};
|
|
1473
|
+
observerFollower.dispose = observerFollower.destroy;
|
|
1474
|
+
|
|
1475
|
+
subscribers.add(observerFollower);
|
|
1476
|
+
return observerFollower;
|
|
1477
|
+
},
|
|
1478
|
+
|
|
1479
|
+
/**
|
|
1480
|
+
* Returns the raw store observer directly (no follower, no cleanup contract).
|
|
1481
|
+
* Use this for direct read access when you don't need to unsubscribe.
|
|
1482
|
+
* WARNING : mutations on this observer impact all subscribers immediately.
|
|
1483
|
+
*
|
|
1484
|
+
* @param {string} name
|
|
1485
|
+
* @returns {ObservableItem|null}
|
|
1486
|
+
*/
|
|
1487
|
+
get(name) {
|
|
1488
|
+
const item = $stores.get(name);
|
|
1489
|
+
if (!item) {
|
|
1490
|
+
DebugManager.warn('Store', `Store.get('${name}') : store not found.`);
|
|
1491
|
+
return null;
|
|
1492
|
+
}
|
|
1493
|
+
return item.observer;
|
|
1494
|
+
},
|
|
1495
|
+
|
|
1496
|
+
/**
|
|
1497
|
+
* @param {string} name
|
|
1498
|
+
* @returns {{ observer: ObservableItem, subscribers: Set } | null}
|
|
1499
|
+
*/
|
|
1500
|
+
getWithSubscribers(name) {
|
|
1501
|
+
return $stores.get(name) ?? null;
|
|
1502
|
+
},
|
|
1503
|
+
|
|
1504
|
+
/**
|
|
1505
|
+
* Destroys a store : cleans up the observer, destroys all followers, and removes the entry.
|
|
1506
|
+
*
|
|
1507
|
+
* @param {string} name
|
|
1508
|
+
*/
|
|
1509
|
+
delete(name) {
|
|
1510
|
+
const item = $stores.get(name);
|
|
1511
|
+
if (!item) {
|
|
1512
|
+
DebugManager.warn('Store', `Store.delete('${name}') : store not found, nothing to delete.`);
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
item.subscribers.forEach(follower => follower.destroy());
|
|
1516
|
+
item.subscribers.clear();
|
|
1517
|
+
item.observer.cleanup();
|
|
1518
|
+
$stores.delete(name);
|
|
1519
|
+
},
|
|
1520
|
+
/**
|
|
1521
|
+
* Creates an isolated store group with its own state namespace.
|
|
1522
|
+
* Each group is a fully independent StoreFactory instance —
|
|
1523
|
+
* no key conflicts, no shared state with the parent store.
|
|
1524
|
+
*
|
|
1525
|
+
* @param {string | ((group: ReturnType<typeof StoreFactory>) => void)} name - Group name for debugging, or setup callback if no name is provided
|
|
1526
|
+
* @param {((group: ReturnType<typeof StoreFactory>) => void)} [callback] - Setup function receiving the isolated store instance
|
|
1527
|
+
* @returns {ReturnType<typeof StoreFactory>}
|
|
1528
|
+
*
|
|
1529
|
+
* @example
|
|
1530
|
+
* // With name (recommended)
|
|
1531
|
+
* const EventStore = Store.group('events', (group) => {
|
|
1532
|
+
* group.create('catalog', []);
|
|
1533
|
+
* group.create('filters', { category: null, date: null });
|
|
1534
|
+
* group.createResettable('selected', null);
|
|
1535
|
+
* group.createComposed('filtered', () => {
|
|
1536
|
+
* const catalog = EventStore.get('catalog').val();
|
|
1537
|
+
* const filters = EventStore.get('filters').val();
|
|
1538
|
+
* return catalog.filter(event => {
|
|
1539
|
+
* if (filters.category && event.category !== filters.category) return false;
|
|
1540
|
+
* return true;
|
|
1541
|
+
* });
|
|
1542
|
+
* }, ['catalog', 'filters']);
|
|
1543
|
+
* });
|
|
1544
|
+
*
|
|
1545
|
+
* // Without name
|
|
1546
|
+
* const CartStore = Store.group((group) => {
|
|
1547
|
+
* group.create('items', []);
|
|
1548
|
+
* });
|
|
1549
|
+
*
|
|
1550
|
+
* // Usage
|
|
1551
|
+
* EventStore.use('catalog'); // two-way follower
|
|
1552
|
+
* EventStore.follow('filtered'); // read-only follower
|
|
1553
|
+
* EventStore.get('filters'); // raw observable
|
|
1554
|
+
*
|
|
1555
|
+
* // Cross-group composed
|
|
1556
|
+
* const OrderStore = Store.group('orders', (group) => {
|
|
1557
|
+
* group.createComposed('summary', () => {
|
|
1558
|
+
* const items = CartStore.get('items').val();
|
|
1559
|
+
* const events = EventStore.get('catalog').val();
|
|
1560
|
+
* return { items, events };
|
|
1561
|
+
* }, [CartStore.get('items'), EventStore.get('catalog')]);
|
|
1562
|
+
* });
|
|
1563
|
+
*/
|
|
1564
|
+
group(name, callback) {
|
|
1565
|
+
if (typeof name === 'function') {
|
|
1566
|
+
callback = name;
|
|
1567
|
+
name = 'anonymous';
|
|
1568
|
+
}
|
|
1569
|
+
const store = StoreFactory();
|
|
1570
|
+
callback && callback(store);
|
|
1571
|
+
return store;
|
|
1572
|
+
},
|
|
1573
|
+
createPersistent(name, value, localstorage_key) {
|
|
1574
|
+
localstorage_key = localstorage_key || name;
|
|
1575
|
+
const observer = this.create(name, $getFromStorage$1(localstorage_key, value));
|
|
1576
|
+
const saver = $saveToStorage$1(value);
|
|
1577
|
+
|
|
1578
|
+
observer.subscribe((val) => saver(localstorage_key, val));
|
|
1579
|
+
return observer;
|
|
1580
|
+
},
|
|
1581
|
+
createPersistentResettable(name, value, localstorage_key) {
|
|
1582
|
+
localstorage_key = localstorage_key || name;
|
|
1583
|
+
const observer = this.createResettable(name, $getFromStorage$1(localstorage_key, value));
|
|
1584
|
+
const saver = $saveToStorage$1(value);
|
|
1585
|
+
observer.subscribe((val) => saver(localstorage_key, val));
|
|
1586
|
+
|
|
1587
|
+
const originalReset = observer.reset.bind(observer);
|
|
1588
|
+
observer.reset = () => {
|
|
1589
|
+
LocalStorage$1.remove(localstorage_key);
|
|
1590
|
+
originalReset();
|
|
1591
|
+
};
|
|
1168
1592
|
|
|
1169
|
-
|
|
1170
|
-
if (!methods.hasOwnProperty(name)) {
|
|
1171
|
-
continue;
|
|
1593
|
+
return observer;
|
|
1172
1594
|
}
|
|
1595
|
+
};
|
|
1173
1596
|
|
|
1174
|
-
const method = methods[name];
|
|
1175
1597
|
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1598
|
+
return new Proxy($api, {
|
|
1599
|
+
get(target, prop) {
|
|
1600
|
+
if (typeof prop === 'symbol' || prop.startsWith('$') || prop in target) {
|
|
1601
|
+
return target[prop];
|
|
1602
|
+
}
|
|
1603
|
+
if (target.has(prop)) {
|
|
1604
|
+
if ($followersCache.has(prop)) {
|
|
1605
|
+
return $followersCache.get(prop);
|
|
1606
|
+
}
|
|
1607
|
+
const follower = target.follow(prop);
|
|
1608
|
+
$followersCache.set(prop, follower);
|
|
1609
|
+
return follower;
|
|
1610
|
+
}
|
|
1611
|
+
return undefined;
|
|
1612
|
+
},
|
|
1613
|
+
set(target, prop, value) {
|
|
1614
|
+
DebugManager.error('Store', `Forbidden: You cannot overwrite the store key '${String(prop)}'. Use .use('${String(prop)}').set(value) instead.`);
|
|
1615
|
+
throw new NativeDocumentError(`Store structure is immutable. Use .set() on the observable.`);
|
|
1616
|
+
},
|
|
1617
|
+
deleteProperty(target, prop) {
|
|
1618
|
+
throw new NativeDocumentError(`Store keys cannot be deleted.`);
|
|
1179
1619
|
}
|
|
1620
|
+
});
|
|
1621
|
+
};
|
|
1180
1622
|
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1623
|
+
const Store = StoreFactory();
|
|
1624
|
+
|
|
1625
|
+
Store.create('locale', 'fr');
|
|
1626
|
+
|
|
1627
|
+
const $parseDateParts = (value, locale) => {
|
|
1628
|
+
const d = new Date(value);
|
|
1629
|
+
return {
|
|
1630
|
+
d,
|
|
1631
|
+
parts: new Intl.DateTimeFormat(locale, {
|
|
1632
|
+
year: 'numeric',
|
|
1633
|
+
month: 'long',
|
|
1634
|
+
day: '2-digit',
|
|
1635
|
+
hour: '2-digit',
|
|
1636
|
+
minute: '2-digit',
|
|
1637
|
+
second: '2-digit',
|
|
1638
|
+
}).formatToParts(d).reduce((acc, { type, value }) => {
|
|
1639
|
+
acc[type] = value;
|
|
1640
|
+
return acc;
|
|
1641
|
+
}, {})
|
|
1642
|
+
};
|
|
1643
|
+
};
|
|
1644
|
+
|
|
1645
|
+
const $applyDatePattern = (pattern, d, parts) => {
|
|
1646
|
+
const pad = n => String(n).padStart(2, '0');
|
|
1647
|
+
return pattern
|
|
1648
|
+
.replace('YYYY', parts.year)
|
|
1649
|
+
.replace('YY', parts.year.slice(-2))
|
|
1650
|
+
.replace('MMMM', parts.month)
|
|
1651
|
+
.replace('MMM', parts.month.slice(0, 3))
|
|
1652
|
+
.replace('MM', pad(d.getMonth() + 1))
|
|
1653
|
+
.replace('DD', pad(d.getDate()))
|
|
1654
|
+
.replace('D', d.getDate())
|
|
1655
|
+
.replace('HH', parts.hour)
|
|
1656
|
+
.replace('mm', parts.minute)
|
|
1657
|
+
.replace('ss', parts.second);
|
|
1658
|
+
};
|
|
1659
|
+
|
|
1660
|
+
const Formatters = {
|
|
1661
|
+
|
|
1662
|
+
currency: (value, locale, { currency = 'XOF', notation, minimumFractionDigits, maximumFractionDigits } = {}) =>
|
|
1663
|
+
new Intl.NumberFormat(locale, {
|
|
1664
|
+
style: 'currency',
|
|
1665
|
+
currency,
|
|
1666
|
+
notation,
|
|
1667
|
+
minimumFractionDigits,
|
|
1668
|
+
maximumFractionDigits
|
|
1669
|
+
}).format(value),
|
|
1670
|
+
|
|
1671
|
+
number: (value, locale, { notation, minimumFractionDigits, maximumFractionDigits } = {}) =>
|
|
1672
|
+
new Intl.NumberFormat(locale, {
|
|
1673
|
+
notation,
|
|
1674
|
+
minimumFractionDigits,
|
|
1675
|
+
maximumFractionDigits
|
|
1676
|
+
}).format(value),
|
|
1677
|
+
|
|
1678
|
+
percent: (value, locale, { decimals = 1 } = {}) =>
|
|
1679
|
+
new Intl.NumberFormat(locale, {
|
|
1680
|
+
style: 'percent',
|
|
1681
|
+
maximumFractionDigits: decimals
|
|
1682
|
+
}).format(value),
|
|
1683
|
+
|
|
1684
|
+
date: (value, locale, { format, dateStyle = 'long' } = {}) => {
|
|
1685
|
+
if (format) {
|
|
1686
|
+
const { d, parts } = $parseDateParts(value, locale);
|
|
1687
|
+
return $applyDatePattern(format, d, parts);
|
|
1688
|
+
}
|
|
1689
|
+
return new Intl.DateTimeFormat(locale, { dateStyle }).format(new Date(value));
|
|
1690
|
+
},
|
|
1691
|
+
|
|
1692
|
+
time: (value, locale, { format, hour = '2-digit', minute = '2-digit', second } = {}) => {
|
|
1693
|
+
if (format) {
|
|
1694
|
+
const { d, parts } = $parseDateParts(value, locale);
|
|
1695
|
+
return $applyDatePattern(format, d, parts);
|
|
1184
1696
|
}
|
|
1697
|
+
return new Intl.DateTimeFormat(locale, { hour, minute, second }).format(new Date(value));
|
|
1698
|
+
},
|
|
1185
1699
|
|
|
1186
|
-
|
|
1187
|
-
|
|
1700
|
+
datetime: (value, locale, { format, dateStyle = 'long', hour = '2-digit', minute = '2-digit', second } = {}) => {
|
|
1701
|
+
if (format) {
|
|
1702
|
+
const { d, parts } = $parseDateParts(value, locale);
|
|
1703
|
+
return $applyDatePattern(format, d, parts);
|
|
1188
1704
|
}
|
|
1705
|
+
return new Intl.DateTimeFormat(locale, { dateStyle, hour, minute, second }).format(new Date(value));
|
|
1706
|
+
},
|
|
1189
1707
|
|
|
1190
|
-
|
|
1708
|
+
relative: (value, locale, { unit = 'day', numeric = 'auto' } = {}) => {
|
|
1709
|
+
const diff = Math.round((value - Date.now()) / (1000 * 60 * 60 * 24));
|
|
1710
|
+
return new Intl.RelativeTimeFormat(locale, { numeric }).format(diff, unit);
|
|
1711
|
+
},
|
|
1712
|
+
|
|
1713
|
+
plural: (value, locale, { singular, plural } = {}) => {
|
|
1714
|
+
const rule = new Intl.PluralRules(locale).select(value);
|
|
1715
|
+
return `${value} ${rule === 'one' ? singular : plural}`;
|
|
1716
|
+
},
|
|
1717
|
+
};
|
|
1718
|
+
|
|
1719
|
+
/**
|
|
1720
|
+
*
|
|
1721
|
+
* @param {*} value
|
|
1722
|
+
* @param {{ propagation: boolean, reset: boolean} | null} configs
|
|
1723
|
+
* @class ObservableItem
|
|
1724
|
+
*/
|
|
1725
|
+
function ObservableItem(value, configs = null) {
|
|
1726
|
+
value = Validator.isObservable(value) ? value.val() : value;
|
|
1727
|
+
|
|
1728
|
+
this.$previousValue = null;
|
|
1729
|
+
this.$currentValue = value;
|
|
1730
|
+
{
|
|
1731
|
+
this.$isCleanedUp = false;
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
this.$firstListener = null;
|
|
1735
|
+
this.$listeners = null;
|
|
1736
|
+
this.$watchers = null;
|
|
1737
|
+
|
|
1738
|
+
this.$memoryId = null;
|
|
1739
|
+
|
|
1740
|
+
if(configs) {
|
|
1741
|
+
this.configs = configs;
|
|
1742
|
+
if(configs.reset) {
|
|
1743
|
+
this.$initialValue = Validator.isObject(value) ? deepClone(value) : value;
|
|
1744
|
+
}
|
|
1191
1745
|
}
|
|
1192
1746
|
{
|
|
1193
|
-
PluginsManager
|
|
1747
|
+
PluginsManager.emit('CreateObservable', this);
|
|
1194
1748
|
}
|
|
1749
|
+
}
|
|
1195
1750
|
|
|
1196
|
-
|
|
1751
|
+
Object.defineProperty(ObservableItem.prototype, '$value', {
|
|
1752
|
+
get() {
|
|
1753
|
+
return this.$currentValue;
|
|
1754
|
+
},
|
|
1755
|
+
set(value) {
|
|
1756
|
+
this.set(value);
|
|
1757
|
+
},
|
|
1758
|
+
configurable: true,
|
|
1759
|
+
});
|
|
1760
|
+
|
|
1761
|
+
ObservableItem.prototype.__$isObservable = true;
|
|
1762
|
+
const noneTrigger = function() {};
|
|
1763
|
+
|
|
1764
|
+
/**
|
|
1765
|
+
* Intercepts and transforms values before they are set on the observable.
|
|
1766
|
+
* The interceptor can modify the value or return undefined to use the original value.
|
|
1767
|
+
*
|
|
1768
|
+
* @param {(value) => any} callback - Interceptor function that receives (newValue, currentValue) and returns the transformed value or undefined
|
|
1769
|
+
* @returns {ObservableItem} The observable instance for chaining
|
|
1770
|
+
* @example
|
|
1771
|
+
* const count = Observable(0);
|
|
1772
|
+
* count.intercept((newVal, oldVal) => Math.max(0, newVal)); // Prevent negative values
|
|
1773
|
+
*/
|
|
1774
|
+
ObservableItem.prototype.intercept = function(callback) {
|
|
1775
|
+
this.$interceptor = callback;
|
|
1776
|
+
this.set = this.$setWithInterceptor;
|
|
1777
|
+
return this;
|
|
1197
1778
|
};
|
|
1198
1779
|
|
|
1199
|
-
function
|
|
1200
|
-
this.$
|
|
1201
|
-
}
|
|
1780
|
+
ObservableItem.prototype.triggerFirstListener = function(operations) {
|
|
1781
|
+
this.$firstListener(this.$currentValue, this.$previousValue, operations);
|
|
1782
|
+
};
|
|
1202
1783
|
|
|
1203
|
-
|
|
1784
|
+
ObservableItem.prototype.triggerListeners = function(operations) {
|
|
1785
|
+
const $listeners = this.$listeners;
|
|
1786
|
+
const $previousValue = this.$previousValue;
|
|
1787
|
+
const $currentValue = this.$currentValue;
|
|
1204
1788
|
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
COMMENT: 8,
|
|
1209
|
-
DOCUMENT_FRAGMENT: 11
|
|
1789
|
+
for(let i = 0, length = $listeners.length; i < length; i++) {
|
|
1790
|
+
$listeners[i]($currentValue, $previousValue, operations);
|
|
1791
|
+
}
|
|
1210
1792
|
};
|
|
1211
1793
|
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
isTemplateBinding(value) {
|
|
1217
|
-
return value?.__$isTemplateBinding;
|
|
1218
|
-
},
|
|
1219
|
-
isObservableWhenResult(value) {
|
|
1220
|
-
return value && (value.__$isObservableWhen || (typeof value === 'object' && '$target' in value && '$observer' in value));
|
|
1221
|
-
},
|
|
1222
|
-
isArrayObservable(value) {
|
|
1223
|
-
return value?.__$isObservableArray;
|
|
1224
|
-
},
|
|
1225
|
-
isProxy(value) {
|
|
1226
|
-
return value?.__isProxy__
|
|
1227
|
-
},
|
|
1228
|
-
isObservableOrProxy(value) {
|
|
1229
|
-
return Validator.isObservable(value) || Validator.isProxy(value);
|
|
1230
|
-
},
|
|
1231
|
-
isAnchor(value) {
|
|
1232
|
-
return value?.__Anchor__
|
|
1233
|
-
},
|
|
1234
|
-
isObservableChecker(value) {
|
|
1235
|
-
return value?.__$isObservableChecker || value instanceof ObservableChecker;
|
|
1236
|
-
},
|
|
1237
|
-
isArray(value) {
|
|
1238
|
-
return Array.isArray(value);
|
|
1239
|
-
},
|
|
1240
|
-
isString(value) {
|
|
1241
|
-
return typeof value === 'string';
|
|
1242
|
-
},
|
|
1243
|
-
isNumber(value) {
|
|
1244
|
-
return typeof value === 'number';
|
|
1245
|
-
},
|
|
1246
|
-
isBoolean(value) {
|
|
1247
|
-
return typeof value === 'boolean';
|
|
1248
|
-
},
|
|
1249
|
-
isFunction(value) {
|
|
1250
|
-
return typeof value === 'function';
|
|
1251
|
-
},
|
|
1252
|
-
isAsyncFunction(value) {
|
|
1253
|
-
return typeof value === 'function' && value.constructor.name === 'AsyncFunction';
|
|
1254
|
-
},
|
|
1255
|
-
isObject(value) {
|
|
1256
|
-
return typeof value === 'object' && value !== null;
|
|
1257
|
-
},
|
|
1258
|
-
isJson(value) {
|
|
1259
|
-
return !(typeof value !== 'object' || value === null || Array.isArray(value) || value.constructor.name !== 'Object')
|
|
1260
|
-
},
|
|
1261
|
-
isElement(value) {
|
|
1262
|
-
return value && (
|
|
1263
|
-
value.nodeType === COMMON_NODE_TYPES.ELEMENT ||
|
|
1264
|
-
value.nodeType === COMMON_NODE_TYPES.TEXT ||
|
|
1265
|
-
value.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT ||
|
|
1266
|
-
value.nodeType === COMMON_NODE_TYPES.COMMENT
|
|
1267
|
-
);
|
|
1268
|
-
},
|
|
1269
|
-
isFragment(value) {
|
|
1270
|
-
return value?.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT;
|
|
1271
|
-
},
|
|
1272
|
-
isStringOrObservable(value) {
|
|
1273
|
-
return this.isString(value) || this.isObservable(value);
|
|
1274
|
-
},
|
|
1275
|
-
isValidChild(child) {
|
|
1276
|
-
return child === null ||
|
|
1277
|
-
this.isElement(child) ||
|
|
1278
|
-
this.isObservable(child) ||
|
|
1279
|
-
this.isNDElement(child) ||
|
|
1280
|
-
['string', 'number', 'boolean'].includes(typeof child);
|
|
1281
|
-
},
|
|
1282
|
-
isNDElement(child) {
|
|
1283
|
-
return child?.__$isNDElement || child instanceof NDElement;
|
|
1284
|
-
},
|
|
1285
|
-
isValidChildren(children) {
|
|
1286
|
-
if (!Array.isArray(children)) {
|
|
1287
|
-
children = [children];
|
|
1288
|
-
}
|
|
1794
|
+
ObservableItem.prototype.triggerWatchers = function(operations) {
|
|
1795
|
+
const $watchers = this.$watchers;
|
|
1796
|
+
const $previousValue = this.$previousValue;
|
|
1797
|
+
const $currentValue = this.$currentValue;
|
|
1289
1798
|
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1799
|
+
const $currentValueCallbacks = $watchers.get($currentValue);
|
|
1800
|
+
const $previousValueCallbacks = $watchers.get($previousValue);
|
|
1801
|
+
if($currentValueCallbacks) {
|
|
1802
|
+
$currentValueCallbacks(true, $previousValue, operations);
|
|
1803
|
+
}
|
|
1804
|
+
if($previousValueCallbacks) {
|
|
1805
|
+
$previousValueCallbacks(false, $currentValue, operations);
|
|
1806
|
+
}
|
|
1807
|
+
};
|
|
1297
1808
|
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1809
|
+
ObservableItem.prototype.triggerAll = function(operations) {
|
|
1810
|
+
this.triggerWatchers(operations);
|
|
1811
|
+
this.triggerListeners(operations);
|
|
1812
|
+
};
|
|
1302
1813
|
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
* @param {Array|Object} data
|
|
1308
|
-
* @returns {boolean}
|
|
1309
|
-
*/
|
|
1310
|
-
containsObservables(data) {
|
|
1311
|
-
if(!data) {
|
|
1312
|
-
return false;
|
|
1313
|
-
}
|
|
1314
|
-
return Validator.isObject(data)
|
|
1315
|
-
&& Object.values(data).some(value => Validator.isObservable(value));
|
|
1316
|
-
},
|
|
1317
|
-
/**
|
|
1318
|
-
* Check if the data contains an observable reference.
|
|
1319
|
-
* @param {string} data
|
|
1320
|
-
* @returns {boolean}
|
|
1321
|
-
*/
|
|
1322
|
-
containsObservableReference(data) {
|
|
1323
|
-
if(!data || typeof data !== 'string') {
|
|
1324
|
-
return false;
|
|
1325
|
-
}
|
|
1326
|
-
return /\{\{#ObItem::\([0-9]+\)\}\}/.test(data);
|
|
1327
|
-
},
|
|
1328
|
-
validateAttributes(attributes) {},
|
|
1814
|
+
ObservableItem.prototype.triggerWatchersAndFirstListener = function(operations) {
|
|
1815
|
+
this.triggerWatchers(operations);
|
|
1816
|
+
this.triggerFirstListener(operations);
|
|
1817
|
+
};
|
|
1329
1818
|
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1819
|
+
ObservableItem.prototype.assocTrigger = function() {
|
|
1820
|
+
this.$firstListener = null;
|
|
1821
|
+
if(this.$watchers?.size && this.$listeners?.length) {
|
|
1822
|
+
this.trigger = (this.$listeners.length === 1) ? this.triggerWatchersAndFirstListener : this.triggerAll;
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1825
|
+
if(this.$listeners?.length) {
|
|
1826
|
+
if(this.$listeners.length === 1) {
|
|
1827
|
+
this.$firstListener = this.$listeners[0];
|
|
1828
|
+
this.trigger = this.triggerFirstListener;
|
|
1829
|
+
}
|
|
1830
|
+
else {
|
|
1831
|
+
this.trigger = this.triggerListeners;
|
|
1333
1832
|
}
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
if(this.$watchers?.size) {
|
|
1836
|
+
this.trigger = this.triggerWatchers;
|
|
1837
|
+
return;
|
|
1334
1838
|
}
|
|
1839
|
+
this.trigger = noneTrigger;
|
|
1335
1840
|
};
|
|
1336
|
-
|
|
1337
|
-
Validator.validateAttributes = function(attributes) {
|
|
1338
|
-
if (!attributes || typeof attributes !== 'object') {
|
|
1339
|
-
return attributes;
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
|
-
const reserved = [];
|
|
1343
|
-
const foundReserved = Object.keys(attributes).filter(key => reserved.includes(key));
|
|
1841
|
+
ObservableItem.prototype.trigger = noneTrigger;
|
|
1344
1842
|
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1843
|
+
ObservableItem.prototype.$updateWithNewValue = function(newValue) {
|
|
1844
|
+
newValue = newValue?.__$isObservable ? newValue.val() : newValue;
|
|
1845
|
+
if(this.$currentValue === newValue) {
|
|
1846
|
+
return;
|
|
1847
|
+
}
|
|
1848
|
+
this.$previousValue = this.$currentValue;
|
|
1849
|
+
this.$currentValue = newValue;
|
|
1850
|
+
{
|
|
1851
|
+
PluginsManager.emit('ObservableBeforeChange', this);
|
|
1852
|
+
}
|
|
1853
|
+
this.trigger();
|
|
1854
|
+
this.$previousValue = null;
|
|
1855
|
+
{
|
|
1856
|
+
PluginsManager.emit('ObservableAfterChange', this);
|
|
1857
|
+
}
|
|
1858
|
+
};
|
|
1348
1859
|
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1860
|
+
/**
|
|
1861
|
+
* @param {*} data
|
|
1862
|
+
*/
|
|
1863
|
+
ObservableItem.prototype.$setWithInterceptor = function(data) {
|
|
1864
|
+
let newValue = (typeof data === 'function') ? data(this.$currentValue) : data;
|
|
1865
|
+
const result = this.$interceptor(newValue, this.$currentValue);
|
|
1352
1866
|
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1867
|
+
if (result !== undefined) {
|
|
1868
|
+
newValue = result;
|
|
1869
|
+
}
|
|
1356
1870
|
|
|
1357
|
-
|
|
1358
|
-
|
|
1871
|
+
this.$updateWithNewValue(newValue);
|
|
1872
|
+
};
|
|
1359
1873
|
|
|
1360
|
-
|
|
1361
|
-
|
|
1874
|
+
/**
|
|
1875
|
+
* @param {*} data
|
|
1876
|
+
*/
|
|
1877
|
+
ObservableItem.prototype.$basicSet = function(data) {
|
|
1878
|
+
let newValue = (typeof data === 'function') ? data(this.$currentValue) : data;
|
|
1879
|
+
this.$updateWithNewValue(newValue);
|
|
1880
|
+
};
|
|
1362
1881
|
|
|
1363
|
-
|
|
1364
|
-
anchorFragment.nativeAppendChild = anchorFragment.appendChild;
|
|
1882
|
+
ObservableItem.prototype.set = ObservableItem.prototype.$basicSet;
|
|
1365
1883
|
|
|
1366
|
-
|
|
1884
|
+
ObservableItem.prototype.val = function() {
|
|
1885
|
+
return this.$currentValue;
|
|
1886
|
+
};
|
|
1367
1887
|
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1888
|
+
ObservableItem.prototype.disconnectAll = function() {
|
|
1889
|
+
this.$listeners?.splice(0);
|
|
1890
|
+
this.$previousValue = null;
|
|
1891
|
+
this.$currentValue = null;
|
|
1892
|
+
if(this.$watchers) {
|
|
1893
|
+
for (const [_, watchValueList] of this.$watchers) {
|
|
1894
|
+
if(Validator.isArray(watchValueList)) {
|
|
1895
|
+
watchValueList.splice(0);
|
|
1896
|
+
}
|
|
1377
1897
|
}
|
|
1378
|
-
|
|
1379
|
-
|
|
1898
|
+
}
|
|
1899
|
+
this.$watchers?.clear();
|
|
1900
|
+
this.$listeners = null;
|
|
1901
|
+
this.$watchers = null;
|
|
1902
|
+
this.trigger = noneTrigger;
|
|
1903
|
+
};
|
|
1380
1904
|
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1905
|
+
/**
|
|
1906
|
+
* Registers a cleanup callback that will be executed when the observable is cleaned up.
|
|
1907
|
+
* Useful for disposing resources, removing event listeners, or other cleanup tasks.
|
|
1908
|
+
*
|
|
1909
|
+
* @param {Function} callback - Cleanup function to execute on observable disposal
|
|
1910
|
+
* @example
|
|
1911
|
+
* const obs = Observable(0);
|
|
1912
|
+
* obs.onCleanup(() => console.log('Cleaned up!'));
|
|
1913
|
+
* obs.cleanup(); // Logs: "Cleaned up!"
|
|
1914
|
+
*/
|
|
1915
|
+
ObservableItem.prototype.onCleanup = function(callback) {
|
|
1916
|
+
this.$cleanupListeners = this.$cleanupListeners ?? [];
|
|
1917
|
+
this.$cleanupListeners.push(callback);
|
|
1918
|
+
};
|
|
1390
1919
|
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
return;
|
|
1920
|
+
ObservableItem.prototype.cleanup = function() {
|
|
1921
|
+
if (this.$cleanupListeners) {
|
|
1922
|
+
for (let i = 0; i < this.$cleanupListeners.length; i++) {
|
|
1923
|
+
this.$cleanupListeners[i]();
|
|
1396
1924
|
}
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1925
|
+
this.$cleanupListeners = null;
|
|
1926
|
+
}
|
|
1927
|
+
MemoryManager.unregister(this.$memoryId);
|
|
1928
|
+
this.disconnectAll();
|
|
1929
|
+
{
|
|
1930
|
+
this.$isCleanedUp = true;
|
|
1931
|
+
}
|
|
1932
|
+
delete this.$value;
|
|
1933
|
+
};
|
|
1403
1934
|
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1935
|
+
/**
|
|
1936
|
+
*
|
|
1937
|
+
* @param {Function} callback
|
|
1938
|
+
* @returns {(function(): void)}
|
|
1939
|
+
*/
|
|
1940
|
+
ObservableItem.prototype.subscribe = function(callback) {
|
|
1941
|
+
{
|
|
1942
|
+
if (this.$isCleanedUp) {
|
|
1943
|
+
DebugManager.warn('Observable subscription', '⚠️ Attempted to subscribe to a cleaned up observable.');
|
|
1407
1944
|
return;
|
|
1408
1945
|
}
|
|
1409
|
-
if(
|
|
1410
|
-
|
|
1411
|
-
return;
|
|
1946
|
+
if (typeof callback !== 'function') {
|
|
1947
|
+
throw new NativeDocumentError('Callback must be a function');
|
|
1412
1948
|
}
|
|
1949
|
+
}
|
|
1950
|
+
this.$listeners = this.$listeners ?? [];
|
|
1413
1951
|
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1952
|
+
this.$listeners.push(callback);
|
|
1953
|
+
this.assocTrigger();
|
|
1954
|
+
{
|
|
1955
|
+
PluginsManager.emit('ObservableSubscribe', this);
|
|
1956
|
+
}
|
|
1957
|
+
};
|
|
1958
|
+
|
|
1959
|
+
/**
|
|
1960
|
+
* Watches for a specific value and executes callback when the observable equals that value.
|
|
1961
|
+
* Creates a watcher that only triggers when the observable changes to the specified value.
|
|
1962
|
+
*
|
|
1963
|
+
* @param {*} value - The value to watch for
|
|
1964
|
+
* @param {(value) => void|ObservableItem} callback - Callback function or observable to set when value matches
|
|
1965
|
+
* @example
|
|
1966
|
+
* const status = Observable('idle');
|
|
1967
|
+
* status.on('loading', () => console.log('Started loading'));
|
|
1968
|
+
* status.on('error', isError); // Set another observable
|
|
1969
|
+
*/
|
|
1970
|
+
ObservableItem.prototype.on = function(value, callback) {
|
|
1971
|
+
this.$watchers = this.$watchers ?? new Map();
|
|
1972
|
+
|
|
1973
|
+
let watchValueList = this.$watchers.get(value);
|
|
1974
|
+
|
|
1975
|
+
if(callback.__$isObservable) {
|
|
1976
|
+
callback = callback.set.bind(callback);
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
if(!watchValueList) {
|
|
1980
|
+
watchValueList = callback;
|
|
1981
|
+
this.$watchers.set(value, callback);
|
|
1982
|
+
} else if(!Validator.isArray(watchValueList.list)) {
|
|
1983
|
+
watchValueList = [watchValueList, callback];
|
|
1984
|
+
callback = (value) => {
|
|
1985
|
+
for(let i = 0, length = watchValueList.length; i < length; i++) {
|
|
1986
|
+
watchValueList[i](value);
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1989
|
+
callback.list = watchValueList;
|
|
1990
|
+
this.$watchers.set(value, callback);
|
|
1991
|
+
} else {
|
|
1992
|
+
watchValueList.list.push(callback);
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
this.assocTrigger();
|
|
1996
|
+
};
|
|
1997
|
+
|
|
1998
|
+
/**
|
|
1999
|
+
* Removes a watcher for a specific value. If no callback is provided, removes all watchers for that value.
|
|
2000
|
+
*
|
|
2001
|
+
* @param {*} value - The value to stop watching
|
|
2002
|
+
* @param {Function} [callback] - Specific callback to remove. If omitted, removes all watchers for this value
|
|
2003
|
+
* @example
|
|
2004
|
+
* const status = Observable('idle');
|
|
2005
|
+
* const handler = () => console.log('Loading');
|
|
2006
|
+
* status.on('loading', handler);
|
|
2007
|
+
* status.off('loading', handler); // Remove specific handler
|
|
2008
|
+
* status.off('loading'); // Remove all handlers for 'loading'
|
|
2009
|
+
*/
|
|
2010
|
+
ObservableItem.prototype.off = function(value, callback) {
|
|
2011
|
+
if(!this.$watchers) return;
|
|
2012
|
+
|
|
2013
|
+
const watchValueList = this.$watchers.get(value);
|
|
2014
|
+
if(!watchValueList) return;
|
|
2015
|
+
|
|
2016
|
+
if(!callback || !Array.isArray(watchValueList.list)) {
|
|
2017
|
+
this.$watchers?.delete(value);
|
|
2018
|
+
this.assocTrigger();
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
2021
|
+
const index = watchValueList.indexOf(callback);
|
|
2022
|
+
watchValueList?.splice(index, 1);
|
|
2023
|
+
if(watchValueList.length === 1) {
|
|
2024
|
+
this.$watchers.set(value, watchValueList[0]);
|
|
2025
|
+
}
|
|
2026
|
+
else if(watchValueList.length === 0) {
|
|
2027
|
+
this.$watchers?.delete(value);
|
|
2028
|
+
}
|
|
2029
|
+
this.assocTrigger();
|
|
2030
|
+
};
|
|
2031
|
+
|
|
2032
|
+
/**
|
|
2033
|
+
* Subscribes to the observable but automatically unsubscribes after the first time the predicate matches.
|
|
2034
|
+
*
|
|
2035
|
+
* @param {(value) => Boolean|any} predicate - Value to match or function that returns true when condition is met
|
|
2036
|
+
* @param {(value) => void} callback - Callback to execute when predicate matches, receives the matched value
|
|
2037
|
+
* @example
|
|
2038
|
+
* const status = Observable('loading');
|
|
2039
|
+
* status.once('ready', (val) => console.log('Ready!'));
|
|
2040
|
+
* status.once(val => val === 'error', (val) => console.log('Error occurred'));
|
|
2041
|
+
*/
|
|
2042
|
+
ObservableItem.prototype.once = function(predicate, callback) {
|
|
2043
|
+
const fn = typeof predicate === 'function' ? predicate : (v) => v === predicate;
|
|
2044
|
+
|
|
2045
|
+
const handler = (val) => {
|
|
2046
|
+
if (fn(val)) {
|
|
2047
|
+
this.unsubscribe(handler);
|
|
2048
|
+
callback(val);
|
|
1433
2049
|
}
|
|
1434
2050
|
};
|
|
2051
|
+
this.subscribe(handler);
|
|
2052
|
+
};
|
|
1435
2053
|
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
2054
|
+
/**
|
|
2055
|
+
* Unsubscribe from an observable.
|
|
2056
|
+
* @param {Function} callback
|
|
2057
|
+
*/
|
|
2058
|
+
ObservableItem.prototype.unsubscribe = function(callback) {
|
|
2059
|
+
if(!this.$listeners) return;
|
|
2060
|
+
const index = this.$listeners.indexOf(callback);
|
|
2061
|
+
if (index > -1) {
|
|
2062
|
+
this.$listeners.splice(index, 1);
|
|
2063
|
+
}
|
|
2064
|
+
this.assocTrigger();
|
|
2065
|
+
{
|
|
2066
|
+
PluginsManager.emit('ObservableUnsubscribe', this);
|
|
2067
|
+
}
|
|
2068
|
+
};
|
|
1441
2069
|
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
return;
|
|
1451
|
-
}
|
|
1452
|
-
anchorFragment.removeChildren();
|
|
1453
|
-
parent.insertBefore(childElement, anchorEnd);
|
|
1454
|
-
};
|
|
2070
|
+
/**
|
|
2071
|
+
* Create an Observable checker instance
|
|
2072
|
+
* @param callback
|
|
2073
|
+
* @returns {ObservableChecker}
|
|
2074
|
+
*/
|
|
2075
|
+
ObservableItem.prototype.check = function(callback) {
|
|
2076
|
+
return new ObservableChecker(this, callback)
|
|
2077
|
+
};
|
|
1455
2078
|
|
|
1456
|
-
|
|
2079
|
+
ObservableItem.prototype.transform = ObservableItem.prototype.check;
|
|
2080
|
+
ObservableItem.prototype.pluck = ObservableItem.prototype.check;
|
|
2081
|
+
ObservableItem.prototype.is = ObservableItem.prototype.check;
|
|
2082
|
+
ObservableItem.prototype.select = ObservableItem.prototype.check;
|
|
1457
2083
|
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
2084
|
+
/**
|
|
2085
|
+
* Gets a property value from the observable's current value.
|
|
2086
|
+
* If the property is an observable, returns its value.
|
|
2087
|
+
*
|
|
2088
|
+
* @param {string|number} key - Property key to retrieve
|
|
2089
|
+
* @returns {*} The value of the property, unwrapped if it's an observable
|
|
2090
|
+
* @example
|
|
2091
|
+
* const user = Observable({ name: 'John', age: Observable(25) });
|
|
2092
|
+
* user.get('name'); // 'John'
|
|
2093
|
+
* user.get('age'); // 25 (unwrapped from observable)
|
|
2094
|
+
*/
|
|
2095
|
+
ObservableItem.prototype.get = function(key) {
|
|
2096
|
+
const item = this.$currentValue[key];
|
|
2097
|
+
return Validator.isObservable(item) ? item.val() : item;
|
|
2098
|
+
};
|
|
1461
2099
|
|
|
2100
|
+
/**
|
|
2101
|
+
* Creates an ObservableWhen that represents whether the observable equals a specific value.
|
|
2102
|
+
* Returns an object that can be subscribed to and will emit true/false.
|
|
2103
|
+
*
|
|
2104
|
+
* @param {*} value - The value to compare against
|
|
2105
|
+
* @returns {ObservableWhen} An ObservableWhen instance that tracks when the observable equals the value
|
|
2106
|
+
* @example
|
|
2107
|
+
* const status = Observable('idle');
|
|
2108
|
+
* const isLoading = status.when('loading');
|
|
2109
|
+
* isLoading.subscribe(active => console.log('Loading:', active));
|
|
2110
|
+
* status.set('loading'); // Logs: "Loading: true"
|
|
2111
|
+
*/
|
|
2112
|
+
ObservableItem.prototype.when = function(value) {
|
|
2113
|
+
return new ObservableWhen(this, value);
|
|
2114
|
+
};
|
|
1462
2115
|
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
2116
|
+
/**
|
|
2117
|
+
* Compares the observable's current value with another value or observable.
|
|
2118
|
+
*
|
|
2119
|
+
* @param {*|ObservableItem} other - Value or observable to compare against
|
|
2120
|
+
* @returns {boolean} True if values are equal
|
|
2121
|
+
* @example
|
|
2122
|
+
* const a = Observable(5);
|
|
2123
|
+
* const b = Observable(5);
|
|
2124
|
+
* a.equals(5); // true
|
|
2125
|
+
* a.equals(b); // true
|
|
2126
|
+
* a.equals(10); // false
|
|
2127
|
+
*/
|
|
2128
|
+
ObservableItem.prototype.equals = function(other) {
|
|
2129
|
+
if(Validator.isObservable(other)) {
|
|
2130
|
+
return this.$currentValue === other.$currentValue;
|
|
2131
|
+
}
|
|
2132
|
+
return this.$currentValue === other;
|
|
2133
|
+
};
|
|
1466
2134
|
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
2135
|
+
/**
|
|
2136
|
+
* Converts the observable's current value to a boolean.
|
|
2137
|
+
*
|
|
2138
|
+
* @returns {boolean} The boolean representation of the current value
|
|
2139
|
+
* @example
|
|
2140
|
+
* const count = Observable(0);
|
|
2141
|
+
* count.toBool(); // false
|
|
2142
|
+
* count.set(5);
|
|
2143
|
+
* count.toBool(); // true
|
|
2144
|
+
*/
|
|
2145
|
+
ObservableItem.prototype.toBool = function() {
|
|
2146
|
+
return !!this.$currentValue;
|
|
2147
|
+
};
|
|
1475
2148
|
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
2149
|
+
/**
|
|
2150
|
+
* Toggles the boolean value of the observable (false becomes true, true becomes false).
|
|
2151
|
+
*
|
|
2152
|
+
* @example
|
|
2153
|
+
* const isOpen = Observable(false);
|
|
2154
|
+
* isOpen.toggle(); // Now true
|
|
2155
|
+
* isOpen.toggle(); // Now false
|
|
2156
|
+
*/
|
|
2157
|
+
ObservableItem.prototype.toggle = function() {
|
|
2158
|
+
this.set(!this.$currentValue);
|
|
2159
|
+
};
|
|
1486
2160
|
|
|
1487
|
-
return anchorFragment;
|
|
1488
|
-
}
|
|
1489
2161
|
/**
|
|
2162
|
+
* Resets the observable to its initial value.
|
|
2163
|
+
* Only works if the observable was created with { reset: true } config.
|
|
1490
2164
|
*
|
|
1491
|
-
* @
|
|
1492
|
-
*
|
|
1493
|
-
*
|
|
2165
|
+
* @example
|
|
2166
|
+
* const count = Observable(0, { reset: true });
|
|
2167
|
+
* count.set(10);
|
|
2168
|
+
* count.reset(); // Back to 0
|
|
1494
2169
|
*/
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
2170
|
+
ObservableItem.prototype.reset = function() {
|
|
2171
|
+
if(!this.configs?.reset) {
|
|
2172
|
+
return;
|
|
2173
|
+
}
|
|
2174
|
+
const resetValue = (Validator.isObject(this.$initialValue))
|
|
2175
|
+
? deepClone(this.$initialValue, (observable) => {
|
|
2176
|
+
observable.reset();
|
|
2177
|
+
})
|
|
2178
|
+
: this.$initialValue;
|
|
2179
|
+
this.set(resetValue);
|
|
2180
|
+
};
|
|
1498
2181
|
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
2182
|
+
/**
|
|
2183
|
+
* Returns a string representation of the observable's current value.
|
|
2184
|
+
*
|
|
2185
|
+
* @returns {string} String representation of the current value
|
|
2186
|
+
*/
|
|
2187
|
+
ObservableItem.prototype.toString = function() {
|
|
2188
|
+
return String(this.$currentValue);
|
|
2189
|
+
};
|
|
1502
2190
|
|
|
1503
|
-
|
|
2191
|
+
/**
|
|
2192
|
+
* Returns the primitive value of the observable (its current value).
|
|
2193
|
+
* Called automatically in type coercion contexts.
|
|
2194
|
+
*
|
|
2195
|
+
* @returns {*} The current value of the observable
|
|
2196
|
+
*/
|
|
2197
|
+
ObservableItem.prototype.valueOf = function() {
|
|
2198
|
+
return this.$currentValue;
|
|
2199
|
+
};
|
|
1504
2200
|
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
2201
|
+
|
|
2202
|
+
/**
|
|
2203
|
+
* Creates a derived observable that formats the current value using Intl.
|
|
2204
|
+
* Automatically reacts to both value changes and locale changes (Store.__nd.locale).
|
|
2205
|
+
*
|
|
2206
|
+
* @param {string | Function} type - Format type or custom formatter function
|
|
2207
|
+
* @param {Object} [options={}] - Options passed to the formatter
|
|
2208
|
+
* @returns {ObservableItem<string>}
|
|
2209
|
+
*
|
|
2210
|
+
* @example
|
|
2211
|
+
* // Currency
|
|
2212
|
+
* price.format('currency') // "15 000 FCFA"
|
|
2213
|
+
* price.format('currency', { currency: 'EUR' }) // "15 000,00 €"
|
|
2214
|
+
* price.format('currency', { notation: 'compact' }) // "15 K FCFA"
|
|
2215
|
+
*
|
|
2216
|
+
* // Number
|
|
2217
|
+
* count.format('number') // "15 000"
|
|
2218
|
+
*
|
|
2219
|
+
* // Percent
|
|
2220
|
+
* rate.format('percent') // "15,0 %"
|
|
2221
|
+
* rate.format('percent', { decimals: 2 }) // "15,00 %"
|
|
2222
|
+
*
|
|
2223
|
+
* // Date
|
|
2224
|
+
* date.format('date') // "3 mars 2026"
|
|
2225
|
+
* date.format('date', { dateStyle: 'full' }) // "mardi 3 mars 2026"
|
|
2226
|
+
* date.format('date', { format: 'DD/MM/YYYY' }) // "03/03/2026"
|
|
2227
|
+
* date.format('date', { format: 'DD MMM YYYY' }) // "03 mar 2026"
|
|
2228
|
+
* date.format('date', { format: 'DD MMMM YYYY' }) // "03 mars 2026"
|
|
2229
|
+
*
|
|
2230
|
+
* // Time
|
|
2231
|
+
* date.format('time') // "20:30"
|
|
2232
|
+
* date.format('time', { second: '2-digit' }) // "20:30:00"
|
|
2233
|
+
* date.format('time', { format: 'HH:mm:ss' }) // "20:30:00"
|
|
2234
|
+
*
|
|
2235
|
+
* // Datetime
|
|
2236
|
+
* date.format('datetime') // "3 mars 2026, 20:30"
|
|
2237
|
+
* date.format('datetime', { dateStyle: 'full' }) // "mardi 3 mars 2026, 20:30"
|
|
2238
|
+
* date.format('datetime', { format: 'DD/MM/YYYY HH:mm' }) // "03/03/2026 20:30"
|
|
2239
|
+
*
|
|
2240
|
+
* // Relative
|
|
2241
|
+
* date.format('relative') // "dans 11 jours"
|
|
2242
|
+
* date.format('relative', { unit: 'month' }) // "dans 1 mois"
|
|
2243
|
+
*
|
|
2244
|
+
* // Plural
|
|
2245
|
+
* count.format('plural', { singular: 'billet', plural: 'billets' }) // "3 billets"
|
|
2246
|
+
*
|
|
2247
|
+
* // Custom formatter
|
|
2248
|
+
* price.format(value => `${value.toLocaleString()} FCFA`)
|
|
2249
|
+
*
|
|
2250
|
+
* // Reacts to locale changes automatically
|
|
2251
|
+
* Store.setLocale('en-US');
|
|
2252
|
+
*/
|
|
2253
|
+
ObservableItem.prototype.format = function(type, options = {}) {
|
|
2254
|
+
const self = this;
|
|
2255
|
+
|
|
2256
|
+
if (typeof type === 'function') {
|
|
2257
|
+
return new ObservableChecker(self, type);
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
{
|
|
2261
|
+
if (!Formatters[type]) {
|
|
2262
|
+
throw new NativeDocumentError(
|
|
2263
|
+
`Observable.format : unknown type '${type}'. Available : ${Object.keys(Formatters).join(', ')}.`
|
|
2264
|
+
);
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
const formatter = Formatters[type];
|
|
2269
|
+
const localeObservable = Store.follow('locale');
|
|
2270
|
+
|
|
2271
|
+
return Observable$1.computed(() => formatter(self.val(), localeObservable.val(), options),
|
|
2272
|
+
[self, localeObservable]
|
|
2273
|
+
);
|
|
2274
|
+
};
|
|
2275
|
+
|
|
2276
|
+
ObservableItem.prototype.persist = function(key, options = {}) {
|
|
2277
|
+
let value = $getFromStorage$1(key, this.$currentValue);
|
|
2278
|
+
if(options.get) {
|
|
2279
|
+
value = options.get(value);
|
|
2280
|
+
}
|
|
2281
|
+
this.set(value);
|
|
2282
|
+
const saver = $saveToStorage$1(this.$currentValue);
|
|
2283
|
+
this.subscribe((newValue) => {
|
|
2284
|
+
saver(key, options.set ? options.set(newValue) : newValue);
|
|
2285
|
+
});
|
|
2286
|
+
return this;
|
|
2287
|
+
};
|
|
1537
2288
|
|
|
1538
2289
|
/**
|
|
1539
2290
|
*
|
|
@@ -1542,18 +2293,18 @@ var NativeDocument = (function (exports) {
|
|
|
1542
2293
|
* @returns {ObservableItem}
|
|
1543
2294
|
* @constructor
|
|
1544
2295
|
*/
|
|
1545
|
-
function Observable(value, configs = null) {
|
|
2296
|
+
function Observable$1(value, configs = null) {
|
|
1546
2297
|
return new ObservableItem(value, configs);
|
|
1547
2298
|
}
|
|
1548
2299
|
|
|
1549
|
-
const $ = Observable;
|
|
1550
|
-
const obs = Observable;
|
|
2300
|
+
const $ = Observable$1;
|
|
2301
|
+
const obs = Observable$1;
|
|
1551
2302
|
|
|
1552
2303
|
/**
|
|
1553
2304
|
*
|
|
1554
2305
|
* @param {string} propertyName
|
|
1555
2306
|
*/
|
|
1556
|
-
Observable.useValueProperty = function(propertyName = 'value') {
|
|
2307
|
+
Observable$1.useValueProperty = function(propertyName = 'value') {
|
|
1557
2308
|
Object.defineProperty(ObservableItem.prototype, propertyName, {
|
|
1558
2309
|
get() {
|
|
1559
2310
|
return this.$currentValue;
|
|
@@ -1571,7 +2322,7 @@ var NativeDocument = (function (exports) {
|
|
|
1571
2322
|
* @param id
|
|
1572
2323
|
* @returns {ObservableItem|null}
|
|
1573
2324
|
*/
|
|
1574
|
-
Observable.getById = function(id) {
|
|
2325
|
+
Observable$1.getById = function(id) {
|
|
1575
2326
|
const item = MemoryManager.getObservableById(parseInt(id));
|
|
1576
2327
|
if(!item) {
|
|
1577
2328
|
throw new NativeDocumentError('Observable.getById : No observable found with id ' + id);
|
|
@@ -1583,7 +2334,7 @@ var NativeDocument = (function (exports) {
|
|
|
1583
2334
|
*
|
|
1584
2335
|
* @param {ObservableItem} observable
|
|
1585
2336
|
*/
|
|
1586
|
-
Observable.cleanup = function(observable) {
|
|
2337
|
+
Observable$1.cleanup = function(observable) {
|
|
1587
2338
|
observable.cleanup();
|
|
1588
2339
|
};
|
|
1589
2340
|
|
|
@@ -1592,7 +2343,7 @@ var NativeDocument = (function (exports) {
|
|
|
1592
2343
|
* @param {Boolean} enable
|
|
1593
2344
|
* @param {{interval:Boolean, threshold:number}} options
|
|
1594
2345
|
*/
|
|
1595
|
-
Observable.autoCleanup = function(enable = false, options = {}) {
|
|
2346
|
+
Observable$1.autoCleanup = function(enable = false, options = {}) {
|
|
1596
2347
|
if(!enable) {
|
|
1597
2348
|
return;
|
|
1598
2349
|
}
|
|
@@ -1737,6 +2488,12 @@ var NativeDocument = (function (exports) {
|
|
|
1737
2488
|
return element;
|
|
1738
2489
|
}
|
|
1739
2490
|
|
|
2491
|
+
function TemplateBinding(hydrate) {
|
|
2492
|
+
this.$hydrate = hydrate;
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
TemplateBinding.prototype.__$isTemplateBinding = true;
|
|
2496
|
+
|
|
1740
2497
|
String.prototype.toNdElement = function () {
|
|
1741
2498
|
const formattedChild = this.resolveObservableTemplate ? this.resolveObservableTemplate() : this;
|
|
1742
2499
|
if(Validator.isString(formattedChild)) {
|
|
@@ -1784,7 +2541,7 @@ var NativeDocument = (function (exports) {
|
|
|
1784
2541
|
Function.prototype.toNdElement = function () {
|
|
1785
2542
|
const child = this;
|
|
1786
2543
|
{
|
|
1787
|
-
PluginsManager
|
|
2544
|
+
PluginsManager.emit('BeforeProcessComponent', child);
|
|
1788
2545
|
}
|
|
1789
2546
|
return ElementCreator.getChild(child());
|
|
1790
2547
|
};
|
|
@@ -1793,6 +2550,88 @@ var NativeDocument = (function (exports) {
|
|
|
1793
2550
|
return ElementCreator.createHydratableNode(null, this);
|
|
1794
2551
|
};
|
|
1795
2552
|
|
|
2553
|
+
/**
|
|
2554
|
+
* @param {HTMLElement} el
|
|
2555
|
+
* @param {number} timeout
|
|
2556
|
+
*/
|
|
2557
|
+
const waitForVisualEnd = (el, timeout = 1000) => {
|
|
2558
|
+
return new Promise((resolve) => {
|
|
2559
|
+
let isResolved = false;
|
|
2560
|
+
|
|
2561
|
+
const cleanupAndResolve = (e) => {
|
|
2562
|
+
if (e && e.target !== el) return;
|
|
2563
|
+
if (isResolved) return;
|
|
2564
|
+
|
|
2565
|
+
isResolved = true;
|
|
2566
|
+
el.removeEventListener('transitionend', cleanupAndResolve);
|
|
2567
|
+
el.removeEventListener('animationend', cleanupAndResolve);
|
|
2568
|
+
clearTimeout(timer);
|
|
2569
|
+
resolve();
|
|
2570
|
+
};
|
|
2571
|
+
|
|
2572
|
+
el.addEventListener('transitionend', cleanupAndResolve);
|
|
2573
|
+
el.addEventListener('animationend', cleanupAndResolve);
|
|
2574
|
+
|
|
2575
|
+
const timer = setTimeout(cleanupAndResolve, timeout);
|
|
2576
|
+
|
|
2577
|
+
const style = window.getComputedStyle(el);
|
|
2578
|
+
const hasTransition = style.transitionDuration !== '0s';
|
|
2579
|
+
const hasAnimation = style.animationDuration !== '0s';
|
|
2580
|
+
|
|
2581
|
+
if (!hasTransition && !hasAnimation) {
|
|
2582
|
+
cleanupAndResolve();
|
|
2583
|
+
}
|
|
2584
|
+
});
|
|
2585
|
+
};
|
|
2586
|
+
|
|
2587
|
+
NDElement.prototype.transitionOut = function(transitionName) {
|
|
2588
|
+
const exitClass = transitionName + '-exit';
|
|
2589
|
+
this.beforeUnmount('transition-exit', async function() {
|
|
2590
|
+
this.$element.classes.add(exitClass);
|
|
2591
|
+
await waitForVisualEnd(this.$element);
|
|
2592
|
+
this.$element.classes.remove(exitClass);
|
|
2593
|
+
});
|
|
2594
|
+
return this;
|
|
2595
|
+
};
|
|
2596
|
+
|
|
2597
|
+
NDElement.prototype.transitionIn = function(transitionName) {
|
|
2598
|
+
const startClass = transitionName + '-enter-from';
|
|
2599
|
+
const endClass = transitionName + '-enter-to';
|
|
2600
|
+
|
|
2601
|
+
this.$element.classes.add(startClass);
|
|
2602
|
+
|
|
2603
|
+
this.mounted(() => {
|
|
2604
|
+
requestAnimationFrame(() => {
|
|
2605
|
+
requestAnimationFrame(() => {
|
|
2606
|
+
this.$element.classes.remove(startClass);
|
|
2607
|
+
this.$element.classes.add(endClass);
|
|
2608
|
+
|
|
2609
|
+
waitForVisualEnd(this.$element).then(() => {
|
|
2610
|
+
this.$element.classes.remove(endClass);
|
|
2611
|
+
});
|
|
2612
|
+
});
|
|
2613
|
+
});
|
|
2614
|
+
});
|
|
2615
|
+
return this;
|
|
2616
|
+
};
|
|
2617
|
+
|
|
2618
|
+
|
|
2619
|
+
NDElement.prototype.transition = function (transitionName) {
|
|
2620
|
+
this.transitionIn(transitionName);
|
|
2621
|
+
this.transitionOut(transitionName);
|
|
2622
|
+
return this;
|
|
2623
|
+
};
|
|
2624
|
+
|
|
2625
|
+
NDElement.prototype.animate = function(animationName) {
|
|
2626
|
+
this.$element.classes.add(animationName);
|
|
2627
|
+
|
|
2628
|
+
waitForVisualEnd(this.$element).then(() => {
|
|
2629
|
+
this.$element.classes.remove(animationName);
|
|
2630
|
+
});
|
|
2631
|
+
|
|
2632
|
+
return this;
|
|
2633
|
+
};
|
|
2634
|
+
|
|
1796
2635
|
String.prototype.handleNdAttribute = function(element, attributeName) {
|
|
1797
2636
|
element.setAttribute(attributeName, this);
|
|
1798
2637
|
};
|
|
@@ -1890,16 +2729,20 @@ var NativeDocument = (function (exports) {
|
|
|
1890
2729
|
processChildren(children, parent) {
|
|
1891
2730
|
if(children === null) return;
|
|
1892
2731
|
{
|
|
1893
|
-
PluginsManager
|
|
2732
|
+
PluginsManager.emit('BeforeProcessChildren', parent);
|
|
1894
2733
|
}
|
|
1895
2734
|
let child = this.getChild(children);
|
|
1896
2735
|
if(child) {
|
|
1897
2736
|
parent.appendChild(child);
|
|
1898
2737
|
}
|
|
1899
2738
|
{
|
|
1900
|
-
PluginsManager
|
|
2739
|
+
PluginsManager.emit('AfterProcessChildren', parent);
|
|
1901
2740
|
}
|
|
1902
2741
|
},
|
|
2742
|
+
async safeRemove(element) {
|
|
2743
|
+
await element.remove();
|
|
2744
|
+
|
|
2745
|
+
},
|
|
1903
2746
|
getChild(child) {
|
|
1904
2747
|
if(child == null) {
|
|
1905
2748
|
return null;
|
|
@@ -2361,10 +3204,10 @@ var NativeDocument = (function (exports) {
|
|
|
2361
3204
|
/**
|
|
2362
3205
|
*
|
|
2363
3206
|
* @param {string} name
|
|
2364
|
-
* @param {?Function} customWrapper
|
|
3207
|
+
* @param {?Function=} customWrapper
|
|
2365
3208
|
* @returns {Function}
|
|
2366
3209
|
*/
|
|
2367
|
-
function HtmlElementWrapper(name, customWrapper) {
|
|
3210
|
+
function HtmlElementWrapper(name, customWrapper = null) {
|
|
2368
3211
|
return createHtmlElement.bind(null, name, customWrapper);
|
|
2369
3212
|
}
|
|
2370
3213
|
|
|
@@ -2418,7 +3261,7 @@ var NativeDocument = (function (exports) {
|
|
|
2418
3261
|
hydrationState[targetType][property] = hydrateFunction;
|
|
2419
3262
|
};
|
|
2420
3263
|
|
|
2421
|
-
const bindAttachMethods =
|
|
3264
|
+
const bindAttachMethods = (node, bindDingData, data) => {
|
|
2422
3265
|
if(!bindDingData.attach) {
|
|
2423
3266
|
return null;
|
|
2424
3267
|
}
|
|
@@ -2654,7 +3497,7 @@ var NativeDocument = (function (exports) {
|
|
|
2654
3497
|
String.prototype.use = function(args) {
|
|
2655
3498
|
const value = this;
|
|
2656
3499
|
|
|
2657
|
-
return Observable.computed(() => {
|
|
3500
|
+
return Observable$1.computed(() => {
|
|
2658
3501
|
return value.replace(/\$\{(.*?)}/g, (match, key) => {
|
|
2659
3502
|
const data = args[key];
|
|
2660
3503
|
if(Validator.isObservable(data)) {
|
|
@@ -2674,7 +3517,7 @@ var NativeDocument = (function (exports) {
|
|
|
2674
3517
|
return value;
|
|
2675
3518
|
}
|
|
2676
3519
|
const [_, id] = value.match(/\{\{#ObItem::\(([0-9]+)\)\}\}/);
|
|
2677
|
-
return Observable.getById(id);
|
|
3520
|
+
return Observable$1.getById(id);
|
|
2678
3521
|
});
|
|
2679
3522
|
};
|
|
2680
3523
|
|
|
@@ -2723,7 +3566,7 @@ var NativeDocument = (function (exports) {
|
|
|
2723
3566
|
const once$1 = (fn) => {
|
|
2724
3567
|
let result = null;
|
|
2725
3568
|
return (...args) => {
|
|
2726
|
-
if(result) {
|
|
3569
|
+
if(result != null) {
|
|
2727
3570
|
return result;
|
|
2728
3571
|
}
|
|
2729
3572
|
result = fn(...args);
|
|
@@ -3149,7 +3992,7 @@ var NativeDocument = (function (exports) {
|
|
|
3149
3992
|
|
|
3150
3993
|
ObservableItem.call(this, target, configs);
|
|
3151
3994
|
{
|
|
3152
|
-
PluginsManager
|
|
3995
|
+
PluginsManager.emit('CreateObservableArray', this);
|
|
3153
3996
|
}
|
|
3154
3997
|
};
|
|
3155
3998
|
|
|
@@ -3367,7 +4210,7 @@ var NativeDocument = (function (exports) {
|
|
|
3367
4210
|
}
|
|
3368
4211
|
}
|
|
3369
4212
|
|
|
3370
|
-
const viewArray = Observable.array();
|
|
4213
|
+
const viewArray = Observable$1.array();
|
|
3371
4214
|
|
|
3372
4215
|
const filters = Object.entries(filterCallbacks);
|
|
3373
4216
|
const updateView = () => {
|
|
@@ -3453,7 +4296,7 @@ var NativeDocument = (function (exports) {
|
|
|
3453
4296
|
* items.push(4); // Triggers update
|
|
3454
4297
|
* items.subscribe((arr) => console.log(arr));
|
|
3455
4298
|
*/
|
|
3456
|
-
Observable.array = function(target = [], configs = null) {
|
|
4299
|
+
Observable$1.array = function(target = [], configs = null) {
|
|
3457
4300
|
return new ObservableArray(target, configs);
|
|
3458
4301
|
};
|
|
3459
4302
|
|
|
@@ -3462,8 +4305,8 @@ var NativeDocument = (function (exports) {
|
|
|
3462
4305
|
* @param {Function} callback
|
|
3463
4306
|
* @returns {Function}
|
|
3464
4307
|
*/
|
|
3465
|
-
Observable.batch = function(callback) {
|
|
3466
|
-
const $observer = Observable(0);
|
|
4308
|
+
Observable$1.batch = function(callback) {
|
|
4309
|
+
const $observer = Observable$1(0);
|
|
3467
4310
|
const batch = function() {
|
|
3468
4311
|
if(Validator.isAsyncFunction(callback)) {
|
|
3469
4312
|
return (callback(...arguments)).then(() => {
|
|
@@ -3477,10 +4320,71 @@ var NativeDocument = (function (exports) {
|
|
|
3477
4320
|
return batch;
|
|
3478
4321
|
};
|
|
3479
4322
|
|
|
3480
|
-
const
|
|
4323
|
+
const ObservableObject = function(target, configs) {
|
|
4324
|
+
ObservableItem.call(this, target);
|
|
4325
|
+
this.$observables = {};
|
|
4326
|
+
this.configs = configs;
|
|
4327
|
+
|
|
4328
|
+
this.$load(target);
|
|
4329
|
+
|
|
4330
|
+
for(const name in target) {
|
|
4331
|
+
if(!Object.hasOwn(this, name)) {
|
|
4332
|
+
Object.defineProperty(this, name, {
|
|
4333
|
+
get: () => this.$observables[name],
|
|
4334
|
+
set: (value) => this.$observables[name].set(value)
|
|
4335
|
+
});
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
|
|
4339
|
+
};
|
|
4340
|
+
|
|
4341
|
+
ObservableObject.prototype = Object.create(ObservableItem.prototype);
|
|
4342
|
+
|
|
4343
|
+
Object.defineProperty(ObservableObject, '$value', {
|
|
4344
|
+
get() {
|
|
4345
|
+
return this.val();
|
|
4346
|
+
},
|
|
4347
|
+
set(value) {
|
|
4348
|
+
this.set(value);
|
|
4349
|
+
}
|
|
4350
|
+
});
|
|
4351
|
+
|
|
4352
|
+
ObservableObject.prototype.__$isObservableObject = true;
|
|
4353
|
+
ObservableObject.prototype.__isProxy__ = true;
|
|
4354
|
+
|
|
4355
|
+
ObservableObject.prototype.$load = function(initialValue) {
|
|
4356
|
+
const configs = this.configs;
|
|
4357
|
+
for(const key in initialValue) {
|
|
4358
|
+
const itemValue = initialValue[key];
|
|
4359
|
+
if(Array.isArray(itemValue)) {
|
|
4360
|
+
if(configs?.deep !== false) {
|
|
4361
|
+
const mappedItemValue = itemValue.map(item => {
|
|
4362
|
+
if(Validator.isJson(item)) {
|
|
4363
|
+
return Observable$1.json(item, configs);
|
|
4364
|
+
}
|
|
4365
|
+
if(Validator.isArray(item)) {
|
|
4366
|
+
return Observable$1.array(item, configs);
|
|
4367
|
+
}
|
|
4368
|
+
return Observable$1(item, configs);
|
|
4369
|
+
});
|
|
4370
|
+
this.$observables[key] = Observable$1.array(mappedItemValue, configs);
|
|
4371
|
+
continue;
|
|
4372
|
+
}
|
|
4373
|
+
this.$observables[key] = Observable$1.array(itemValue, configs);
|
|
4374
|
+
continue;
|
|
4375
|
+
}
|
|
4376
|
+
if(Validator.isObservable(itemValue) || Validator.isProxy(itemValue)) {
|
|
4377
|
+
this.$observables[key] = itemValue;
|
|
4378
|
+
continue;
|
|
4379
|
+
}
|
|
4380
|
+
this.$observables[key] = Observable$1(itemValue, configs);
|
|
4381
|
+
}
|
|
4382
|
+
};
|
|
4383
|
+
|
|
4384
|
+
ObservableObject.prototype.val = function() {
|
|
3481
4385
|
const result = {};
|
|
3482
|
-
for(const key in
|
|
3483
|
-
const dataItem =
|
|
4386
|
+
for(const key in this.$observables) {
|
|
4387
|
+
const dataItem = this.$observables[key];
|
|
3484
4388
|
if(Validator.isObservable(dataItem)) {
|
|
3485
4389
|
let value = dataItem.val();
|
|
3486
4390
|
if(Array.isArray(value)) {
|
|
@@ -3503,9 +4407,10 @@ var NativeDocument = (function (exports) {
|
|
|
3503
4407
|
}
|
|
3504
4408
|
return result;
|
|
3505
4409
|
};
|
|
4410
|
+
ObservableObject.prototype.$val = ObservableObject.prototype.val;
|
|
3506
4411
|
|
|
3507
|
-
|
|
3508
|
-
const item =
|
|
4412
|
+
ObservableObject.prototype.get = function(property) {
|
|
4413
|
+
const item = this.$observables[property];
|
|
3509
4414
|
if(Validator.isObservable(item)) {
|
|
3510
4415
|
return item.val();
|
|
3511
4416
|
}
|
|
@@ -3514,100 +4419,87 @@ var NativeDocument = (function (exports) {
|
|
|
3514
4419
|
}
|
|
3515
4420
|
return item;
|
|
3516
4421
|
};
|
|
4422
|
+
ObservableObject.prototype.$get = ObservableObject.prototype.get;
|
|
3517
4423
|
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
* user.name = 'Jane X'
|
|
3538
|
-
* user.age.subscribe(val => console.log('Age:', val));
|
|
3539
|
-
*/
|
|
3540
|
-
Observable.init = function(initialValue, configs = null) {
|
|
3541
|
-
const data = {};
|
|
3542
|
-
for(const key in initialValue) {
|
|
3543
|
-
const itemValue = initialValue[key];
|
|
3544
|
-
if(Array.isArray(itemValue)) {
|
|
3545
|
-
if(configs?.deep !== false) {
|
|
3546
|
-
const mappedItemValue = itemValue.map(item => {
|
|
3547
|
-
if(Validator.isJson(item)) {
|
|
3548
|
-
return Observable.json(item, configs);
|
|
3549
|
-
}
|
|
3550
|
-
if(Validator.isArray(item)) {
|
|
3551
|
-
return Observable.array(item, configs);
|
|
4424
|
+
ObservableObject.prototype.set = function(newData) {
|
|
4425
|
+
const data = Validator.isProxy(newData) ? newData.$value : newData;
|
|
4426
|
+
const configs = this.configs;
|
|
4427
|
+
|
|
4428
|
+
for(const key in data) {
|
|
4429
|
+
const targetItem = this.$observables[key];
|
|
4430
|
+
const newValueOrigin = newData[key];
|
|
4431
|
+
const newValue = data[key];
|
|
4432
|
+
|
|
4433
|
+
if(Validator.isObservable(targetItem)) {
|
|
4434
|
+
if(!Validator.isArray(newValue)) {
|
|
4435
|
+
targetItem.set(newValue);
|
|
4436
|
+
continue;
|
|
4437
|
+
}
|
|
4438
|
+
const firstElementFromOriginalValue = newValueOrigin.at(0);
|
|
4439
|
+
if(Validator.isObservable(firstElementFromOriginalValue) || Validator.isProxy(firstElementFromOriginalValue)) {
|
|
4440
|
+
const newValues = newValue.map(item => {
|
|
4441
|
+
if(Validator.isProxy(firstElementFromOriginalValue)) {
|
|
4442
|
+
return Observable$1.init(item, configs);
|
|
3552
4443
|
}
|
|
3553
|
-
return Observable(item, configs);
|
|
4444
|
+
return Observable$1(item, configs);
|
|
3554
4445
|
});
|
|
3555
|
-
|
|
4446
|
+
targetItem.set(newValues);
|
|
3556
4447
|
continue;
|
|
3557
4448
|
}
|
|
3558
|
-
|
|
4449
|
+
targetItem.set([...newValue]);
|
|
3559
4450
|
continue;
|
|
3560
4451
|
}
|
|
3561
|
-
if(Validator.
|
|
3562
|
-
|
|
4452
|
+
if(Validator.isProxy(targetItem)) {
|
|
4453
|
+
targetItem.update(newValue);
|
|
3563
4454
|
continue;
|
|
3564
4455
|
}
|
|
3565
|
-
|
|
4456
|
+
this[key] = newValue;
|
|
3566
4457
|
}
|
|
4458
|
+
};
|
|
4459
|
+
ObservableObject.prototype.$set = ObservableObject.prototype.set;
|
|
4460
|
+
ObservableObject.prototype.$updateWith = ObservableObject.prototype.set;
|
|
3567
4461
|
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
}
|
|
3573
|
-
};
|
|
3574
|
-
|
|
3575
|
-
const $val = () => ObservableObjectValue(data);
|
|
4462
|
+
ObservableObject.prototype.observables = function() {
|
|
4463
|
+
return Object.values(this.$observables);
|
|
4464
|
+
};
|
|
4465
|
+
ObservableObject.prototype.$observables = ObservableObject.prototype.observables;
|
|
3576
4466
|
|
|
3577
|
-
|
|
4467
|
+
ObservableObject.prototype.keys = function() {
|
|
4468
|
+
return Object.keys(this.$observables);
|
|
4469
|
+
};
|
|
4470
|
+
ObservableObject.prototype.$keys = ObservableObject.prototype.keys;
|
|
4471
|
+
ObservableObject.prototype.clone = function() {
|
|
4472
|
+
return Observable$1.init(this.val(), this.configs);
|
|
4473
|
+
};
|
|
4474
|
+
ObservableObject.prototype.$clone = ObservableObject.prototype.clone;
|
|
4475
|
+
ObservableObject.prototype.reset = function() {
|
|
4476
|
+
for(const key in this.$observables) {
|
|
4477
|
+
this.$observables[key].reset();
|
|
4478
|
+
}
|
|
4479
|
+
};
|
|
4480
|
+
ObservableObject.prototype.originalSubscribe = ObservableObject.prototype.subscribe;
|
|
4481
|
+
ObservableObject.prototype.subscribe = function(callback) {
|
|
4482
|
+
const observables = this.observables();
|
|
4483
|
+
const updatedValue = nextTick(() => {
|
|
4484
|
+
this.$currentValue = this.val();
|
|
4485
|
+
this.trigger();
|
|
4486
|
+
});
|
|
3578
4487
|
|
|
3579
|
-
|
|
3580
|
-
Observable.update(proxy, values);
|
|
3581
|
-
};
|
|
4488
|
+
this.originalSubscribe(callback);
|
|
3582
4489
|
|
|
3583
|
-
|
|
4490
|
+
for(let i = 0, length = observables.length; i < length; i++) {
|
|
4491
|
+
const observable = observables[i];
|
|
4492
|
+
observable.subscribe(updatedValue);
|
|
4493
|
+
}
|
|
4494
|
+
};
|
|
4495
|
+
ObservableObject.prototype.configs = function() {
|
|
4496
|
+
return this.configs;
|
|
4497
|
+
};
|
|
3584
4498
|
|
|
3585
|
-
|
|
3586
|
-
get(target, property) {
|
|
3587
|
-
if(property === '__isProxy__') { return true; }
|
|
3588
|
-
if(property === '$value') { return $val() }
|
|
3589
|
-
if(property === 'get' || property === '$get') { return $get; }
|
|
3590
|
-
if(property === 'val' || property === '$val') { return $val; }
|
|
3591
|
-
if(property === 'set' || property === '$set' || property === '$updateWith') { return $updateWith; }
|
|
3592
|
-
if(property === 'observables' || property === '$observables') { return Object.values(target); }
|
|
3593
|
-
if(property === 'keys'|| property === '$keys') { return Object.keys(initialValue); }
|
|
3594
|
-
if(property === 'clone' || property === '$clone') { return $clone; }
|
|
3595
|
-
if(property === 'reset') { return $reset; }
|
|
3596
|
-
if(property === 'configs') { return configs; }
|
|
3597
|
-
return target[property];
|
|
3598
|
-
},
|
|
3599
|
-
set(target, prop, newValue) {
|
|
3600
|
-
if(target[prop] !== undefined) {
|
|
3601
|
-
Validator.isObservable(newValue)
|
|
3602
|
-
? target[prop].set(newValue.val())
|
|
3603
|
-
: target[prop].set(newValue);
|
|
3604
|
-
return true;
|
|
3605
|
-
}
|
|
3606
|
-
return true;
|
|
3607
|
-
}
|
|
3608
|
-
});
|
|
4499
|
+
ObservableObject.prototype.update = ObservableObject.prototype.set;
|
|
3609
4500
|
|
|
3610
|
-
|
|
4501
|
+
Observable$1.init = function(initialValue, configs = null) {
|
|
4502
|
+
return new ObservableObject(initialValue, configs)
|
|
3611
4503
|
};
|
|
3612
4504
|
|
|
3613
4505
|
/**
|
|
@@ -3615,8 +4507,8 @@ var NativeDocument = (function (exports) {
|
|
|
3615
4507
|
* @param {any[]} data
|
|
3616
4508
|
* @return Proxy[]
|
|
3617
4509
|
*/
|
|
3618
|
-
Observable.arrayOfObject = function(data) {
|
|
3619
|
-
return data.map(item => Observable.object(item));
|
|
4510
|
+
Observable$1.arrayOfObject = function(data) {
|
|
4511
|
+
return data.map(item => Observable$1.object(item));
|
|
3620
4512
|
};
|
|
3621
4513
|
|
|
3622
4514
|
/**
|
|
@@ -3624,7 +4516,7 @@ var NativeDocument = (function (exports) {
|
|
|
3624
4516
|
* @param {ObservableItem|Object<ObservableItem>} data
|
|
3625
4517
|
* @returns {{}|*|null}
|
|
3626
4518
|
*/
|
|
3627
|
-
Observable.value = function(data) {
|
|
4519
|
+
Observable$1.value = function(data) {
|
|
3628
4520
|
if(Validator.isObservable(data)) {
|
|
3629
4521
|
return data.val();
|
|
3630
4522
|
}
|
|
@@ -3635,52 +4527,15 @@ var NativeDocument = (function (exports) {
|
|
|
3635
4527
|
const result = [];
|
|
3636
4528
|
for(let i = 0, length = data.length; i < length; i++) {
|
|
3637
4529
|
const item = data[i];
|
|
3638
|
-
result.push(Observable.value(item));
|
|
4530
|
+
result.push(Observable$1.value(item));
|
|
3639
4531
|
}
|
|
3640
4532
|
return result;
|
|
3641
4533
|
}
|
|
3642
4534
|
return data;
|
|
3643
4535
|
};
|
|
3644
4536
|
|
|
3645
|
-
|
|
3646
|
-
Observable.
|
|
3647
|
-
const data = Validator.isProxy(newData) ? newData.$value : newData;
|
|
3648
|
-
const configs = $target.configs;
|
|
3649
|
-
|
|
3650
|
-
for(const key in data) {
|
|
3651
|
-
const targetItem = $target[key];
|
|
3652
|
-
const newValueOrigin = newData[key];
|
|
3653
|
-
const newValue = data[key];
|
|
3654
|
-
|
|
3655
|
-
if(Validator.isObservable(targetItem)) {
|
|
3656
|
-
if(Validator.isArray(newValue)) {
|
|
3657
|
-
const firstElementFromOriginalValue = newValueOrigin.at(0);
|
|
3658
|
-
if(Validator.isObservable(firstElementFromOriginalValue) || Validator.isProxy(firstElementFromOriginalValue)) {
|
|
3659
|
-
const newValues = newValue.map(item => {
|
|
3660
|
-
if(Validator.isProxy(firstElementFromOriginalValue)) {
|
|
3661
|
-
return Observable.init(item, configs);
|
|
3662
|
-
}
|
|
3663
|
-
return Observable(item, configs);
|
|
3664
|
-
});
|
|
3665
|
-
targetItem.set(newValues);
|
|
3666
|
-
continue;
|
|
3667
|
-
}
|
|
3668
|
-
targetItem.set([...newValue]);
|
|
3669
|
-
continue;
|
|
3670
|
-
}
|
|
3671
|
-
targetItem.set(newValue);
|
|
3672
|
-
continue;
|
|
3673
|
-
}
|
|
3674
|
-
if(Validator.isProxy(targetItem)) {
|
|
3675
|
-
Observable.update(targetItem, newValue);
|
|
3676
|
-
continue;
|
|
3677
|
-
}
|
|
3678
|
-
$target[key] = newValue;
|
|
3679
|
-
}
|
|
3680
|
-
};
|
|
3681
|
-
|
|
3682
|
-
Observable.object = Observable.init;
|
|
3683
|
-
Observable.json = Observable.init;
|
|
4537
|
+
Observable$1.object = Observable$1.init;
|
|
4538
|
+
Observable$1.json = Observable$1.init;
|
|
3684
4539
|
|
|
3685
4540
|
/**
|
|
3686
4541
|
* Creates a computed observable that automatically updates when its dependencies change.
|
|
@@ -3701,12 +4556,12 @@ var NativeDocument = (function (exports) {
|
|
|
3701
4556
|
* const batch = Observable.batch(() => { ... });
|
|
3702
4557
|
* const computed = Observable.computed(() => { ... }, batch);
|
|
3703
4558
|
*/
|
|
3704
|
-
Observable.computed = function(callback, dependencies = []) {
|
|
4559
|
+
Observable$1.computed = function(callback, dependencies = []) {
|
|
3705
4560
|
const initialValue = callback();
|
|
3706
4561
|
const observable = new ObservableItem(initialValue);
|
|
3707
4562
|
const updatedValue = nextTick(() => observable.set(callback()));
|
|
3708
4563
|
{
|
|
3709
|
-
PluginsManager
|
|
4564
|
+
PluginsManager.emit('CreateObservableComputed', observable, dependencies);
|
|
3710
4565
|
}
|
|
3711
4566
|
|
|
3712
4567
|
if(Validator.isFunction(dependencies)) {
|
|
@@ -3730,85 +4585,12 @@ var NativeDocument = (function (exports) {
|
|
|
3730
4585
|
return observable;
|
|
3731
4586
|
};
|
|
3732
4587
|
|
|
3733
|
-
const Store = (function() {
|
|
3734
|
-
|
|
3735
|
-
const $stores = new Map();
|
|
3736
|
-
|
|
3737
|
-
return {
|
|
3738
|
-
/**
|
|
3739
|
-
* Create a new state follower and return it.
|
|
3740
|
-
* @param {string} name
|
|
3741
|
-
* @returns {ObservableItem}
|
|
3742
|
-
*/
|
|
3743
|
-
use(name) {
|
|
3744
|
-
const {observer: originalObserver, subscribers } = $stores.get(name);
|
|
3745
|
-
const observerFollower = Observable(originalObserver.val());
|
|
3746
|
-
const unSubscriber = originalObserver.subscribe(value => observerFollower.set(value));
|
|
3747
|
-
const updaterUnsubscriber = observerFollower.subscribe(value => originalObserver.set(value));
|
|
3748
|
-
observerFollower.destroy = () => {
|
|
3749
|
-
unSubscriber();
|
|
3750
|
-
updaterUnsubscriber();
|
|
3751
|
-
observerFollower.cleanup();
|
|
3752
|
-
};
|
|
3753
|
-
subscribers.add(observerFollower);
|
|
3754
|
-
|
|
3755
|
-
return observerFollower;
|
|
3756
|
-
},
|
|
3757
|
-
/**
|
|
3758
|
-
* @param {string} name
|
|
3759
|
-
* @returns {ObservableItem}
|
|
3760
|
-
*/
|
|
3761
|
-
follow(name) {
|
|
3762
|
-
return this.use(name);
|
|
3763
|
-
},
|
|
3764
|
-
/**
|
|
3765
|
-
* Create a new state and return the observer.
|
|
3766
|
-
* @param {string} name
|
|
3767
|
-
* @param {*} value
|
|
3768
|
-
* @returns {ObservableItem}
|
|
3769
|
-
*/
|
|
3770
|
-
create(name, value) {
|
|
3771
|
-
const observer = Observable(value);
|
|
3772
|
-
$stores.set(name, { observer, subscribers: new Set()});
|
|
3773
|
-
return observer;
|
|
3774
|
-
},
|
|
3775
|
-
/**
|
|
3776
|
-
* Get the observer for a state.
|
|
3777
|
-
* @param {string} name
|
|
3778
|
-
* @returns {null|ObservableItem}
|
|
3779
|
-
*/
|
|
3780
|
-
get(name) {
|
|
3781
|
-
const item = $stores.get(name);
|
|
3782
|
-
return item ? item.observer : null;
|
|
3783
|
-
},
|
|
3784
|
-
/**
|
|
3785
|
-
*
|
|
3786
|
-
* @param {string} name
|
|
3787
|
-
* @returns {{observer: ObservableItem, subscribers: Set}}
|
|
3788
|
-
*/
|
|
3789
|
-
getWithSubscribers(name) {
|
|
3790
|
-
return $stores.get(name);
|
|
3791
|
-
},
|
|
3792
|
-
/**
|
|
3793
|
-
* Delete a state.
|
|
3794
|
-
* @param {string} name
|
|
3795
|
-
*/
|
|
3796
|
-
delete(name) {
|
|
3797
|
-
const item = $stores.get(name);
|
|
3798
|
-
if(!item) return;
|
|
3799
|
-
item.observer.cleanup();
|
|
3800
|
-
item.subscribers.forEach(follower => follower.destroy());
|
|
3801
|
-
item.observer.clear();
|
|
3802
|
-
}
|
|
3803
|
-
};
|
|
3804
|
-
}());
|
|
3805
|
-
|
|
3806
4588
|
/**
|
|
3807
4589
|
* Renders a list of items from an observable array or object, automatically updating when data changes.
|
|
3808
4590
|
* Efficiently manages DOM updates by tracking items with keys.
|
|
3809
4591
|
*
|
|
3810
4592
|
* @param {ObservableItem<Array|Object>} data - Observable containing array or object to iterate over
|
|
3811
|
-
* @param {
|
|
4593
|
+
* @param {(item: *, index: null|ObservableItem) => NdChild} callback - Function that renders each item (item, index) => ValidChild
|
|
3812
4594
|
* @param {string|Function} [key] - Property name or function to generate unique keys for items
|
|
3813
4595
|
* @param {Object} [options={}] - Configuration options
|
|
3814
4596
|
* @param {boolean} [options.shouldKeepItemsInCache=false] - Whether to cache rendered items
|
|
@@ -3847,7 +4629,7 @@ var NativeDocument = (function (exports) {
|
|
|
3847
4629
|
}
|
|
3848
4630
|
const child = cacheItem.child?.deref();
|
|
3849
4631
|
if(parent && child) {
|
|
3850
|
-
|
|
4632
|
+
child.remove();
|
|
3851
4633
|
}
|
|
3852
4634
|
cacheItem.indexObserver?.cleanup();
|
|
3853
4635
|
cacheItem.child = null;
|
|
@@ -3871,14 +4653,14 @@ var NativeDocument = (function (exports) {
|
|
|
3871
4653
|
}
|
|
3872
4654
|
|
|
3873
4655
|
try {
|
|
3874
|
-
const indexObserver = callback.length >= 2 ? Observable(indexKey) : null;
|
|
4656
|
+
const indexObserver = callback.length >= 2 ? Observable$1(indexKey) : null;
|
|
3875
4657
|
let child = ElementCreator.getChild(callback(item, indexObserver));
|
|
3876
4658
|
if(!child) {
|
|
3877
4659
|
throw new NativeDocumentError("ForEach child can't be null or undefined!");
|
|
3878
4660
|
}
|
|
3879
4661
|
cache.set(keyId, { keyId, isNew: true, child: new WeakRef(child), indexObserver});
|
|
3880
4662
|
} catch (e) {
|
|
3881
|
-
DebugManager
|
|
4663
|
+
DebugManager.error('ForEach', `Error creating element for key ${keyId}` , e);
|
|
3882
4664
|
throw e;
|
|
3883
4665
|
}
|
|
3884
4666
|
return keyId;
|
|
@@ -3965,7 +4747,7 @@ var NativeDocument = (function (exports) {
|
|
|
3965
4747
|
* Provides index observables and handles array mutations efficiently.
|
|
3966
4748
|
*
|
|
3967
4749
|
* @param {ObservableArray} data - ObservableArray to iterate over
|
|
3968
|
-
* @param {
|
|
4750
|
+
* @param {(item: *, index: null|ObservableItem) => NdChild} callback - Function that renders each item (item, indexObservable) => ValidChild
|
|
3969
4751
|
* @param {Object} [configs={}] - Configuration options
|
|
3970
4752
|
* @param {boolean} [configs.shouldKeepItemsInCache] - Whether to cache rendered items
|
|
3971
4753
|
* @param {boolean} [configs.isParentUniqueChild] - When it's the only child of the parent
|
|
@@ -4053,7 +4835,7 @@ var NativeDocument = (function (exports) {
|
|
|
4053
4835
|
cache.delete(item);
|
|
4054
4836
|
}
|
|
4055
4837
|
|
|
4056
|
-
const indexObserver = isIndexRequired ? Observable(indexKey) : null;
|
|
4838
|
+
const indexObserver = isIndexRequired ? Observable$1(indexKey) : null;
|
|
4057
4839
|
let child = ElementCreator.getChild(callback(item, indexObserver));
|
|
4058
4840
|
if(child) {
|
|
4059
4841
|
cache.set(item, {
|
|
@@ -4237,7 +5019,7 @@ var NativeDocument = (function (exports) {
|
|
|
4237
5019
|
* The element is mounted/unmounted from the DOM as the condition changes.
|
|
4238
5020
|
*
|
|
4239
5021
|
* @param {ObservableItem<boolean>|ObservableChecker<boolean>|ObservableWhen} condition - Observable condition to watch
|
|
4240
|
-
* @param {
|
|
5022
|
+
* @param {NdChild|(() => NdChild)} child - Element or content to show/hide
|
|
4241
5023
|
* @param {Object} [options={}] - Configuration options
|
|
4242
5024
|
* @param {string|null} [options.comment=null] - Comment for debugging
|
|
4243
5025
|
* @param {boolean} [options.shouldKeepInCache=true] - Whether to cache the element when hidden
|
|
@@ -4248,7 +5030,7 @@ var NativeDocument = (function (exports) {
|
|
|
4248
5030
|
*/
|
|
4249
5031
|
const ShowIf = function(condition, child, { comment = null, shouldKeepInCache = true} = {}) {
|
|
4250
5032
|
if(!(Validator.isObservable(condition)) && !Validator.isObservableWhenResult(condition)) {
|
|
4251
|
-
return DebugManager
|
|
5033
|
+
return DebugManager.warn('ShowIf', "ShowIf : condition must be an Observable / "+comment, condition);
|
|
4252
5034
|
}
|
|
4253
5035
|
const element = Anchor('Show if : '+(comment || ''));
|
|
4254
5036
|
|
|
@@ -4285,7 +5067,7 @@ var NativeDocument = (function (exports) {
|
|
|
4285
5067
|
* Inverse of ShowIf - element is shown when condition is false.
|
|
4286
5068
|
*
|
|
4287
5069
|
* @param {ObservableItem<boolean>|ObservableChecker<boolean>} condition - Observable condition to watch
|
|
4288
|
-
* @param {
|
|
5070
|
+
* @param {NdChild|(() => NdChild)} child - Element or content to show/hide
|
|
4289
5071
|
* @param {Object} [configs] - Configuration options
|
|
4290
5072
|
* @param {string|null} [configs.comment] - Comment for debugging
|
|
4291
5073
|
* @param {boolean} [configs.shouldKeepInCache] - Whether to cache element when hidden
|
|
@@ -4295,7 +5077,7 @@ var NativeDocument = (function (exports) {
|
|
|
4295
5077
|
* HideIf(hasError, Div({}, 'Content'));
|
|
4296
5078
|
*/
|
|
4297
5079
|
const HideIf = function(condition, child, configs) {
|
|
4298
|
-
const hideCondition = Observable(!condition.val());
|
|
5080
|
+
const hideCondition = Observable$1(!condition.val());
|
|
4299
5081
|
condition.subscribe(value => hideCondition.set(!value));
|
|
4300
5082
|
|
|
4301
5083
|
return ShowIf(hideCondition, child, configs);
|
|
@@ -4306,7 +5088,7 @@ var NativeDocument = (function (exports) {
|
|
|
4306
5088
|
* Same as ShowIf - element is shown when condition is true.
|
|
4307
5089
|
*
|
|
4308
5090
|
* @param {ObservableItem<boolean>|ObservableChecker<boolean>|ObservableWhen} condition - Observable condition to watch
|
|
4309
|
-
* @param {
|
|
5091
|
+
* @param {NdChild|(() => NdChild)} child - Element or content to show/hide
|
|
4310
5092
|
* @param {Object} [configs] - Configuration options
|
|
4311
5093
|
* @param {string|null} [configs.comment] - Comment for debugging
|
|
4312
5094
|
* @param {boolean} [configs.shouldKeepInCache] - Whether to cache element when hidden
|
|
@@ -4322,13 +5104,13 @@ var NativeDocument = (function (exports) {
|
|
|
4322
5104
|
*
|
|
4323
5105
|
* @overload
|
|
4324
5106
|
* @param {ObservableWhen} observerWhenResult - Result from observable.when(value)
|
|
4325
|
-
* @param {
|
|
5107
|
+
* @param {NdChild|(() => NdChild)} view - Content to show when condition matches
|
|
4326
5108
|
* @returns {AnchorDocumentFragment}
|
|
4327
5109
|
*
|
|
4328
5110
|
* @overload
|
|
4329
5111
|
* @param {ObservableItem} observer - Observable to watch
|
|
4330
5112
|
* @param {*} target - Value to match
|
|
4331
|
-
* @param {
|
|
5113
|
+
* @param {NdChild|(() => NdChild)} view - Content to show when observable equals target
|
|
4332
5114
|
* @returns {AnchorDocumentFragment}
|
|
4333
5115
|
*
|
|
4334
5116
|
* @example
|
|
@@ -4372,7 +5154,7 @@ var NativeDocument = (function (exports) {
|
|
|
4372
5154
|
* Like a switch statement for UI - shows the content corresponding to current value.
|
|
4373
5155
|
*
|
|
4374
5156
|
* @param {ObservableItem|ObservableChecker} $condition - Observable to watch
|
|
4375
|
-
* @param {Object<string|number,
|
|
5157
|
+
* @param {Object<string|number, NdChild|(() => NdChild)>} values - Map of values to their corresponding content
|
|
4376
5158
|
* @param {boolean} [shouldKeepInCache=true] - Whether to cache rendered views
|
|
4377
5159
|
* @returns {AnchorDocumentFragment & {add: Function, remove: Function}} Fragment with dynamic methods
|
|
4378
5160
|
* @example
|
|
@@ -4501,41 +5283,202 @@ var NativeDocument = (function (exports) {
|
|
|
4501
5283
|
}
|
|
4502
5284
|
};
|
|
4503
5285
|
|
|
5286
|
+
/**
|
|
5287
|
+
* Creates a `<div>` element.
|
|
5288
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLDivElement}
|
|
5289
|
+
*/
|
|
4504
5290
|
const Div = HtmlElementWrapper('div');
|
|
5291
|
+
|
|
5292
|
+
/**
|
|
5293
|
+
* Creates a `<span>` element.
|
|
5294
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLSpanElement}
|
|
5295
|
+
*/
|
|
4505
5296
|
const Span = HtmlElementWrapper('span');
|
|
5297
|
+
|
|
5298
|
+
/**
|
|
5299
|
+
* Creates a `<label>` element.
|
|
5300
|
+
* @type {function(LabelAttributes=, NdChild|NdChild[]=): HTMLLabelElement}
|
|
5301
|
+
*/
|
|
4506
5302
|
const Label = HtmlElementWrapper('label');
|
|
5303
|
+
|
|
5304
|
+
/**
|
|
5305
|
+
* Creates a `<p>` element.
|
|
5306
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLParagraphElement}
|
|
5307
|
+
*/
|
|
4507
5308
|
const P = HtmlElementWrapper('p');
|
|
5309
|
+
|
|
5310
|
+
/**
|
|
5311
|
+
* Alias for {@link P}.
|
|
5312
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLParagraphElement}
|
|
5313
|
+
*/
|
|
4508
5314
|
const Paragraph = P;
|
|
5315
|
+
|
|
5316
|
+
/**
|
|
5317
|
+
* Creates a `<strong>` element.
|
|
5318
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5319
|
+
*/
|
|
4509
5320
|
const Strong = HtmlElementWrapper('strong');
|
|
5321
|
+
|
|
5322
|
+
/**
|
|
5323
|
+
* Creates a `<h1>` element.
|
|
5324
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLHeadingElement}
|
|
5325
|
+
*/
|
|
4510
5326
|
const H1 = HtmlElementWrapper('h1');
|
|
5327
|
+
|
|
5328
|
+
/**
|
|
5329
|
+
* Creates a `<h2>` element.
|
|
5330
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLHeadingElement}
|
|
5331
|
+
*/
|
|
4511
5332
|
const H2 = HtmlElementWrapper('h2');
|
|
5333
|
+
|
|
5334
|
+
/**
|
|
5335
|
+
* Creates a `<h3>` element.
|
|
5336
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLHeadingElement}
|
|
5337
|
+
*/
|
|
4512
5338
|
const H3 = HtmlElementWrapper('h3');
|
|
5339
|
+
|
|
5340
|
+
/**
|
|
5341
|
+
* Creates a `<h4>` element.
|
|
5342
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLHeadingElement}
|
|
5343
|
+
*/
|
|
4513
5344
|
const H4 = HtmlElementWrapper('h4');
|
|
5345
|
+
|
|
5346
|
+
/**
|
|
5347
|
+
* Creates a `<h5>` element.
|
|
5348
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLHeadingElement}
|
|
5349
|
+
*/
|
|
4514
5350
|
const H5 = HtmlElementWrapper('h5');
|
|
5351
|
+
|
|
5352
|
+
/**
|
|
5353
|
+
* Creates a `<h6>` element.
|
|
5354
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLHeadingElement}
|
|
5355
|
+
*/
|
|
4515
5356
|
const H6 = HtmlElementWrapper('h6');
|
|
4516
5357
|
|
|
5358
|
+
/**
|
|
5359
|
+
* Creates a `<br>` element.
|
|
5360
|
+
* @type {function(GlobalAttributes=): HTMLBRElement}
|
|
5361
|
+
*/
|
|
4517
5362
|
const Br = HtmlElementWrapper('br');
|
|
4518
5363
|
|
|
5364
|
+
/**
|
|
5365
|
+
* Creates an `<a>` element.
|
|
5366
|
+
* @type {function(AnchorAttributes=, NdChild|NdChild[]=): HTMLAnchorElement}
|
|
5367
|
+
*/
|
|
4519
5368
|
const Link$1 = HtmlElementWrapper('a');
|
|
5369
|
+
|
|
5370
|
+
/**
|
|
5371
|
+
* Creates a `<pre>` element.
|
|
5372
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLPreElement}
|
|
5373
|
+
*/
|
|
4520
5374
|
const Pre = HtmlElementWrapper('pre');
|
|
5375
|
+
|
|
5376
|
+
/**
|
|
5377
|
+
* Creates a `<code>` element.
|
|
5378
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5379
|
+
*/
|
|
4521
5380
|
const Code = HtmlElementWrapper('code');
|
|
5381
|
+
|
|
5382
|
+
/**
|
|
5383
|
+
* Creates a `<blockquote>` element.
|
|
5384
|
+
* @type {function(GlobalAttributes & { cite?: string }=, NdChild|NdChild[]=): HTMLQuoteElement}
|
|
5385
|
+
*/
|
|
4522
5386
|
const Blockquote = HtmlElementWrapper('blockquote');
|
|
5387
|
+
|
|
5388
|
+
/**
|
|
5389
|
+
* Creates an `<hr>` element.
|
|
5390
|
+
* @type {function(GlobalAttributes=): HTMLHRElement}
|
|
5391
|
+
*/
|
|
4523
5392
|
const Hr = HtmlElementWrapper('hr');
|
|
5393
|
+
|
|
5394
|
+
/**
|
|
5395
|
+
* Creates an `<em>` element.
|
|
5396
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5397
|
+
*/
|
|
4524
5398
|
const Em = HtmlElementWrapper('em');
|
|
5399
|
+
|
|
5400
|
+
/**
|
|
5401
|
+
* Creates a `<small>` element.
|
|
5402
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5403
|
+
*/
|
|
4525
5404
|
const Small = HtmlElementWrapper('small');
|
|
5405
|
+
|
|
5406
|
+
/**
|
|
5407
|
+
* Creates a `<mark>` element.
|
|
5408
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5409
|
+
*/
|
|
4526
5410
|
const Mark = HtmlElementWrapper('mark');
|
|
5411
|
+
|
|
5412
|
+
/**
|
|
5413
|
+
* Creates a `<del>` element.
|
|
5414
|
+
* @type {function(ModAttributes=, NdChild|NdChild[]=): HTMLModElement}
|
|
5415
|
+
*/
|
|
4527
5416
|
const Del = HtmlElementWrapper('del');
|
|
5417
|
+
|
|
5418
|
+
/**
|
|
5419
|
+
* Creates an `<ins>` element.
|
|
5420
|
+
* @type {function(ModAttributes=, NdChild|NdChild[]=): HTMLModElement}
|
|
5421
|
+
*/
|
|
4528
5422
|
const Ins = HtmlElementWrapper('ins');
|
|
5423
|
+
|
|
5424
|
+
/**
|
|
5425
|
+
* Creates a `<sub>` element.
|
|
5426
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5427
|
+
*/
|
|
4529
5428
|
const Sub = HtmlElementWrapper('sub');
|
|
5429
|
+
|
|
5430
|
+
/**
|
|
5431
|
+
* Creates a `<sup>` element.
|
|
5432
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5433
|
+
*/
|
|
4530
5434
|
const Sup = HtmlElementWrapper('sup');
|
|
5435
|
+
|
|
5436
|
+
/**
|
|
5437
|
+
* Creates an `<abbr>` element.
|
|
5438
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5439
|
+
*/
|
|
4531
5440
|
const Abbr = HtmlElementWrapper('abbr');
|
|
5441
|
+
|
|
5442
|
+
/**
|
|
5443
|
+
* Creates a `<cite>` element.
|
|
5444
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5445
|
+
*/
|
|
4532
5446
|
const Cite = HtmlElementWrapper('cite');
|
|
5447
|
+
|
|
5448
|
+
/**
|
|
5449
|
+
* Creates a `<q>` element.
|
|
5450
|
+
* @type {function(GlobalAttributes & { cite?: string }=, NdChild|NdChild[]=): HTMLQuoteElement}
|
|
5451
|
+
*/
|
|
4533
5452
|
const Quote = HtmlElementWrapper('q');
|
|
4534
5453
|
|
|
5454
|
+
/**
|
|
5455
|
+
* Creates a `<dl>` element.
|
|
5456
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLDListElement}
|
|
5457
|
+
*/
|
|
4535
5458
|
const Dl = HtmlElementWrapper('dl');
|
|
5459
|
+
|
|
5460
|
+
/**
|
|
5461
|
+
* Creates a `<dt>` element.
|
|
5462
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5463
|
+
*/
|
|
4536
5464
|
const Dt = HtmlElementWrapper('dt');
|
|
5465
|
+
|
|
5466
|
+
/**
|
|
5467
|
+
* Creates a `<dd>` element.
|
|
5468
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5469
|
+
*/
|
|
4537
5470
|
const Dd = HtmlElementWrapper('dd');
|
|
4538
5471
|
|
|
5472
|
+
/**
|
|
5473
|
+
* Creates a `<form>` element.
|
|
5474
|
+
* Extended with fluent methods: `.submit()`, `.post()`, `.get()`, `.multipartFormData()`.
|
|
5475
|
+
* @type {function(FormAttributes=, NdChild|NdChild[]=): HTMLFormElement & {
|
|
5476
|
+
* submit: (actionOrFn: string | ((e: SubmitEvent) => void)) => HTMLFormElement,
|
|
5477
|
+
* post: (action: string) => HTMLFormElement,
|
|
5478
|
+
* get: (action: string) => HTMLFormElement,
|
|
5479
|
+
* multipartFormData: () => HTMLFormElement,
|
|
5480
|
+
* }}
|
|
5481
|
+
*/
|
|
4539
5482
|
const Form = HtmlElementWrapper('form', function(el) {
|
|
4540
5483
|
|
|
4541
5484
|
el.submit = function(action) {
|
|
@@ -4565,68 +5508,298 @@ var NativeDocument = (function (exports) {
|
|
|
4565
5508
|
return el;
|
|
4566
5509
|
});
|
|
4567
5510
|
|
|
5511
|
+
/**
|
|
5512
|
+
* Creates an `<input>` element.
|
|
5513
|
+
* @type {function(InputAttributes=): HTMLInputElement}
|
|
5514
|
+
*/
|
|
4568
5515
|
const Input = HtmlElementWrapper('input');
|
|
4569
5516
|
|
|
5517
|
+
/**
|
|
5518
|
+
* Creates a `<textarea>` element.
|
|
5519
|
+
* @type {function(TextAreaAttributes=, NdChild|NdChild[]=): HTMLTextAreaElement}
|
|
5520
|
+
*/
|
|
4570
5521
|
const TextArea = HtmlElementWrapper('textarea');
|
|
5522
|
+
|
|
5523
|
+
/**
|
|
5524
|
+
* Alias for {@link TextArea}.
|
|
5525
|
+
* @type {function(TextAreaAttributes=, NdChild|NdChild[]=): HTMLTextAreaElement}
|
|
5526
|
+
*/
|
|
4571
5527
|
const TextInput = TextArea;
|
|
4572
5528
|
|
|
5529
|
+
/**
|
|
5530
|
+
* Creates a `<select>` element.
|
|
5531
|
+
* @type {function(SelectAttributes=, NdChild|NdChild[]=): HTMLSelectElement}
|
|
5532
|
+
*/
|
|
4573
5533
|
const Select = HtmlElementWrapper('select');
|
|
4574
|
-
|
|
5534
|
+
|
|
5535
|
+
/**
|
|
5536
|
+
* Creates a `<fieldset>` element.
|
|
5537
|
+
* @type {function(GlobalAttributes & { disabled?: Observable<boolean>|boolean }=, NdChild|NdChild[]=): HTMLFieldSetElement}
|
|
5538
|
+
*/
|
|
5539
|
+
const FieldSet = HtmlElementWrapper('fieldset');
|
|
5540
|
+
|
|
5541
|
+
/**
|
|
5542
|
+
* Creates an `<option>` element.
|
|
5543
|
+
* @type {function(OptionAttributes=, NdChild|NdChild[]=): HTMLOptionElement}
|
|
5544
|
+
*/
|
|
4575
5545
|
const Option = HtmlElementWrapper('option');
|
|
5546
|
+
|
|
5547
|
+
/**
|
|
5548
|
+
* Creates a `<legend>` element.
|
|
5549
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLLegendElement}
|
|
5550
|
+
*/
|
|
4576
5551
|
const Legend = HtmlElementWrapper('legend');
|
|
5552
|
+
|
|
5553
|
+
/**
|
|
5554
|
+
* Creates a `<datalist>` element.
|
|
5555
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLDataListElement}
|
|
5556
|
+
*/
|
|
4577
5557
|
const Datalist = HtmlElementWrapper('datalist');
|
|
5558
|
+
|
|
5559
|
+
/**
|
|
5560
|
+
* Creates an `<output>` element.
|
|
5561
|
+
* @type {function(OutputAttributes=, NdChild|NdChild[]=): HTMLOutputElement}
|
|
5562
|
+
*/
|
|
4578
5563
|
const Output = HtmlElementWrapper('output');
|
|
5564
|
+
|
|
5565
|
+
/**
|
|
5566
|
+
* Creates a `<progress>` element.
|
|
5567
|
+
* @type {function(ProgressAttributes=, NdChild|NdChild[]=): HTMLProgressElement}
|
|
5568
|
+
*/
|
|
4579
5569
|
const Progress = HtmlElementWrapper('progress');
|
|
5570
|
+
|
|
5571
|
+
/**
|
|
5572
|
+
* Creates a `<meter>` element.
|
|
5573
|
+
* @type {function(MeterAttributes=, NdChild|NdChild[]=): HTMLMeterElement}
|
|
5574
|
+
*/
|
|
4580
5575
|
const Meter = HtmlElementWrapper('meter');
|
|
4581
5576
|
|
|
5577
|
+
/**
|
|
5578
|
+
* Creates an `<input readonly>` element.
|
|
5579
|
+
* @param {Omit<InputAttributes, 'type'|'readonly'|'readOnly'>} [attributes]
|
|
5580
|
+
* @returns {HTMLInputElement}
|
|
5581
|
+
*/
|
|
4582
5582
|
const ReadonlyInput = (attributes) => Input({ readonly: true, ...attributes });
|
|
4583
|
-
|
|
5583
|
+
|
|
5584
|
+
/**
|
|
5585
|
+
* Creates an `<input type="hidden">` element.
|
|
5586
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5587
|
+
* @returns {HTMLInputElement}
|
|
5588
|
+
*/
|
|
5589
|
+
const HiddenInput = (attributes) => Input({ type: 'hidden', ...attributes });
|
|
5590
|
+
|
|
5591
|
+
/**
|
|
5592
|
+
* Creates an `<input type="file">` element.
|
|
5593
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5594
|
+
* @returns {HTMLInputElement}
|
|
5595
|
+
*/
|
|
4584
5596
|
const FileInput = (attributes) => Input({ type: 'file', ...attributes });
|
|
5597
|
+
|
|
5598
|
+
/**
|
|
5599
|
+
* Creates an `<input type="password">` element.
|
|
5600
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5601
|
+
* @returns {HTMLInputElement}
|
|
5602
|
+
*/
|
|
4585
5603
|
const PasswordInput = (attributes) => Input({ type: 'password', ...attributes });
|
|
5604
|
+
|
|
5605
|
+
/**
|
|
5606
|
+
* Creates an `<input type="checkbox">` element.
|
|
5607
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5608
|
+
* @returns {HTMLInputElement}
|
|
5609
|
+
*/
|
|
4586
5610
|
const Checkbox = (attributes) => Input({ type: 'checkbox', ...attributes });
|
|
5611
|
+
|
|
5612
|
+
/**
|
|
5613
|
+
* Creates an `<input type="radio">` element.
|
|
5614
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5615
|
+
* @returns {HTMLInputElement}
|
|
5616
|
+
*/
|
|
4587
5617
|
const Radio = (attributes) => Input({ type: 'radio', ...attributes });
|
|
4588
5618
|
|
|
5619
|
+
/**
|
|
5620
|
+
* Creates an `<input type="range">` element.
|
|
5621
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5622
|
+
* @returns {HTMLInputElement}
|
|
5623
|
+
*/
|
|
4589
5624
|
const RangeInput = (attributes) => Input({ type: 'range', ...attributes });
|
|
5625
|
+
|
|
5626
|
+
/**
|
|
5627
|
+
* Creates an `<input type="color">` element.
|
|
5628
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5629
|
+
* @returns {HTMLInputElement}
|
|
5630
|
+
*/
|
|
4590
5631
|
const ColorInput = (attributes) => Input({ type: 'color', ...attributes });
|
|
5632
|
+
|
|
5633
|
+
/**
|
|
5634
|
+
* Creates an `<input type="date">` element.
|
|
5635
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5636
|
+
* @returns {HTMLInputElement}
|
|
5637
|
+
*/
|
|
4591
5638
|
const DateInput = (attributes) => Input({ type: 'date', ...attributes });
|
|
5639
|
+
|
|
5640
|
+
/**
|
|
5641
|
+
* Creates an `<input type="time">` element.
|
|
5642
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5643
|
+
* @returns {HTMLInputElement}
|
|
5644
|
+
*/
|
|
4592
5645
|
const TimeInput = (attributes) => Input({ type: 'time', ...attributes });
|
|
5646
|
+
|
|
5647
|
+
/**
|
|
5648
|
+
* Creates an `<input type="datetime-local">` element.
|
|
5649
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5650
|
+
* @returns {HTMLInputElement}
|
|
5651
|
+
*/
|
|
4593
5652
|
const DateTimeInput = (attributes) => Input({ type: 'datetime-local', ...attributes });
|
|
5653
|
+
|
|
5654
|
+
/**
|
|
5655
|
+
* Creates an `<input type="week">` element.
|
|
5656
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5657
|
+
* @returns {HTMLInputElement}
|
|
5658
|
+
*/
|
|
4594
5659
|
const WeekInput = (attributes) => Input({ type: 'week', ...attributes });
|
|
5660
|
+
|
|
5661
|
+
/**
|
|
5662
|
+
* Creates an `<input type="month">` element.
|
|
5663
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5664
|
+
* @returns {HTMLInputElement}
|
|
5665
|
+
*/
|
|
4595
5666
|
const MonthInput = (attributes) => Input({ type: 'month', ...attributes });
|
|
5667
|
+
|
|
5668
|
+
/**
|
|
5669
|
+
* Creates an `<input type="search">` element.
|
|
5670
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5671
|
+
* @returns {HTMLInputElement}
|
|
5672
|
+
*/
|
|
4596
5673
|
const SearchInput = (attributes) => Input({ type: 'search', ...attributes });
|
|
5674
|
+
|
|
5675
|
+
/**
|
|
5676
|
+
* Creates an `<input type="tel">` element.
|
|
5677
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5678
|
+
* @returns {HTMLInputElement}
|
|
5679
|
+
*/
|
|
4597
5680
|
const TelInput = (attributes) => Input({ type: 'tel', ...attributes });
|
|
5681
|
+
|
|
5682
|
+
/**
|
|
5683
|
+
* Creates an `<input type="url">` element.
|
|
5684
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5685
|
+
* @returns {HTMLInputElement}
|
|
5686
|
+
*/
|
|
4598
5687
|
const UrlInput = (attributes) => Input({ type: 'url', ...attributes });
|
|
5688
|
+
|
|
5689
|
+
/**
|
|
5690
|
+
* Creates an `<input type="email">` element.
|
|
5691
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5692
|
+
* @returns {HTMLInputElement}
|
|
5693
|
+
*/
|
|
4599
5694
|
const EmailInput = (attributes) => Input({ type: 'email', ...attributes });
|
|
4600
|
-
const NumberInput = (attributes) => Input({ type: 'number', ...attributes });
|
|
4601
5695
|
|
|
5696
|
+
/**
|
|
5697
|
+
* Creates an `<input type="number">` element.
|
|
5698
|
+
* @param {Omit<InputAttributes, 'type'>} [attributes]
|
|
5699
|
+
* @returns {HTMLInputElement}
|
|
5700
|
+
*/
|
|
5701
|
+
const NumberInput = (attributes) => Input({ type: 'number', ...attributes });
|
|
4602
5702
|
|
|
5703
|
+
/**
|
|
5704
|
+
* Creates a `<button>` element.
|
|
5705
|
+
* @type {function(ButtonAttributes=, NdChild|NdChild[]=): HTMLButtonElement}
|
|
5706
|
+
*/
|
|
4603
5707
|
const Button = HtmlElementWrapper('button');
|
|
5708
|
+
|
|
5709
|
+
/**
|
|
5710
|
+
* Creates a `<button type="button">` element.
|
|
5711
|
+
* @param {NdChild|NdChild[]} [child]
|
|
5712
|
+
* @param {Omit<ButtonAttributes, 'type'>} [attributes]
|
|
5713
|
+
* @returns {HTMLButtonElement}
|
|
5714
|
+
*/
|
|
4604
5715
|
const SimpleButton = (child, attributes) => Button(child, { type: 'button', ...attributes });
|
|
5716
|
+
|
|
5717
|
+
/**
|
|
5718
|
+
* Creates a `<button type="submit">` element.
|
|
5719
|
+
* @param {NdChild|NdChild[]} [child]
|
|
5720
|
+
* @param {Omit<ButtonAttributes, 'type'>} [attributes]
|
|
5721
|
+
* @returns {HTMLButtonElement}
|
|
5722
|
+
*/
|
|
4605
5723
|
const SubmitButton = (child, attributes) => Button(child, { type: 'submit', ...attributes });
|
|
4606
5724
|
|
|
5725
|
+
/**
|
|
5726
|
+
* Creates a `<main>` element.
|
|
5727
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5728
|
+
*/
|
|
4607
5729
|
const Main = HtmlElementWrapper('main');
|
|
5730
|
+
|
|
5731
|
+
/**
|
|
5732
|
+
* Creates a `<section>` element.
|
|
5733
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5734
|
+
*/
|
|
4608
5735
|
const Section = HtmlElementWrapper('section');
|
|
5736
|
+
|
|
5737
|
+
/**
|
|
5738
|
+
* Creates an `<article>` element.
|
|
5739
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5740
|
+
*/
|
|
4609
5741
|
const Article = HtmlElementWrapper('article');
|
|
5742
|
+
|
|
5743
|
+
/**
|
|
5744
|
+
* Creates an `<aside>` element.
|
|
5745
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5746
|
+
*/
|
|
4610
5747
|
const Aside = HtmlElementWrapper('aside');
|
|
5748
|
+
|
|
5749
|
+
/**
|
|
5750
|
+
* Creates a `<nav>` element.
|
|
5751
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5752
|
+
*/
|
|
4611
5753
|
const Nav = HtmlElementWrapper('nav');
|
|
5754
|
+
|
|
5755
|
+
/**
|
|
5756
|
+
* Creates a `<figure>` element.
|
|
5757
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5758
|
+
*/
|
|
4612
5759
|
const Figure = HtmlElementWrapper('figure');
|
|
5760
|
+
|
|
5761
|
+
/**
|
|
5762
|
+
* Creates a `<figcaption>` element.
|
|
5763
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5764
|
+
*/
|
|
4613
5765
|
const FigCaption = HtmlElementWrapper('figcaption');
|
|
4614
5766
|
|
|
5767
|
+
/**
|
|
5768
|
+
* Creates a `<header>` element.
|
|
5769
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5770
|
+
*/
|
|
4615
5771
|
const Header = HtmlElementWrapper('header');
|
|
5772
|
+
|
|
5773
|
+
/**
|
|
5774
|
+
* Creates a `<footer>` element.
|
|
5775
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5776
|
+
*/
|
|
4616
5777
|
const Footer = HtmlElementWrapper('footer');
|
|
4617
5778
|
|
|
5779
|
+
/**
|
|
5780
|
+
* Creates an `<img>` element.
|
|
5781
|
+
* @type {function(ImgAttributes=): HTMLImageElement}
|
|
5782
|
+
*/
|
|
4618
5783
|
const BaseImage = HtmlElementWrapper('img');
|
|
5784
|
+
|
|
5785
|
+
/**
|
|
5786
|
+
* Creates an `<img>` element.
|
|
5787
|
+
* @param {Observable<string>|string} src
|
|
5788
|
+
* @param {Omit<ImgAttributes, 'src'>} [attributes]
|
|
5789
|
+
* @returns {HTMLImageElement}
|
|
5790
|
+
*/
|
|
4619
5791
|
const Img = function(src, attributes) {
|
|
4620
5792
|
return BaseImage({ src, ...attributes });
|
|
4621
5793
|
};
|
|
4622
5794
|
|
|
4623
5795
|
/**
|
|
4624
|
-
*
|
|
4625
|
-
*
|
|
4626
|
-
* @param {string
|
|
4627
|
-
* @param {
|
|
4628
|
-
* @param {
|
|
4629
|
-
* @
|
|
5796
|
+
* Creates an `<img>` that loads asynchronously, showing a placeholder until the image is ready.
|
|
5797
|
+
* Supports reactive `src` — automatically updates when the observable changes.
|
|
5798
|
+
* @param {Observable<string>|string} src - Final image URL
|
|
5799
|
+
* @param {string|null} defaultImage - Placeholder shown while loading
|
|
5800
|
+
* @param {Omit<ImgAttributes, 'src'>} attributes
|
|
5801
|
+
* @param {(error: NativeDocumentError|null, img: HTMLImageElement) => void} [callback]
|
|
5802
|
+
* @returns {HTMLImageElement}
|
|
4630
5803
|
*/
|
|
4631
5804
|
const AsyncImg = function(src, defaultImage, attributes, callback) {
|
|
4632
5805
|
const defaultSrc = Validator.isObservable(src) ? src.val() : src;
|
|
@@ -4650,56 +5823,230 @@ var NativeDocument = (function (exports) {
|
|
|
4650
5823
|
};
|
|
4651
5824
|
|
|
4652
5825
|
/**
|
|
4653
|
-
*
|
|
4654
|
-
* @param {string}
|
|
4655
|
-
* @param {
|
|
4656
|
-
* @returns {
|
|
5826
|
+
* Creates an `<img loading="lazy">` element.
|
|
5827
|
+
* @param {Observable<string>|string} src
|
|
5828
|
+
* @param {Omit<ImgAttributes, 'src'|'loading'>} [attributes]
|
|
5829
|
+
* @returns {HTMLImageElement}
|
|
4657
5830
|
*/
|
|
4658
5831
|
const LazyImg = function(src, attributes) {
|
|
4659
5832
|
return Img(src, { ...attributes, loading: 'lazy' });
|
|
4660
5833
|
};
|
|
4661
5834
|
|
|
5835
|
+
/**
|
|
5836
|
+
* Creates a `<details>` element.
|
|
5837
|
+
* @type {function(DetailsAttributes=, NdChild|NdChild[]=): HTMLDetailsElement}
|
|
5838
|
+
*/
|
|
4662
5839
|
const Details = HtmlElementWrapper('details');
|
|
5840
|
+
|
|
5841
|
+
/**
|
|
5842
|
+
* Creates a `<summary>` element.
|
|
5843
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5844
|
+
*/
|
|
4663
5845
|
const Summary = HtmlElementWrapper('summary');
|
|
5846
|
+
|
|
5847
|
+
/**
|
|
5848
|
+
* Creates a `<dialog>` element.
|
|
5849
|
+
* @type {function(DialogAttributes=, NdChild|NdChild[]=): HTMLDialogElement}
|
|
5850
|
+
*/
|
|
4664
5851
|
const Dialog = HtmlElementWrapper('dialog');
|
|
5852
|
+
|
|
5853
|
+
/**
|
|
5854
|
+
* Creates a `<menu>` element.
|
|
5855
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLMenuElement}
|
|
5856
|
+
*/
|
|
4665
5857
|
const Menu = HtmlElementWrapper('menu');
|
|
4666
5858
|
|
|
5859
|
+
/**
|
|
5860
|
+
* Creates an `<ol>` element.
|
|
5861
|
+
* @type {function(OlAttributes=, NdChild|NdChild[]=): HTMLOListElement}
|
|
5862
|
+
*/
|
|
4667
5863
|
const OrderedList = HtmlElementWrapper('ol');
|
|
5864
|
+
|
|
5865
|
+
/**
|
|
5866
|
+
* Creates a `<ul>` element.
|
|
5867
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLUListElement}
|
|
5868
|
+
*/
|
|
4668
5869
|
const UnorderedList = HtmlElementWrapper('ul');
|
|
5870
|
+
|
|
5871
|
+
/**
|
|
5872
|
+
* Creates a `<li>` element.
|
|
5873
|
+
* @type {function(GlobalAttributes & { value?: number }=, NdChild|NdChild[]=): HTMLLIElement}
|
|
5874
|
+
*/
|
|
4669
5875
|
const ListItem = HtmlElementWrapper('li');
|
|
4670
5876
|
|
|
5877
|
+
/**
|
|
5878
|
+
* Alias for {@link ListItem}.
|
|
5879
|
+
* @type {typeof ListItem}
|
|
5880
|
+
*/
|
|
4671
5881
|
const Li = ListItem;
|
|
5882
|
+
|
|
5883
|
+
/**
|
|
5884
|
+
* Alias for {@link OrderedList}.
|
|
5885
|
+
* @type {typeof OrderedList}
|
|
5886
|
+
*/
|
|
4672
5887
|
const Ol = OrderedList;
|
|
5888
|
+
|
|
5889
|
+
/**
|
|
5890
|
+
* Alias for {@link UnorderedList}.
|
|
5891
|
+
* @type {typeof UnorderedList}
|
|
5892
|
+
*/
|
|
4673
5893
|
const Ul = UnorderedList;
|
|
4674
5894
|
|
|
5895
|
+
/**
|
|
5896
|
+
* Creates an `<audio>` element.
|
|
5897
|
+
* @type {function(AudioAttributes=, NdChild|NdChild[]=): HTMLAudioElement}
|
|
5898
|
+
*/
|
|
4675
5899
|
const Audio = HtmlElementWrapper('audio');
|
|
5900
|
+
|
|
5901
|
+
/**
|
|
5902
|
+
* Creates a `<video>` element.
|
|
5903
|
+
* @type {function(VideoAttributes=, NdChild|NdChild[]=): HTMLVideoElement}
|
|
5904
|
+
*/
|
|
4676
5905
|
const Video = HtmlElementWrapper('video');
|
|
5906
|
+
|
|
5907
|
+
/**
|
|
5908
|
+
* Creates a `<source>` element.
|
|
5909
|
+
* @type {function(SourceAttributes=): HTMLSourceElement}
|
|
5910
|
+
*/
|
|
4677
5911
|
const Source = HtmlElementWrapper('source');
|
|
5912
|
+
|
|
5913
|
+
/**
|
|
5914
|
+
* Creates a `<track>` element.
|
|
5915
|
+
* @type {function(TrackAttributes=): HTMLTrackElement}
|
|
5916
|
+
*/
|
|
4678
5917
|
const Track = HtmlElementWrapper('track');
|
|
5918
|
+
|
|
5919
|
+
/**
|
|
5920
|
+
* Creates a `<canvas>` element.
|
|
5921
|
+
* @type {function(CanvasAttributes=, NdChild|NdChild[]=): HTMLCanvasElement}
|
|
5922
|
+
*/
|
|
4679
5923
|
const Canvas = HtmlElementWrapper('canvas');
|
|
5924
|
+
|
|
5925
|
+
/**
|
|
5926
|
+
* Creates an `<svg>` element.
|
|
5927
|
+
* @type {function(SvgAttributes=, NdChild|NdChild[]=): SVGSVGElement}
|
|
5928
|
+
*/
|
|
4680
5929
|
const Svg = HtmlElementWrapper('svg');
|
|
4681
5930
|
|
|
5931
|
+
/**
|
|
5932
|
+
* Creates a `<time>` element.
|
|
5933
|
+
* @type {function(TimeAttributes=, NdChild|NdChild[]=): HTMLTimeElement}
|
|
5934
|
+
*/
|
|
4682
5935
|
const Time = HtmlElementWrapper('time');
|
|
5936
|
+
|
|
5937
|
+
/**
|
|
5938
|
+
* Creates a `<data>` element.
|
|
5939
|
+
* @type {function(GlobalAttributes & { value?: Observable<string>|string }=, NdChild|NdChild[]=): HTMLDataElement}
|
|
5940
|
+
*/
|
|
4683
5941
|
const Data = HtmlElementWrapper('data');
|
|
5942
|
+
|
|
5943
|
+
/**
|
|
5944
|
+
* Creates an `<address>` element.
|
|
5945
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5946
|
+
*/
|
|
4684
5947
|
const Address = HtmlElementWrapper('address');
|
|
5948
|
+
|
|
5949
|
+
/**
|
|
5950
|
+
* Creates a `<kbd>` element.
|
|
5951
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5952
|
+
*/
|
|
4685
5953
|
const Kbd = HtmlElementWrapper('kbd');
|
|
5954
|
+
|
|
5955
|
+
/**
|
|
5956
|
+
* Creates a `<samp>` element.
|
|
5957
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5958
|
+
*/
|
|
4686
5959
|
const Samp = HtmlElementWrapper('samp');
|
|
5960
|
+
|
|
5961
|
+
/**
|
|
5962
|
+
* Creates a `<var>` element.
|
|
5963
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
5964
|
+
*/
|
|
4687
5965
|
const Var = HtmlElementWrapper('var');
|
|
5966
|
+
|
|
5967
|
+
/**
|
|
5968
|
+
* Creates a `<wbr>` element.
|
|
5969
|
+
* @type {function(GlobalAttributes=): HTMLElement}
|
|
5970
|
+
*/
|
|
4688
5971
|
const Wbr = HtmlElementWrapper('wbr');
|
|
4689
5972
|
|
|
5973
|
+
/**
|
|
5974
|
+
* Creates a `<caption>` element.
|
|
5975
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLTableCaptionElement}
|
|
5976
|
+
*/
|
|
4690
5977
|
const Caption = HtmlElementWrapper('caption');
|
|
5978
|
+
|
|
5979
|
+
/**
|
|
5980
|
+
* Creates a `<table>` element.
|
|
5981
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLTableElement}
|
|
5982
|
+
*/
|
|
4691
5983
|
const Table = HtmlElementWrapper('table');
|
|
5984
|
+
|
|
5985
|
+
/**
|
|
5986
|
+
* Creates a `<thead>` element.
|
|
5987
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLTableSectionElement}
|
|
5988
|
+
*/
|
|
4692
5989
|
const THead = HtmlElementWrapper('thead');
|
|
5990
|
+
|
|
5991
|
+
/**
|
|
5992
|
+
* Creates a `<tfoot>` element.
|
|
5993
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLTableSectionElement}
|
|
5994
|
+
*/
|
|
4693
5995
|
const TFoot = HtmlElementWrapper('tfoot');
|
|
5996
|
+
|
|
5997
|
+
/**
|
|
5998
|
+
* Creates a `<tbody>` element.
|
|
5999
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLTableSectionElement}
|
|
6000
|
+
*/
|
|
4694
6001
|
const TBody = HtmlElementWrapper('tbody');
|
|
6002
|
+
|
|
6003
|
+
/**
|
|
6004
|
+
* Creates a `<tr>` element.
|
|
6005
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLTableRowElement}
|
|
6006
|
+
*/
|
|
4695
6007
|
const Tr = HtmlElementWrapper('tr');
|
|
6008
|
+
|
|
6009
|
+
/**
|
|
6010
|
+
* Alias for {@link Tr}.
|
|
6011
|
+
* @type {typeof Tr}
|
|
6012
|
+
*/
|
|
4696
6013
|
const TRow = Tr;
|
|
6014
|
+
|
|
6015
|
+
/**
|
|
6016
|
+
* Creates a `<th>` element.
|
|
6017
|
+
* @type {function(ThAttributes=, NdChild|NdChild[]=): HTMLTableCellElement}
|
|
6018
|
+
*/
|
|
4697
6019
|
const Th = HtmlElementWrapper('th');
|
|
6020
|
+
|
|
6021
|
+
/**
|
|
6022
|
+
* Alias for {@link Th}.
|
|
6023
|
+
* @type {typeof Th}
|
|
6024
|
+
*/
|
|
4698
6025
|
const THeadCell = Th;
|
|
6026
|
+
|
|
6027
|
+
/**
|
|
6028
|
+
* Alias for {@link Th}.
|
|
6029
|
+
* @type {typeof Th}
|
|
6030
|
+
*/
|
|
4699
6031
|
const TFootCell = Th;
|
|
6032
|
+
|
|
6033
|
+
/**
|
|
6034
|
+
* Creates a `<td>` element.
|
|
6035
|
+
* @type {function(TdAttributes=, NdChild|NdChild[]=): HTMLTableCellElement}
|
|
6036
|
+
*/
|
|
4700
6037
|
const Td = HtmlElementWrapper('td');
|
|
6038
|
+
|
|
6039
|
+
/**
|
|
6040
|
+
* Alias for {@link Td}.
|
|
6041
|
+
* @type {typeof Td}
|
|
6042
|
+
*/
|
|
4701
6043
|
const TBodyCell = Td;
|
|
4702
6044
|
|
|
6045
|
+
/**
|
|
6046
|
+
* Creates an empty `DocumentFragment` wrapper.
|
|
6047
|
+
* Useful for grouping elements without adding a DOM node.
|
|
6048
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): DocumentFragment}
|
|
6049
|
+
*/
|
|
4703
6050
|
const Fragment = HtmlElementWrapper('');
|
|
4704
6051
|
|
|
4705
6052
|
var elements = /*#__PURE__*/Object.freeze({
|
|
@@ -5102,7 +6449,7 @@ var NativeDocument = (function (exports) {
|
|
|
5102
6449
|
window.history.pushState({ name: route.name(), params, path}, route.name() || path , path);
|
|
5103
6450
|
this.handleRouteChange(route, params, query, path);
|
|
5104
6451
|
} catch (e) {
|
|
5105
|
-
DebugManager
|
|
6452
|
+
DebugManager.error('HistoryRouter', 'Error in pushState', e);
|
|
5106
6453
|
}
|
|
5107
6454
|
};
|
|
5108
6455
|
/**
|
|
@@ -5115,7 +6462,7 @@ var NativeDocument = (function (exports) {
|
|
|
5115
6462
|
window.history.replaceState({ name: route.name(), params, path}, route.name() || path , path);
|
|
5116
6463
|
this.handleRouteChange(route, params, {}, path);
|
|
5117
6464
|
} catch(e) {
|
|
5118
|
-
DebugManager
|
|
6465
|
+
DebugManager.error('HistoryRouter', 'Error in replaceState', e);
|
|
5119
6466
|
}
|
|
5120
6467
|
};
|
|
5121
6468
|
this.forward = function() {
|
|
@@ -5142,7 +6489,7 @@ var NativeDocument = (function (exports) {
|
|
|
5142
6489
|
}
|
|
5143
6490
|
this.handleRouteChange(route, params, query, path);
|
|
5144
6491
|
} catch(e) {
|
|
5145
|
-
DebugManager
|
|
6492
|
+
DebugManager.error('HistoryRouter', 'Error in popstate event', e);
|
|
5146
6493
|
}
|
|
5147
6494
|
});
|
|
5148
6495
|
const { route, params, query, path } = this.resolve(defaultPath || (window.location.pathname+window.location.search));
|
|
@@ -5367,7 +6714,7 @@ var NativeDocument = (function (exports) {
|
|
|
5367
6714
|
listener(request);
|
|
5368
6715
|
next && next(request);
|
|
5369
6716
|
} catch (e) {
|
|
5370
|
-
DebugManager
|
|
6717
|
+
DebugManager.warn('Route Listener', 'Error in listener:', e);
|
|
5371
6718
|
}
|
|
5372
6719
|
}
|
|
5373
6720
|
};
|
|
@@ -5545,7 +6892,7 @@ var NativeDocument = (function (exports) {
|
|
|
5545
6892
|
*/
|
|
5546
6893
|
Router.create = function(options, callback) {
|
|
5547
6894
|
if(!Validator.isFunction(callback)) {
|
|
5548
|
-
DebugManager
|
|
6895
|
+
DebugManager.error('Router', 'Callback must be a function');
|
|
5549
6896
|
throw new RouterError('Callback must be a function');
|
|
5550
6897
|
}
|
|
5551
6898
|
const router = new Router(options);
|
|
@@ -5663,11 +7010,14 @@ var NativeDocument = (function (exports) {
|
|
|
5663
7010
|
configs.body = params;
|
|
5664
7011
|
}
|
|
5665
7012
|
else {
|
|
5666
|
-
configs.headers['Content-Type'] = 'application/json';
|
|
5667
7013
|
if(method !== 'GET') {
|
|
7014
|
+
configs.headers['Content-Type'] = 'application/json';
|
|
5668
7015
|
configs.body = JSON.stringify(params);
|
|
5669
7016
|
} else {
|
|
5670
|
-
|
|
7017
|
+
const queryString = new URLSearchParams(params).toString();
|
|
7018
|
+
if (queryString) {
|
|
7019
|
+
endpoint = endpoint + (endpoint.includes('?') ? '&' : '?') + queryString;
|
|
7020
|
+
}
|
|
5671
7021
|
}
|
|
5672
7022
|
}
|
|
5673
7023
|
}
|
|
@@ -5734,10 +7084,11 @@ var NativeDocument = (function (exports) {
|
|
|
5734
7084
|
exports.ElementCreator = ElementCreator;
|
|
5735
7085
|
exports.HtmlElementWrapper = HtmlElementWrapper;
|
|
5736
7086
|
exports.NDElement = NDElement;
|
|
5737
|
-
exports.Observable = Observable;
|
|
5738
|
-
exports.PluginsManager = PluginsManager
|
|
7087
|
+
exports.Observable = Observable$1;
|
|
7088
|
+
exports.PluginsManager = PluginsManager;
|
|
5739
7089
|
exports.SingletonView = SingletonView;
|
|
5740
7090
|
exports.Store = Store;
|
|
7091
|
+
exports.StoreFactory = StoreFactory;
|
|
5741
7092
|
exports.TemplateCloner = TemplateCloner;
|
|
5742
7093
|
exports.Validator = Validator;
|
|
5743
7094
|
exports.autoMemoize = autoMemoize;
|