@twobirds/microcomponents 0.1.16 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/MC.ts +345 -346
- package/dist/elements.ts +80 -96
- package/dist/formValues.ts +165 -171
- package/dist/helpers.ts +100 -100
- package/dist/observables.ts +295 -325
- package/package.json +4 -3
- package/dist/MC.d.ts +0 -39
- package/dist/MC.d.ts.map +0 -1
- package/dist/MC.js +0 -302
- package/dist/MC.min.js +0 -345
- package/dist/elements.d.ts +0 -5
- package/dist/elements.d.ts.map +0 -1
- package/dist/elements.js +0 -67
- package/dist/elements.min.js +0 -1
- package/dist/formValues.d.ts +0 -3
- package/dist/formValues.d.ts.map +0 -1
- package/dist/formValues.js +0 -159
- package/dist/formValues.min.js +0 -1
- package/dist/helpers.d.ts +0 -14
- package/dist/helpers.d.ts.map +0 -1
- package/dist/helpers.js +0 -111
- package/dist/microcomponents.d.ts +0 -6
- package/dist/microcomponents.d.ts.map +0 -1
- package/dist/microcomponents.js +0 -6
- package/dist/microcomponents.min.js +0 -1
- package/dist/observables.d.ts +0 -11
- package/dist/observables.d.ts.map +0 -1
- package/dist/observables.js +0 -234
- package/dist/observables.min.js +0 -1
package/dist/MC.ts
CHANGED
|
@@ -5,308 +5,307 @@ import { LooseObject } from './helpers.js';
|
|
|
5
5
|
const isBrowser = new Function('try {return this===window;}catch(e){ return false;}');
|
|
6
6
|
|
|
7
7
|
export interface HTMLMcElement extends HTMLElement {
|
|
8
|
-
|
|
8
|
+
_mc: LooseObject;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
function isDOM(element: { [key: string]: any }) {
|
|
12
|
-
|
|
12
|
+
return element && element instanceof HTMLElement;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
// add a microcomponent to a target DOM node
|
|
16
16
|
function add(target: HTMLElement, key: string, element: any = {}): HTMLMcElement {
|
|
17
|
-
|
|
17
|
+
let node = target as HTMLMcElement;
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
// create the _mc property if necessary
|
|
20
|
+
if (!node._mc) {
|
|
21
|
+
node._mc = new (DC as any)(target);
|
|
22
|
+
}
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
const _mc = node._mc;
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
// add the element with the given property key to the _mc property
|
|
27
|
+
if (key.length && !_mc[key]) {
|
|
28
|
+
_mc[key] = element;
|
|
29
|
+
// add attribute if HTMLElement
|
|
30
|
+
if (target instanceof HTMLElement && !target.getAttribute('data-mc')) {
|
|
31
|
+
target.setAttribute('data-mc', '');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
//console.warn('add() args: target, key, element', arguments, node);
|
|
36
|
+
|
|
37
|
+
return node;
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
// remove a micro component from the DOM
|
|
39
41
|
function remove(target: HTMLElement, key: string) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
) {
|
|
55
|
-
target.removeAttribute('data-mc');
|
|
56
|
-
}
|
|
57
|
-
return;
|
|
42
|
+
if (!key) return; // silent fail
|
|
43
|
+
|
|
44
|
+
const _mc = (target as unknown as HTMLMcElement)?._mc || {};
|
|
45
|
+
|
|
46
|
+
// delete the property from the HTMLElement _mc collection
|
|
47
|
+
if (_mc && _mc[key]) {
|
|
48
|
+
delete _mc[key];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// remove the _mc attribute if the DOM collection is empty
|
|
52
|
+
if (!Object.keys(_mc).length && target instanceof HTMLElement && target.hasAttribute('data-mc')) {
|
|
53
|
+
target.removeAttribute('data-mc');
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
58
56
|
}
|
|
59
57
|
|
|
60
58
|
// run the "init" lifecycle event on the complete _mc structure
|
|
61
59
|
function init(element: DC) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
//console.warn('init(): args', ...arguments);
|
|
61
|
+
setTimeout(() => {
|
|
62
|
+
if (element.constructor === DC) return;
|
|
63
|
+
element.trigger('Init');
|
|
64
|
+
}, 0);
|
|
66
65
|
}
|
|
67
66
|
|
|
68
67
|
// 'eventName' => '_mcEventName'
|
|
69
68
|
function getMcEventName(eventName: string): string {
|
|
70
|
-
|
|
69
|
+
return '_mc' + eventName[0].toUpperCase() + eventName.substring(1);
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
/*
|
|
74
73
|
CustomEvent Section...
|
|
75
74
|
*/
|
|
76
75
|
function off(domNode: Node, eventName: string, handler: EventListenerOrEventListenerObject) {
|
|
77
|
-
|
|
76
|
+
domNode.removeEventListener(getMcEventName(eventName), handler);
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
function on(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
domNode: Node,
|
|
81
|
+
eventName: string,
|
|
82
|
+
handler: EventListenerOrEventListenerObject,
|
|
83
|
+
once: boolean = false
|
|
85
84
|
): EventListenerOrEventListenerObject {
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
domNode.addEventListener(getMcEventName(eventName), handler, { capture: false, once });
|
|
86
|
+
return handler;
|
|
88
87
|
}
|
|
89
88
|
|
|
90
89
|
function one(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
domNode: Node,
|
|
91
|
+
eventName: string,
|
|
92
|
+
handler: EventListenerOrEventListenerObject
|
|
94
93
|
): EventListenerOrEventListenerObject {
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
on(domNode, eventName, handler, true);
|
|
95
|
+
return handler;
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
class BubbleController {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
stopped = false;
|
|
100
|
+
constructor() {}
|
|
101
|
+
stop() {
|
|
102
|
+
this.stopped = true;
|
|
103
|
+
}
|
|
105
104
|
}
|
|
106
105
|
|
|
107
106
|
// create and dispatch custom event
|
|
108
107
|
function trigger(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
domNode: HTMLElement,
|
|
109
|
+
event: string,
|
|
110
|
+
data: any = {},
|
|
111
|
+
bubble: string = 'l', // direction of bubbling
|
|
112
|
+
controller?: BubbleController
|
|
114
113
|
) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
114
|
+
//console.warn('trigger args', ...arguments);
|
|
115
|
+
|
|
116
|
+
const eventName = /^_mc/.test(event) ? event : getMcEventName(event),
|
|
117
|
+
bubbleController = controller ? controller : new BubbleController(),
|
|
118
|
+
ev = new CustomEvent(eventName, {
|
|
119
|
+
detail: { data, control: bubbleController },
|
|
120
|
+
bubbles: false,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (bubbleController.stopped) return;
|
|
124
|
+
|
|
125
|
+
if (/l/.test(bubble)) {
|
|
126
|
+
domNode.dispatchEvent(ev);
|
|
127
|
+
ev.stopImmediatePropagation();
|
|
128
|
+
|
|
129
|
+
if (bubbleController.stopped) return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// bubble if up or down is indicated
|
|
133
|
+
if (/[ud]/.test(bubble)) {
|
|
134
|
+
// add missing 'l', or else no handlers are executed
|
|
135
|
+
if (bubble.indexOf('l') === -1) {
|
|
136
|
+
bubble += 'l';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
setTimeout(() => {
|
|
140
|
+
// bubble up towards document.body
|
|
141
|
+
if (bubble.indexOf('u') > -1) {
|
|
142
|
+
let parentMc: HTMLMcElement | null | undefined =
|
|
143
|
+
domNode.parentElement?.closest('[data-mc]');
|
|
144
|
+
if (parentMc) {
|
|
145
|
+
parentMc?._mc.trigger(eventName, data, bubble, bubbleController);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// bubble down towards DOM children
|
|
150
|
+
if (bubble.indexOf('d') > -1) {
|
|
151
|
+
let childNodes: DC[] | null = (domNode as HTMLMcElement)._mc.children();
|
|
152
|
+
if (childNodes) {
|
|
153
|
+
childNodes.forEach((_mc: DC) => _mc.trigger(eventName, data, bubble)); // event multiplex - dont carry bubble controller
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}, 0);
|
|
157
|
+
}
|
|
159
158
|
}
|
|
160
159
|
|
|
161
160
|
function autoAttachListeners(element: MC | DC) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
161
|
+
if (!isBrowser() || element.constructor === DC) return;
|
|
162
|
+
|
|
163
|
+
const target = element.target;
|
|
164
|
+
|
|
165
|
+
if (target instanceof HTMLElement) {
|
|
166
|
+
let that: LooseObject = element;
|
|
167
|
+
Object.getOwnPropertyNames(that.constructor.prototype)
|
|
168
|
+
.filter(
|
|
169
|
+
(key) =>
|
|
170
|
+
/^(on[A-Z]|one[A-Z])/.test(key) && typeof that.constructor.prototype[key] === 'function'
|
|
171
|
+
)
|
|
172
|
+
.forEach((key) => {
|
|
173
|
+
let once = /^one/.test(key),
|
|
174
|
+
withoutOnOne = key.replace(/^on[e]{0,1}/, ''), // preserves upper/lowercase for non-native events
|
|
175
|
+
nativeEventName = withoutOnOne.toLowerCase(); // lowercase for native event names
|
|
176
|
+
|
|
177
|
+
if ('on' + nativeEventName in target) {
|
|
178
|
+
// it is a native HTML event
|
|
179
|
+
let listener = (ev: Event) => {
|
|
180
|
+
that[key](ev);
|
|
181
|
+
};
|
|
182
|
+
// console.log( 'AAL: attach native event listener', nativeEventName, 'to', target );
|
|
183
|
+
target.addEventListener(nativeEventName, listener);
|
|
184
|
+
} else {
|
|
185
|
+
// it is a customEvent
|
|
186
|
+
// console.log( 'AAL: attach custom event listener', '_mc' + withoutOnOne , 'to key', key, 'in', element );
|
|
187
|
+
let listener = (ev: CustomEvent) => {
|
|
188
|
+
that[key](ev);
|
|
189
|
+
};
|
|
190
|
+
on(target, withoutOnOne, listener as EventListenerOrEventListenerObject, once);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
}
|
|
196
194
|
}
|
|
197
195
|
|
|
198
196
|
function getMcChildNodes(domNode: HTMLElement): DC[] | null {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
197
|
+
const id = Math.random().toString().replace('.', '');
|
|
198
|
+
const selector = '[data-mc]:not([temp_id="' + id + '"] [data-mc] [data-mc])';
|
|
199
|
+
domNode.setAttribute('temp_id', id);
|
|
200
|
+
const mcArray: unknown[] = ([...domNode.querySelectorAll(selector)] as HTMLMcElement[])
|
|
201
|
+
.filter((e) => !!e._mc)
|
|
202
|
+
.map((e) => e._mc);
|
|
203
|
+
domNode.removeAttribute('temp_id');
|
|
204
|
+
return mcArray.length ? (mcArray as DC[]) : null;
|
|
207
205
|
}
|
|
208
206
|
|
|
209
207
|
class McBase {
|
|
210
|
-
|
|
208
|
+
private _target: WeakRef<any>; // avoid circular reference
|
|
209
|
+
|
|
210
|
+
constructor(target?: { [key: string]: any }) {
|
|
211
|
+
let element = this as unknown as MC | DC;
|
|
211
212
|
|
|
212
|
-
|
|
213
|
-
let element = this as unknown as MC | DC;
|
|
213
|
+
this._target = new WeakRef(target || {});
|
|
214
214
|
|
|
215
|
-
|
|
215
|
+
//console.warn('McBase: this, element, args', target, this, element, arguments);
|
|
216
216
|
|
|
217
|
-
|
|
217
|
+
autoAttachListeners(element);
|
|
218
218
|
|
|
219
|
-
|
|
220
|
-
|
|
219
|
+
init(element as DC); // async lifecycle event
|
|
220
|
+
}
|
|
221
221
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
222
|
+
get target(): any {
|
|
223
|
+
return this._target.deref();
|
|
224
|
+
}
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
class MC extends McBase {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
228
|
+
constructor(target?: any) {
|
|
229
|
+
super(target);
|
|
230
|
+
}
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
class DC extends McBase {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
234
|
+
constructor(target: HTMLElement) {
|
|
235
|
+
super(target);
|
|
236
|
+
//console.warn('DC constructor:', arguments);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
static add(target: HTMLElement, key: string, element: any = {}): HTMLMcElement {
|
|
240
|
+
//console.warn('static DC.add() args', arguments);
|
|
241
|
+
return add(target, key, element);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
static remove(target: HTMLElement, key: string) {
|
|
245
|
+
remove(target, key);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* event handling */
|
|
249
|
+
off(eventName: string, handler: EventListenerOrEventListenerObject) {
|
|
250
|
+
off(this.target, eventName, handler);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
on(
|
|
254
|
+
eventName: string,
|
|
255
|
+
handler: EventListenerOrEventListenerObject
|
|
256
|
+
): EventListenerOrEventListenerObject {
|
|
257
|
+
return on(this.target, eventName, handler);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
one(
|
|
261
|
+
eventName: string,
|
|
262
|
+
handler: EventListenerOrEventListenerObject
|
|
263
|
+
): EventListenerOrEventListenerObject {
|
|
264
|
+
return one(this.target, eventName, handler);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
trigger(eventName: string, data: any = {}, bubble: string = 'l', controller?: BubbleController) {
|
|
268
|
+
//console.warn('MC.trigger args', ...arguments, this);
|
|
269
|
+
|
|
270
|
+
trigger(this.target, eventName, data, bubble, controller);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/* DOM traversal */
|
|
274
|
+
ancestors(): DC[] | null {
|
|
275
|
+
let currentNode: HTMLElement | null = (this as DC)?.target as HTMLMcElement,
|
|
276
|
+
result: DC[] = [];
|
|
277
|
+
|
|
278
|
+
if (!isDOM(currentNode)) return [];
|
|
279
|
+
|
|
280
|
+
while ((currentNode = currentNode.closest('[data-mc]'))) {
|
|
281
|
+
if ((currentNode as HTMLMcElement)?._mc) {
|
|
282
|
+
result.push((currentNode as HTMLMcElement)?._mc as DC);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return result.length ? result : null;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
closest(): DC | null {
|
|
290
|
+
let target: HTMLElement = (this as DC).target;
|
|
291
|
+
if (!isDOM(target)) return null;
|
|
292
|
+
return ((target.closest('[data-mc]') as HTMLMcElement)?._mc as DC) || null;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
children(): DC[] | null {
|
|
296
|
+
let target: any = (this as any)?.target;
|
|
297
|
+
if (!isDOM(target)) return null;
|
|
298
|
+
return getMcChildNodes(target);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
descendants(): DC[] | null {
|
|
302
|
+
const target: any = (this as DC)?.target;
|
|
303
|
+
if (!isDOM(target)) return [];
|
|
304
|
+
const mcArray: unknown[] = ([...target.querySelectorAll('[data-mc]')] as HTMLMcElement[])
|
|
305
|
+
.filter((e) => !!e._mc)
|
|
306
|
+
.map((e) => e._mc);
|
|
307
|
+
return mcArray.length ? (mcArray as DC[]) : null;
|
|
308
|
+
}
|
|
310
309
|
}
|
|
311
310
|
|
|
312
311
|
/*
|
|
@@ -316,141 +315,141 @@ Autoload Section...
|
|
|
316
315
|
const loadingDCs = new Set<string>();
|
|
317
316
|
|
|
318
317
|
function attachDC(element: string): Function {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
318
|
+
//@ts-ignore
|
|
319
|
+
return () => {
|
|
320
|
+
const elements: HTMLElement[] = Array.from(
|
|
321
|
+
document.querySelectorAll(`[data-mc*="${element}"]`)
|
|
322
|
+
).filter((element) => element instanceof HTMLElement);
|
|
323
|
+
|
|
324
|
+
if (elements.length === 0) return;
|
|
325
|
+
|
|
326
|
+
//console.log( 'loadedPromise elements', elements );
|
|
327
|
+
|
|
328
|
+
const Klass = customElements.get(element);
|
|
329
|
+
|
|
330
|
+
elements.forEach((node: HTMLElement) => {
|
|
331
|
+
try {
|
|
332
|
+
//console.log( 'add', klass!.name, 'to', node );
|
|
333
|
+
DC.add(node, Klass!.name, new Klass!(node));
|
|
334
|
+
} catch (error) {
|
|
335
|
+
if ((Klass as LooseObject)['create']) {
|
|
336
|
+
let element: HTMLMcElement = (Klass as LooseObject).create(node);
|
|
337
|
+
element.setAttribute('data-mc', node.getAttribute('data-mc')!);
|
|
338
|
+
node.replaceWith(element);
|
|
339
|
+
node = element;
|
|
340
|
+
} else {
|
|
341
|
+
throw `Class ${(Klass as LooseObject).name} doesn't have a callable constructor AND class doesn't have a static .create() method.`;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
//@ts-ignore
|
|
346
|
+
const new_mc = node
|
|
347
|
+
.getAttribute('data-mc')
|
|
348
|
+
.split(' ')
|
|
349
|
+
.filter((name) => name !== element && name !== '')
|
|
350
|
+
.join(' ')
|
|
351
|
+
.trim();
|
|
352
|
+
|
|
353
|
+
//@ts-ignore
|
|
354
|
+
node.setAttribute(
|
|
355
|
+
'data-mc',
|
|
356
|
+
//@ts-ignore
|
|
357
|
+
new_mc
|
|
358
|
+
);
|
|
359
|
+
});
|
|
360
|
+
};
|
|
362
361
|
}
|
|
363
362
|
|
|
364
363
|
function makeLoadScript(element: string) {
|
|
365
|
-
|
|
364
|
+
if (loadingDCs.has(element)) return; // already loading
|
|
366
365
|
|
|
367
|
-
|
|
366
|
+
loadingDCs.add(element);
|
|
368
367
|
|
|
369
|
-
|
|
370
|
-
|
|
368
|
+
//console.log( 'makeLoadScript:', element);
|
|
369
|
+
const fileName: string = './' + element.split('-').join('/') + '.js';
|
|
371
370
|
|
|
372
|
-
|
|
371
|
+
const se: HTMLScriptElement = document.createElement('script');
|
|
373
372
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
373
|
+
se.setAttribute('src', fileName);
|
|
374
|
+
se.setAttribute('blocking', 'render');
|
|
375
|
+
se.async = true;
|
|
376
|
+
se.setAttribute('type', 'module');
|
|
377
|
+
se.setAttribute('data-name', element);
|
|
378
|
+
se.setAttribute('loading', '');
|
|
380
379
|
|
|
381
|
-
|
|
380
|
+
const loadedPromise = customElements.whenDefined(element);
|
|
382
381
|
|
|
383
|
-
|
|
384
|
-
|
|
382
|
+
//@ts-ignore
|
|
383
|
+
loadedPromise.then(attachDC(element));
|
|
385
384
|
|
|
386
|
-
|
|
387
|
-
|
|
385
|
+
se.addEventListener('load', (ev: Event) => {
|
|
386
|
+
loadingDCs.delete(element);
|
|
388
387
|
|
|
389
|
-
|
|
390
|
-
|
|
388
|
+
document.head.querySelector(`script[data-name="${element}"]`)?.remove();
|
|
389
|
+
});
|
|
391
390
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
391
|
+
se.addEventListener('error', (ev: Event) => {
|
|
392
|
+
console.error('could not load DC code from', fileName);
|
|
393
|
+
});
|
|
395
394
|
|
|
396
|
-
|
|
395
|
+
document.head.append(se);
|
|
397
396
|
}
|
|
398
397
|
|
|
399
398
|
function loadUndefinedMCs() {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
399
|
+
// load unresolved custom elements
|
|
400
|
+
[...document.querySelectorAll(':not(:defined)')]
|
|
401
|
+
.filter(
|
|
402
|
+
(element) =>
|
|
403
|
+
!!element &&
|
|
404
|
+
!customElements.get(element.tagName.toLowerCase()) && // not in CustomElementsRegistry
|
|
405
|
+
!loadingDCs.has(element.tagName.toLowerCase()) // not in loading list
|
|
406
|
+
)
|
|
407
|
+
.forEach((el) => {
|
|
408
|
+
//console.log( 'detected CE', el.tagName.toLowerCase() );
|
|
409
|
+
makeLoadScript(el.tagName.toLowerCase()); // will automatically be instanciated
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// if defined in _mc attribute: instanciate DCs, load if necessary
|
|
413
|
+
[...document.querySelectorAll('[data-mc]:not([data-mc=""]')]
|
|
414
|
+
.filter((element) => !!element)
|
|
415
|
+
.forEach((el) => {
|
|
416
|
+
const _mc = el
|
|
417
|
+
.getAttribute('data-mc')
|
|
418
|
+
?.split(' ')
|
|
419
|
+
.filter((name) => name !== '');
|
|
420
|
+
_mc?.forEach((element) => {
|
|
421
|
+
//console.log( 'detected DC', dc );
|
|
422
|
+
const isDefined = customElements.get(element);
|
|
423
|
+
if (!loadingDCs.has(element) && !isDefined) {
|
|
424
|
+
makeLoadScript(element);
|
|
425
|
+
} else if (isDefined) {
|
|
426
|
+
attachDC(element)();
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
});
|
|
431
430
|
}
|
|
432
431
|
|
|
433
432
|
let autoloadEnabled: boolean = false;
|
|
434
433
|
let observer: MutationObserver | null = null;
|
|
435
434
|
|
|
436
435
|
function autoload(enable: boolean = true): boolean {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
436
|
+
if (!enable) {
|
|
437
|
+
observer?.disconnect();
|
|
438
|
+
observer = null;
|
|
439
|
+
return autoloadEnabled;
|
|
440
|
+
}
|
|
442
441
|
|
|
443
|
-
|
|
444
|
-
|
|
442
|
+
autoloadEnabled = enable;
|
|
443
|
+
observer = new MutationObserver(loadUndefinedMCs);
|
|
445
444
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
445
|
+
setTimeout(() => {
|
|
446
|
+
observer!.observe(document.body, { childList: true, subtree: true });
|
|
447
|
+
loadUndefinedMCs();
|
|
448
|
+
}, 5);
|
|
450
449
|
|
|
451
|
-
|
|
450
|
+
(window as LooseObject).autoload = (window as LooseObject).autoload || autoload;
|
|
452
451
|
|
|
453
|
-
|
|
452
|
+
return autoloadEnabled;
|
|
454
453
|
}
|
|
455
454
|
|
|
456
455
|
(autoload as LooseObject).state = loadingDCs;
|