@twobirds/microcomponents 0.0.33 → 0.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -27
- package/assets/documentation/{MicroComponents.md → MC.md} +17 -17
- package/assets/documentation/comparision.md +0 -0
- package/assets/documentation/elements.md +276 -0
- package/assets/documentation/magic.md +10 -68
- package/dist/MC.d.ts +2 -3
- package/dist/MC.d.ts.map +1 -1
- package/dist/MC.min.js +45 -43
- package/dist/MC.ts +173 -175
- package/dist/autoloader.ts +1 -1
- package/dist/{customElements.d.ts → elements.d.ts} +1 -1
- package/dist/elements.d.ts.map +1 -0
- package/dist/elements.min.js +1 -0
- package/dist/{customElements.ts → elements.ts} +23 -14
- package/dist/helpers.d.ts +6 -4
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.ts +95 -128
- package/dist/microcomponents.d.ts +3 -3
- package/dist/microcomponents.d.ts.map +1 -1
- package/dist/microcomponents.min.js +1 -1
- package/dist/microcomponents.ts +3 -3
- package/dist/{customObservables.d.ts → observables.d.ts} +3 -3
- package/dist/observables.d.ts.map +1 -0
- package/dist/observables.min.js +1 -0
- package/dist/observables.ts +354 -0
- package/dist/{customSelectors.d.ts → selectors.d.ts} +1 -1
- package/dist/selectors.d.ts.map +1 -0
- package/dist/selectors.min.js +1 -0
- package/dist/test.ts +133 -157
- package/klemmstein.png +0 -0
- package/package.json +52 -52
- package/public/MC.js +46 -44
- package/public/MC.js.map +1 -1
- package/public/MC.min.js +45 -43
- package/public/assets/search.js +1 -1
- package/public/autoloader.js +1 -1
- package/public/autoloader.js.map +1 -1
- package/public/classes/{DC.html → MC.DC.html} +60 -59
- package/public/classes/{MC.html → MC.MC.html} +41 -35
- package/public/classes/{McBase.html → MC.McBase.html} +28 -20
- package/public/classes/{McEvent.html → MC.McEvent.html} +48 -42
- package/public/documentation/{MicroComponents.md → MC.md} +17 -17
- package/public/documentation/comparision.md +0 -0
- package/public/documentation/elements.md +276 -0
- package/public/documentation/magic.md +10 -68
- package/public/{customElements.js → elements.js} +9 -10
- package/public/elements.js.map +1 -0
- package/public/elements.min.js +1 -0
- package/public/functions/{addListener.html → MC.addListener.html} +18 -12
- package/public/functions/{removeListener.html → MC.removeListener.html} +18 -12
- package/public/functions/elements.defineCE.html +78 -0
- package/public/functions/elements.getCE.html +63 -0
- package/public/functions/formValues.formValues.html +68 -0
- package/public/functions/observables.observe.html +65 -0
- package/public/functions/selectors._d.html +69 -0
- package/public/functions/selectors._t.html +69 -0
- package/public/helpers.js +66 -89
- package/public/helpers.js.map +1 -1
- package/public/index.html +48 -33
- package/public/interfaces/{HTMLMcElement.html → MC.HTMLMcElement.html} +601 -595
- package/public/interfaces/selectors.DSelector.html +1013 -0
- package/public/interfaces/selectors.TSelector.html +712 -0
- package/public/microcomponents.js +3 -3
- package/public/microcomponents.js.map +1 -1
- package/public/microcomponents.min.js +1 -1
- package/public/modules/MC.html +78 -0
- package/public/modules/elements.html +62 -0
- package/public/modules/formValues.html +60 -0
- package/public/modules/observables.html +65 -0
- package/public/modules/selectors.html +76 -0
- package/public/modules.html +11 -23
- package/public/observables.js +255 -0
- package/public/observables.js.map +1 -0
- package/public/observables.min.js +1 -0
- package/public/{customSelectors.js → selectors.js} +1 -1
- package/public/selectors.js.map +1 -0
- package/public/selectors.min.js +1 -0
- package/public/src/MC.ts +376 -0
- package/public/src/McEvent.ts +96 -0
- package/public/src/autoloader.ts +98 -0
- package/{src/customElements.ts → public/src/elements.ts} +23 -14
- package/public/src/formValues.ts +275 -0
- package/public/src/helpers.ts +140 -0
- package/public/src/microcomponents.ts +8 -0
- package/public/src/observables.ts +354 -0
- package/public/src/test.ts +187 -0
- package/public/test.js +99 -115
- package/public/test.js.map +1 -1
- package/public/types/observables.Observable.html +91 -0
- package/public/types/selectors.selection.html +58 -0
- package/public/types/selectors.singleSelector.html +58 -0
- package/src/MC.ts +173 -175
- package/src/autoloader.ts +1 -1
- package/src/elements.ts +76 -0
- package/src/helpers.ts +95 -128
- package/src/microcomponents.ts +3 -3
- package/src/observables.ts +354 -0
- package/src/selectors.ts +1634 -0
- package/src/test.ts +133 -157
- package/typedoc.json +1 -1
- package/webpack.config.js +9 -9
- package/dist/customElements.d.ts.map +0 -1
- package/dist/customElements.min.js +0 -1
- package/dist/customObservables.d.ts.map +0 -1
- package/dist/customObservables.min.js +0 -1
- package/dist/customObservables.ts +0 -348
- package/dist/customSelectors.d.ts.map +0 -1
- package/dist/customSelectors.min.js +0 -1
- package/public/customElements.js.map +0 -1
- package/public/customElements.min.js +0 -1
- package/public/customObservables.js +0 -256
- package/public/customObservables.js.map +0 -1
- package/public/customObservables.min.js +0 -1
- package/public/customSelectors.js.map +0 -1
- package/public/customSelectors.min.js +0 -1
- package/src/customObservables.ts +0 -348
- /package/dist/{customSelectors.ts → selectors.ts} +0 -0
- /package/{src/customSelectors.ts → public/src/selectors.ts} +0 -0
package/public/src/MC.ts
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import { LooseObject } from './helpers.js';
|
|
4
|
+
import { McEvent } from './McEvent.js';
|
|
5
|
+
|
|
6
|
+
var isBrowser = new Function(
|
|
7
|
+
'try {return this===window;}catch(e){ return false;}'
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
let nativeEventNames: Set<string> = new Set();
|
|
11
|
+
|
|
12
|
+
// HTMLElement native event names
|
|
13
|
+
if (isBrowser()) {
|
|
14
|
+
Object.keys(HTMLElement.prototype)
|
|
15
|
+
.filter((key) => /^on/.test(key))
|
|
16
|
+
.forEach((eventName) => nativeEventNames.add(eventName));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface HTMLMcElement extends HTMLElement {
|
|
20
|
+
_mc: LooseObject;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// get all microcomponents from a list of HTMLElements
|
|
24
|
+
function getMicroComponents(elements: any[], search: string): any[] {
|
|
25
|
+
let mcValues: any[] = [];
|
|
26
|
+
|
|
27
|
+
elements.forEach((e) => {
|
|
28
|
+
if (e) {
|
|
29
|
+
if (e instanceof HTMLElement) {
|
|
30
|
+
const _mc = (e as any)?._mc;
|
|
31
|
+
if (!search && _mc) {
|
|
32
|
+
mcValues = mcValues.concat(Object.values((e as any)._mc));
|
|
33
|
+
} else if (search && _mc && _mc[search]) {
|
|
34
|
+
mcValues.push(_mc[search]);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return mcValues;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// get all ancestor DOM nodes up to the document root
|
|
43
|
+
function traverseNodes(
|
|
44
|
+
node: { [key: string]: any },
|
|
45
|
+
search: string,
|
|
46
|
+
firstonly = true
|
|
47
|
+
): any[] {
|
|
48
|
+
let mcValues: any[] = [];
|
|
49
|
+
while (node) {
|
|
50
|
+
if (node._mc) {
|
|
51
|
+
if (!search) {
|
|
52
|
+
mcValues = mcValues.concat(Object.values(node._mc));
|
|
53
|
+
} else if (search && node._mc[search]) {
|
|
54
|
+
mcValues.push(node._mc[search]);
|
|
55
|
+
}
|
|
56
|
+
if (firstonly) return mcValues;
|
|
57
|
+
}
|
|
58
|
+
node = node.parentNode;
|
|
59
|
+
}
|
|
60
|
+
return mcValues;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isDOM(element: { [key: string]: any }) {
|
|
64
|
+
return element && element instanceof HTMLElement;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function addListener(
|
|
68
|
+
domNode: Node,
|
|
69
|
+
eventName: string,
|
|
70
|
+
handler: EventListenerOrEventListenerObject | null,
|
|
71
|
+
capture: boolean = false,
|
|
72
|
+
once: boolean = false
|
|
73
|
+
) {
|
|
74
|
+
let options: EventListenerOptions & { once: boolean } = { once: false };
|
|
75
|
+
if (capture) {
|
|
76
|
+
options.capture = capture;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (once) {
|
|
80
|
+
options.once = once;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
//console.log( 'addEventListener', eventName, ( handler as Function ).name, options );
|
|
84
|
+
domNode.addEventListener(eventName, handler, options);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function removeListener(
|
|
88
|
+
domNode: Node,
|
|
89
|
+
eventName: string,
|
|
90
|
+
handler: EventListenerOrEventListenerObject | null
|
|
91
|
+
) {
|
|
92
|
+
domNode.removeEventListener(eventName, handler);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// add a microcomponent to a target DOM node
|
|
96
|
+
function add(target: HTMLElement, key: string, element = {}): any {
|
|
97
|
+
let node = target as HTMLMcElement;
|
|
98
|
+
|
|
99
|
+
// create the _mc property if necessary
|
|
100
|
+
if (!node._mc) {
|
|
101
|
+
let debug = (DC as any)?.debug;
|
|
102
|
+
(DC as any).debug = false;
|
|
103
|
+
node._mc = new (DC as any)(target);
|
|
104
|
+
(DC as any).debug = debug;
|
|
105
|
+
delete node._mc._mc; // NOT NEEDED on the top level _mc property of a DOM HTMLElement
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const _mc = node._mc;
|
|
109
|
+
|
|
110
|
+
// add the element with the given property key to the _mc property
|
|
111
|
+
if (key.length && !_mc[key]) {
|
|
112
|
+
_mc[key] = element;
|
|
113
|
+
// add attribute if HTMLElement
|
|
114
|
+
if (target instanceof HTMLElement) {
|
|
115
|
+
target.setAttribute('_mc', '');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return element;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// remove a micro component from the DOM
|
|
122
|
+
function remove(target: HTMLMcElement, key: string) {
|
|
123
|
+
if (!key) return; // silent fail
|
|
124
|
+
|
|
125
|
+
const _mc = target?._mc || {};
|
|
126
|
+
|
|
127
|
+
// delete the property from the HTMLElement _mc collection
|
|
128
|
+
if (_mc && _mc[key]) {
|
|
129
|
+
delete _mc[key];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// remove the _mc attribute if the DOM collection is empty
|
|
133
|
+
if (
|
|
134
|
+
!Object.keys(_mc).length &&
|
|
135
|
+
target instanceof HTMLElement &&
|
|
136
|
+
target.hasAttribute('_mc')
|
|
137
|
+
) {
|
|
138
|
+
target.removeAttribute('_mc');
|
|
139
|
+
}
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// trigger an event
|
|
144
|
+
function trigger(target: unknown, ev: McEvent | string, data: any = {}) {
|
|
145
|
+
let _mc = (target as any)?._mc;
|
|
146
|
+
if (!_mc) return;
|
|
147
|
+
[...Object.values(_mc)].forEach((mc: any) => {
|
|
148
|
+
//console.log( 'mc [', mc.constructor.name, ']', mc.constructor.prototype?.oneInit );
|
|
149
|
+
if ((mc as any)?.trigger && typeof (mc as any)?.trigger === 'function') {
|
|
150
|
+
(mc as any)?.trigger(ev, data);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// run the "init" lifecycle event on the complete _mc structure
|
|
157
|
+
function init(element: MC | DC) {
|
|
158
|
+
if (element.constructor === DC) return;
|
|
159
|
+
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
element.trigger('Init');
|
|
162
|
+
/*
|
|
163
|
+
let keys = Object.keys( ( element as any)?._mc );
|
|
164
|
+
if ( keys.length ){
|
|
165
|
+
//console.log( 'inner Inits on [', mc.constructor.name, ']', keys );
|
|
166
|
+
keys?.forEach( (key: string) => {
|
|
167
|
+
let mc = ( element as any)?._mc?.[key];
|
|
168
|
+
//console.log( key, typeof mc?.oneInit, mc );
|
|
169
|
+
if ( ( mc as any )['oneInit'] && typeof ( mc as any ).oneInit == 'function' ){
|
|
170
|
+
( mc as any ).oneInit( new McEvent('Init') );
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
};
|
|
174
|
+
*/
|
|
175
|
+
}, 0);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function autoAttachListeners(element: MC | DC) {
|
|
179
|
+
if (!isBrowser() || element.constructor === DC) return;
|
|
180
|
+
|
|
181
|
+
const target = element.target;
|
|
182
|
+
|
|
183
|
+
if (target instanceof HTMLElement) {
|
|
184
|
+
let that: LooseObject = element;
|
|
185
|
+
Object.getOwnPropertyNames(that.constructor.prototype)
|
|
186
|
+
.filter(
|
|
187
|
+
(key) =>
|
|
188
|
+
/^on[A-Z]|one[A-Z]/.test(key) &&
|
|
189
|
+
typeof that.constructor.prototype[key] === 'function'
|
|
190
|
+
)
|
|
191
|
+
.forEach((key) => {
|
|
192
|
+
let once = /^one/.test(key),
|
|
193
|
+
withoutOnOne = key.replace(/^on[e]{0,1}/, ''), // preserves upper/lowercase for non-native events
|
|
194
|
+
nativeEventName = withoutOnOne.toLowerCase(),
|
|
195
|
+
listener = (ev: McEvent | Event | CustomEvent) => {
|
|
196
|
+
that.trigger(withoutOnOne, ev);
|
|
197
|
+
};
|
|
198
|
+
if (once) {
|
|
199
|
+
// console.log( '...is only called once', that.constructor.prototype[key] );
|
|
200
|
+
Object.defineProperty(element, 'on' + withoutOnOne, {
|
|
201
|
+
configurable: true,
|
|
202
|
+
enumerable: false,
|
|
203
|
+
writable: true,
|
|
204
|
+
value: (ev: any) => {
|
|
205
|
+
// console.log( 'onceHandler execute:', that.constructor.prototype[key] );
|
|
206
|
+
that.constructor.prototype[key].bind(that)(ev);
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (nativeEventNames.has('on' + nativeEventName)) {
|
|
212
|
+
// native event defined in HTMLElement
|
|
213
|
+
// console.log('added as native listener', target, nativeEventName );
|
|
214
|
+
addListener(target, nativeEventName, listener, false, once);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
class McBase {
|
|
221
|
+
#target: WeakRef<any>; // avoid circular reference
|
|
222
|
+
|
|
223
|
+
constructor(target?: { [key: string]: any }, debug: boolean = false) {
|
|
224
|
+
let that: unknown = this,
|
|
225
|
+
element = that as MC | DC;
|
|
226
|
+
|
|
227
|
+
this.#target = new WeakRef(target || {});
|
|
228
|
+
|
|
229
|
+
init(element); // async lifecycle event
|
|
230
|
+
|
|
231
|
+
autoAttachListeners(element);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
get target(): any {
|
|
235
|
+
return this.#target.deref();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
class MC extends McBase {
|
|
240
|
+
_mc: { [key: string]: any } = {};
|
|
241
|
+
|
|
242
|
+
constructor(target?: any) {
|
|
243
|
+
super(target);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
static trigger = trigger;
|
|
247
|
+
|
|
248
|
+
trigger(ev: McEvent | string, data: any = {}, bubble?: string) {
|
|
249
|
+
let that = this;
|
|
250
|
+
|
|
251
|
+
//console.log( that, '.trigger(', ev, data, bubble, ')' );
|
|
252
|
+
bubble = bubble || 'l';
|
|
253
|
+
|
|
254
|
+
// run all triggers
|
|
255
|
+
if (that.constructor === MC || that.constructor === DC) {
|
|
256
|
+
[...Object.getOwnPropertyNames(that)].forEach((mc) => {
|
|
257
|
+
if (
|
|
258
|
+
(that as any)[mc]?.trigger &&
|
|
259
|
+
typeof (that as any)[mc]?.trigger === 'function'
|
|
260
|
+
) {
|
|
261
|
+
(that as any)[mc]?.trigger(ev, data, bubble);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
return; // must return here!
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// only this instance
|
|
268
|
+
if ((that as any) instanceof MC || (that as any) instanceof DC) {
|
|
269
|
+
const that = this,
|
|
270
|
+
mcEvent: McEvent =
|
|
271
|
+
typeof ev !== 'string'
|
|
272
|
+
? (ev as McEvent)
|
|
273
|
+
: new McEvent(ev, data, bubble),
|
|
274
|
+
handlerName =
|
|
275
|
+
'on' + mcEvent.type[0].toUpperCase() + mcEvent.type.slice(1);
|
|
276
|
+
// console.log('trigger', handlerName, mcEvent, data, bubble );
|
|
277
|
+
|
|
278
|
+
if (mcEvent.bubble.indexOf('l') > -1) {
|
|
279
|
+
if (
|
|
280
|
+
!mcEvent.immediateStopped &&
|
|
281
|
+
typeof (that as any)[handlerName] === 'function'
|
|
282
|
+
) {
|
|
283
|
+
// console.log( 'execute handler:', handlerName );
|
|
284
|
+
(that as any)[handlerName](mcEvent);
|
|
285
|
+
if ((that as any).hasOwnProperty(handlerName)) {
|
|
286
|
+
// it is a once handler
|
|
287
|
+
delete (that as any)[handlerName]; // remove after first execution
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// if event stopped or local only, handling is cancelled
|
|
293
|
+
if (mcEvent.stopped || mcEvent.bubble === 'l') {
|
|
294
|
+
return that;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// at this point, either 'u' or 'd' bubbling should be indicated
|
|
298
|
+
// mcEvent bubbling is asynchronous, and the order of target MC execution in case of multiple matches is not guaranteed!
|
|
299
|
+
if (
|
|
300
|
+
isBrowser() &&
|
|
301
|
+
/[ud]/.test(mcEvent.bubble) &&
|
|
302
|
+
(that as any) instanceof MC
|
|
303
|
+
) {
|
|
304
|
+
setTimeout(() => {
|
|
305
|
+
// bubbling must include 'l' for local, or else no handlers are executed'
|
|
306
|
+
if (mcEvent.bubble.indexOf('l') === -1) {
|
|
307
|
+
mcEvent.bubble += 'l';
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// bubble up towards root
|
|
311
|
+
if (mcEvent.bubble.indexOf('u') > -1) {
|
|
312
|
+
(that as any).parent().forEach((mc: any) => {
|
|
313
|
+
mc instanceof MC ? (mc as any).trigger(mcEvent) : null;
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// bubble down
|
|
318
|
+
if (mcEvent.bubble.indexOf('d') > -1) {
|
|
319
|
+
(that as any).children().forEach((mc: any) => {
|
|
320
|
+
mc instanceof MC ? (mc as any).trigger(mcEvent) : null;
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}, 0);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
class DC extends McBase {
|
|
330
|
+
_mc: { [key: string]: any } = {};
|
|
331
|
+
|
|
332
|
+
constructor(target: HTMLElement, debug: boolean = false) {
|
|
333
|
+
super(target);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
static add: Function = add;
|
|
337
|
+
static remove: Function = remove;
|
|
338
|
+
static trigger: Function = trigger;
|
|
339
|
+
|
|
340
|
+
trigger(ev: McEvent | string, data: any = {}, bubble?: string) {
|
|
341
|
+
MC.prototype.trigger.call(this, ev, data, bubble);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
parent(search: string = ''): any[] {
|
|
345
|
+
let target: HTMLElement = (this as any).target;
|
|
346
|
+
if (!isDOM(target)) return [];
|
|
347
|
+
return traverseNodes((target as any).parentNode, search, true);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
ancestors(search: string = ''): any[] {
|
|
351
|
+
let target: any = (this as any)?.target;
|
|
352
|
+
if (!isDOM(target)) return [];
|
|
353
|
+
return traverseNodes((this as any).target.parentNode, search, false);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
children(search: string = ''): any[] {
|
|
357
|
+
let target: any = (this as any)?.target;
|
|
358
|
+
if (!isDOM(target)) return [];
|
|
359
|
+
const id = Math.random().toString().replace('.', '');
|
|
360
|
+
const selector = '[_mc]:not([temp_id="' + id + '"] [_mc] [_mc])';
|
|
361
|
+
target.setAttribute('temp_id', id);
|
|
362
|
+
const myDomElements = target.querySelectorAll(selector);
|
|
363
|
+
const mcValues = getMicroComponents([...myDomElements], search);
|
|
364
|
+
target.removeAttribute('temp_id');
|
|
365
|
+
return mcValues;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
descendants(search: string = ''): any[] {
|
|
369
|
+
let target: any = (this as any)?.target;
|
|
370
|
+
if (!isDOM(target)) return [];
|
|
371
|
+
const myDomElements = target.querySelectorAll('*[_mc]');
|
|
372
|
+
return getMicroComponents([...myDomElements], search);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export { addListener, removeListener, McBase, MC, DC, McEvent };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var isBrowser=new Function("try {return this===window;}catch(e){ return false;}");
|
|
4
|
+
|
|
5
|
+
let nativeEventNames: Set<string> = new Set();
|
|
6
|
+
|
|
7
|
+
// HTMLElement native event names
|
|
8
|
+
if ( isBrowser() ){
|
|
9
|
+
Object.keys( HTMLElement.prototype ).filter( key => /^on/.test(key) ).forEach( eventName => nativeEventNames.add( eventName ) );
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function isDOM(element: { [key:string]: any } ) {
|
|
13
|
+
return element && element instanceof HTMLElement;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface McEvent {
|
|
17
|
+
data: any;
|
|
18
|
+
bubble: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class McEvent{
|
|
22
|
+
|
|
23
|
+
#type: string;
|
|
24
|
+
#stopped: boolean = false;
|
|
25
|
+
#immediateStopped: boolean = false;
|
|
26
|
+
|
|
27
|
+
constructor( type: string, data: any = {}, bubble: string = 'l' ){
|
|
28
|
+
// bubble standard = local only, options = any combination of'uld' characters: up to root, local, down
|
|
29
|
+
this.#type = type;
|
|
30
|
+
this.data = data;
|
|
31
|
+
this.bubble = bubble;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get type(): string {
|
|
35
|
+
return this.#type;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get stopped(): boolean {
|
|
39
|
+
return this.#stopped;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get immediateStopped(): boolean {
|
|
43
|
+
return this.#immediateStopped;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
stopPropagation(){
|
|
47
|
+
this.#stopped = true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
stopImmediatePropagation(){
|
|
51
|
+
this.stopPropagation();
|
|
52
|
+
this.#immediateStopped = true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// get all microcomponents from a list of HTMLElements
|
|
58
|
+
function getMicroComponents( elements: any[], search: string): any[] {
|
|
59
|
+
let mcValues: any[] = [];
|
|
60
|
+
|
|
61
|
+
elements.forEach( e => {
|
|
62
|
+
if (e) {
|
|
63
|
+
if (e instanceof HTMLElement) {
|
|
64
|
+
const _mc = ( e as any )?._mc;
|
|
65
|
+
if ( !search && _mc ) {
|
|
66
|
+
mcValues = mcValues.concat(Object.values(( e as any )._mc));
|
|
67
|
+
}
|
|
68
|
+
else if ( search && _mc && _mc[search] ) {
|
|
69
|
+
mcValues.push( _mc[search] );
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return mcValues;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// get all ancestor DOM nodes up to the document root
|
|
78
|
+
function traverseNodes(node: { [key:string]: any }, search: string, firstonly = true): any[] {
|
|
79
|
+
let mcValues: any[] = [];
|
|
80
|
+
while (node) {
|
|
81
|
+
if (node._mc) {
|
|
82
|
+
if (!search) {
|
|
83
|
+
mcValues = mcValues.concat(Object.values(node._mc));
|
|
84
|
+
}
|
|
85
|
+
else if (search && node._mc[search]) {
|
|
86
|
+
mcValues.push(node._mc[search]);
|
|
87
|
+
}
|
|
88
|
+
if (firstonly)
|
|
89
|
+
return mcValues;
|
|
90
|
+
}
|
|
91
|
+
node = node.parentNode;
|
|
92
|
+
}
|
|
93
|
+
return mcValues;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { McEvent };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { getCE } from './elements.js'
|
|
4
|
+
|
|
5
|
+
// set of currently loading scripts
|
|
6
|
+
const loadingScripts: Set<string> = new Set();
|
|
7
|
+
|
|
8
|
+
const _makeLoadData = ( e: HTMLElement ): Array<any> | false => {
|
|
9
|
+
|
|
10
|
+
let
|
|
11
|
+
tagName = e?.localName ?? '',
|
|
12
|
+
isAttribute = e.getAttribute?.('is') || '',
|
|
13
|
+
isUBE = isAttribute ? true : false,
|
|
14
|
+
isCE = tagName.indexOf('-') !== -1 ? true : false,
|
|
15
|
+
ubeSelector = isUBE ? `${tagName}[is=\"${isAttribute}\"]:defined` : '',
|
|
16
|
+
ceSelector = isCE ? tagName + ':defined' : '',
|
|
17
|
+
fileBaseName = isUBE
|
|
18
|
+
? isAttribute
|
|
19
|
+
: isCE
|
|
20
|
+
? tagName
|
|
21
|
+
: '',
|
|
22
|
+
fileName = fileBaseName.length ? '/' + fileBaseName.split('-').join('/') + '.js' : '',
|
|
23
|
+
selector = isUBE
|
|
24
|
+
? ubeSelector
|
|
25
|
+
: isCE
|
|
26
|
+
? ceSelector
|
|
27
|
+
: ''
|
|
28
|
+
;
|
|
29
|
+
|
|
30
|
+
//console.log( 'makeLoadData()', tagName, isUBE, isCE, ubeSelector, ceSelector, fileBaseName, ' => ', (isUBE || isCE) ? [ e, selector, fileName ] : false );
|
|
31
|
+
return (isUBE || isCE) ? [ e, selector, fileName, fileBaseName ] : false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const _loadRequirements = ( node: HTMLTemplateElement | HTMLElement ): Promise<any> => {
|
|
35
|
+
|
|
36
|
+
let
|
|
37
|
+
undefinedSet: Set<any> = new Set(),
|
|
38
|
+
element: any = node instanceof HTMLTemplateElement ? (node as HTMLTemplateElement).content : node,
|
|
39
|
+
head = document.head,
|
|
40
|
+
allPromises: Array<any> = [],
|
|
41
|
+
e: HTMLElement;
|
|
42
|
+
;
|
|
43
|
+
|
|
44
|
+
if ( element instanceof HTMLTemplateElement === false ){
|
|
45
|
+
// if node itself is undefined
|
|
46
|
+
let data: any = _makeLoadData(element);
|
|
47
|
+
|
|
48
|
+
if ( data && !data[0].matches( data[1] ) ){
|
|
49
|
+
undefinedSet.add( data );
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// if some of the childNodes are undefined
|
|
54
|
+
Array.from( element.childNodes ).forEach(( node )=>{
|
|
55
|
+
let data: any = _makeLoadData(node as HTMLElement);
|
|
56
|
+
|
|
57
|
+
if ( data && !data[0].matches( data[1] ) ){
|
|
58
|
+
undefinedSet.add( data );
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if ( !!undefinedSet.size ){ // there are requirements
|
|
63
|
+
|
|
64
|
+
undefinedSet.forEach( (data) => {
|
|
65
|
+
if ( !getCE( data[3] ) && !loadingScripts.has( data[2]) ){
|
|
66
|
+
|
|
67
|
+
loadingScripts.add( data[2] );
|
|
68
|
+
|
|
69
|
+
const se: HTMLScriptElement = document.createElement('script');
|
|
70
|
+
|
|
71
|
+
se.setAttribute( 'src', data[2] );
|
|
72
|
+
se.setAttribute( 'blocking', 'render' );
|
|
73
|
+
se.setAttribute( 'type', 'module' );
|
|
74
|
+
let s = (data as any)[2];
|
|
75
|
+
se.onload = () => {
|
|
76
|
+
// console.info('loaded', s);
|
|
77
|
+
loadingScripts.delete( s );
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
head.append( se );
|
|
81
|
+
|
|
82
|
+
let e = (data as Array<any>)[0];
|
|
83
|
+
} else {
|
|
84
|
+
return ;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return Promise.all( allPromises );
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
TBD
|
|
95
|
+
if ( template.content.childNodes.length ){
|
|
96
|
+
_loadRequirements(template);
|
|
97
|
+
}
|
|
98
|
+
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { DC } from
|
|
4
|
-
import { kebabToPascal } from
|
|
3
|
+
import { DC } from "./MC.js";
|
|
4
|
+
import { kebabToPascal } from "./helpers.js";
|
|
5
5
|
|
|
6
6
|
class CeBaseClass extends HTMLElement {
|
|
7
7
|
constructor() {
|
|
@@ -9,34 +9,43 @@ class CeBaseClass extends HTMLElement {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
connectedCallback() {
|
|
12
|
-
(DC as any).trigger(this,
|
|
12
|
+
(DC as any).trigger(this, "Connected");
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
disconnectedCallback() {
|
|
16
|
-
(DC as any).trigger(this,
|
|
16
|
+
(DC as any).trigger(this, "Disconnected");
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
adoptedCallback() {
|
|
20
|
-
(DC as any).trigger(this,
|
|
20
|
+
(DC as any).trigger(this, "Adopted");
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
attributeChangedCallback(name: string, oldValue: any, newValue: any) {
|
|
24
|
-
(DC as any).trigger(this,
|
|
24
|
+
(DC as any).trigger(this, "AttributeChanged", { name, oldValue, newValue });
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
function createNamedClass(
|
|
29
|
-
|
|
28
|
+
function createNamedClass(
|
|
29
|
+
name: string,
|
|
30
|
+
ClassBody: { new (...args: any[]): any }
|
|
31
|
+
) {
|
|
32
|
+
return Object.defineProperty(ClassBody, "name", { value: name });
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
export function defineCE(
|
|
35
|
+
export function defineCE(
|
|
36
|
+
tagName: string,
|
|
37
|
+
DefinitionClass: { new (...args: any[]): any },
|
|
38
|
+
observedAttributes: string[] = []
|
|
39
|
+
) {
|
|
33
40
|
if (customElements.get(tagName)) {
|
|
34
41
|
console.warn(`IGNORED: Custom element "${tagName}" is already defined!`);
|
|
35
42
|
return;
|
|
36
43
|
}
|
|
37
44
|
|
|
38
|
-
if (!tagName.includes(
|
|
39
|
-
throw new Error(
|
|
45
|
+
if (!tagName.includes("-")) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
'createCustomElement: tagName must contain at least one hyphen ("-").'
|
|
48
|
+
);
|
|
40
49
|
}
|
|
41
50
|
|
|
42
51
|
let name = kebabToPascal(tagName);
|
|
@@ -48,10 +57,10 @@ export function defineCE( tagName: string, DefinitionClass: { new (...args: any[
|
|
|
48
57
|
class extends CeBaseClass {
|
|
49
58
|
instance: any;
|
|
50
59
|
|
|
51
|
-
constructor(
|
|
60
|
+
constructor(data?: any) {
|
|
52
61
|
super();
|
|
53
62
|
let instance = new DefinitionClass(this, data);
|
|
54
|
-
(
|
|
63
|
+
(DC as any).add(this, name, instance);
|
|
55
64
|
}
|
|
56
65
|
|
|
57
66
|
static get observedAttributes() {
|
|
@@ -60,7 +69,7 @@ export function defineCE( tagName: string, DefinitionClass: { new (...args: any[
|
|
|
60
69
|
}
|
|
61
70
|
)
|
|
62
71
|
);
|
|
63
|
-
}
|
|
72
|
+
}
|
|
64
73
|
|
|
65
74
|
export function getCE(tagName: string): CustomElementConstructor | undefined {
|
|
66
75
|
return customElements.get(tagName);
|