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