@twobirds/microcomponents 0.0.83 → 0.0.85

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.
Files changed (202) hide show
  1. package/README.md +22 -6
  2. package/assets/documentation/MC.md +60 -81
  3. package/assets/documentation/elements.md +6 -9
  4. package/assets/documentation/observables.md +97 -11
  5. package/assets/test/test.html +1 -1
  6. package/dist/MC.d.ts +14 -16
  7. package/dist/MC.d.ts.map +1 -1
  8. package/dist/MC.js +150 -218
  9. package/dist/MC.min.js +164 -308
  10. package/dist/MC.ts +213 -319
  11. package/dist/elements.d.ts.map +1 -1
  12. package/dist/elements.js +10 -4
  13. package/dist/elements.min.js +1 -1
  14. package/dist/elements.ts +17 -4
  15. package/dist/formValues.js +2 -2
  16. package/dist/formValues.min.js +1 -1
  17. package/dist/formValues.ts +3 -3
  18. package/dist/microcomponents.d.ts +0 -1
  19. package/dist/microcomponents.d.ts.map +1 -1
  20. package/dist/microcomponents.js +0 -1
  21. package/dist/microcomponents.min.js +1 -1
  22. package/dist/microcomponents.ts +1 -1
  23. package/dist/observables.d.ts.map +1 -1
  24. package/dist/observables.js +14 -12
  25. package/dist/observables.min.js +1 -1
  26. package/dist/observables.ts +32 -32
  27. package/package.json +1 -1
  28. package/public/MC.d.ts +14 -16
  29. package/public/MC.d.ts.map +1 -1
  30. package/public/MC.js +150 -218
  31. package/public/MC.js.map +1 -1
  32. package/public/MC.min.js +164 -308
  33. package/public/MC.ts +213 -319
  34. package/public/documentation/MC.md +60 -81
  35. package/public/documentation/elements.md +6 -9
  36. package/public/documentation/observables.md +97 -11
  37. package/public/elements.d.ts.map +1 -1
  38. package/public/elements.js +10 -4
  39. package/public/elements.js.map +1 -1
  40. package/public/elements.min.js +1 -1
  41. package/public/elements.ts +17 -4
  42. package/public/formValues.js +2 -2
  43. package/public/formValues.js.map +1 -1
  44. package/public/formValues.min.js +1 -1
  45. package/public/formValues.ts +3 -3
  46. package/public/microcomponents.d.ts +0 -1
  47. package/public/microcomponents.d.ts.map +1 -1
  48. package/public/microcomponents.js +0 -1
  49. package/public/microcomponents.js.map +1 -1
  50. package/public/microcomponents.min.js +1 -1
  51. package/public/microcomponents.ts +1 -1
  52. package/public/observables.d.ts.map +1 -1
  53. package/public/observables.js +14 -12
  54. package/public/observables.js.map +1 -1
  55. package/public/observables.min.js +1 -1
  56. package/public/observables.ts +32 -32
  57. package/public/src/MC.d.ts +14 -16
  58. package/public/src/MC.d.ts.map +1 -1
  59. package/public/src/MC.js +150 -218
  60. package/public/src/MC.js.map +1 -1
  61. package/public/src/MC.ts +213 -319
  62. package/public/src/elements.d.ts.map +1 -1
  63. package/public/src/elements.js +10 -4
  64. package/public/src/elements.js.map +1 -1
  65. package/public/src/elements.ts +17 -4
  66. package/public/src/formValues.js +2 -2
  67. package/public/src/formValues.js.map +1 -1
  68. package/public/src/formValues.ts +3 -3
  69. package/public/src/microcomponents.d.ts +0 -1
  70. package/public/src/microcomponents.d.ts.map +1 -1
  71. package/public/src/microcomponents.js +0 -1
  72. package/public/src/microcomponents.js.map +1 -1
  73. package/public/src/microcomponents.ts +1 -1
  74. package/public/src/observables.d.ts.map +1 -1
  75. package/public/src/observables.js +14 -12
  76. package/public/src/observables.js.map +1 -1
  77. package/public/src/observables.ts +32 -32
  78. package/public/src/test/test/grandparent.d.ts.map +1 -1
  79. package/public/src/test/test/grandparent.js +1 -1
  80. package/public/src/test/test/grandparent.js.map +1 -1
  81. package/public/src/test/test/grandparent.ts +12 -4
  82. package/public/src/test/test/testform.js +1 -1
  83. package/public/src/test/test/testform.js.map +1 -1
  84. package/public/src/test/test/testform.ts +6 -8
  85. package/public/src/test/test.js +6 -5
  86. package/public/src/test/test.js.map +1 -1
  87. package/public/src/test/test.ts +10 -9
  88. package/public/test/MC.d.ts +14 -16
  89. package/public/test/MC.d.ts.map +1 -1
  90. package/public/test/MC.js +150 -218
  91. package/public/test/MC.min.js +164 -308
  92. package/public/test/MC.ts +213 -319
  93. package/public/test/elements.d.ts.map +1 -1
  94. package/public/test/elements.js +10 -4
  95. package/public/test/elements.min.js +1 -1
  96. package/public/test/elements.ts +17 -4
  97. package/public/test/formValues.js +2 -2
  98. package/public/test/formValues.min.js +1 -1
  99. package/public/test/formValues.ts +3 -3
  100. package/public/test/microcomponents.d.ts +0 -1
  101. package/public/test/microcomponents.d.ts.map +1 -1
  102. package/public/test/microcomponents.js +0 -1
  103. package/public/test/microcomponents.min.js +1 -1
  104. package/public/test/microcomponents.ts +1 -1
  105. package/public/test/observables.d.ts.map +1 -1
  106. package/public/test/observables.js +14 -12
  107. package/public/test/observables.min.js +1 -1
  108. package/public/test/observables.ts +32 -32
  109. package/public/test/test/grandparent.d.ts.map +1 -1
  110. package/public/test/test/grandparent.js +1 -1
  111. package/public/test/test/grandparent.js.map +1 -1
  112. package/public/test/test/grandparent.ts +12 -4
  113. package/public/test/test/testform.js +1 -1
  114. package/public/test/test/testform.js.map +1 -1
  115. package/public/test/test/testform.ts +6 -8
  116. package/public/test/test.html +1 -1
  117. package/public/test/test.js +6 -5
  118. package/public/test/test.js.map +1 -1
  119. package/public/test/test.ts +10 -9
  120. package/public/typedoc/assets/navigation.js +1 -1
  121. package/public/typedoc/assets/search.js +1 -1
  122. package/public/typedoc/classes/MC.DC.html +7 -6
  123. package/public/typedoc/classes/MC.MC.html +3 -6
  124. package/public/typedoc/classes/MC.McBase.html +3 -4
  125. package/public/typedoc/functions/MC.autoload.html +1 -1
  126. package/public/typedoc/functions/MC.off.html +1 -0
  127. package/public/typedoc/functions/{selectors._d.html → MC.on.html} +1 -1
  128. package/public/typedoc/functions/MC.one.html +1 -0
  129. package/public/typedoc/functions/MC.trigger.html +1 -0
  130. package/public/typedoc/functions/elements.defineCE.html +1 -1
  131. package/public/typedoc/functions/elements.getCE.html +1 -1
  132. package/public/typedoc/functions/formValues.formValues.html +1 -1
  133. package/public/typedoc/functions/observables.observe.html +1 -1
  134. package/public/typedoc/index.html +21 -10
  135. package/public/typedoc/interfaces/MC.HTMLMcElement.html +2 -2
  136. package/public/typedoc/modules/MC.html +6 -5
  137. package/public/typedoc/modules/elements.html +1 -1
  138. package/public/typedoc/modules/formValues.html +1 -1
  139. package/public/typedoc/modules/observables.html +1 -1
  140. package/public/typedoc/modules.html +0 -1
  141. package/public/typedoc/types/observables.Observable.html +1 -1
  142. package/src/MC.ts +213 -319
  143. package/src/elements.ts +17 -4
  144. package/src/formValues.ts +3 -3
  145. package/src/microcomponents.ts +1 -1
  146. package/src/observables.ts +32 -32
  147. package/src/test/test/grandparent.ts +12 -4
  148. package/src/test/test/testform.ts +6 -8
  149. package/src/test/test.ts +10 -9
  150. package/tsconfig.json +2 -2
  151. package/typedoc.json +1 -1
  152. package/webpack.config.js +2 -2
  153. package/dist/McEvent.d.ts +0 -15
  154. package/dist/McEvent.d.ts.map +0 -1
  155. package/dist/McEvent.js +0 -71
  156. package/dist/selectors.d.ts +0 -106
  157. package/dist/selectors.d.ts.map +0 -1
  158. package/dist/selectors.js +0 -759
  159. package/dist/selectors.min.js +0 -1
  160. package/public/McEvent.d.ts +0 -15
  161. package/public/McEvent.d.ts.map +0 -1
  162. package/public/McEvent.js +0 -71
  163. package/public/McEvent.js.map +0 -1
  164. package/public/selectors.d.ts +0 -106
  165. package/public/selectors.d.ts.map +0 -1
  166. package/public/selectors.js +0 -759
  167. package/public/selectors.js.map +0 -1
  168. package/public/selectors.min.js +0 -1
  169. package/public/src/McEvent.d.ts +0 -15
  170. package/public/src/McEvent.d.ts.map +0 -1
  171. package/public/src/McEvent.js +0 -71
  172. package/public/src/McEvent.js.map +0 -1
  173. package/public/src/selectors.d.ts +0 -106
  174. package/public/src/selectors.d.ts.map +0 -1
  175. package/public/src/selectors.js +0 -759
  176. package/public/src/selectors.js.map +0 -1
  177. package/public/test/McEvent.d.ts +0 -15
  178. package/public/test/McEvent.d.ts.map +0 -1
  179. package/public/test/McEvent.js +0 -71
  180. package/public/test/McEvent.ts +0 -96
  181. package/public/test/selectors.d.ts +0 -106
  182. package/public/test/selectors.d.ts.map +0 -1
  183. package/public/test/selectors.js +0 -759
  184. package/public/test/selectors.min.js +0 -1
  185. package/public/test/selectors.ts +0 -1269
  186. package/public/typedoc/classes/MC.McEvent.html +0 -9
  187. package/public/typedoc/functions/MC.addListener.html +0 -1
  188. package/public/typedoc/functions/MC.removeListener.html +0 -1
  189. package/public/typedoc/functions/selectors._t.html +0 -1
  190. package/public/typedoc/interfaces/selectors.DSelector.html +0 -48
  191. package/public/typedoc/interfaces/selectors.TSelector.html +0 -34
  192. package/public/typedoc/modules/selectors.html +0 -7
  193. package/public/typedoc/types/selectors.selection.html +0 -1
  194. package/public/typedoc/types/selectors.singleSelector.html +0 -1
  195. package/src/McEvent.ts +0 -96
  196. package/src/selectors.ts +0 -1269
  197. /package/{dist/McEvent.ts → public/McEvent._ts} +0 -0
  198. /package/{dist/selectors.ts → public/selectors._ts} +0 -0
  199. /package/public/{McEvent.ts → src/McEvent._ts} +0 -0
  200. /package/public/{selectors.ts → src/selectors._ts} +0 -0
  201. /package/{public/src/McEvent.ts → src/McEvent._ts} +0 -0
  202. /package/{public/src/selectors.ts → src/selectors._ts} +0 -0
package/src/MC.ts CHANGED
@@ -1,108 +1,37 @@
1
1
  'use strict';
2
2
 
3
3
  import { LooseObject } from './helpers.js';
4
- import { McEvent } from './McEvent.js';
5
4
 
6
- var isBrowser = new Function(
5
+ const isBrowser = new Function(
7
6
  'try {return this===window;}catch(e){ return false;}'
8
7
  );
9
8
 
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));
9
+ // get HTMLElement native event names
10
+ function getNativeEventNames( domNode: HTMLElement ): string[] {
11
+ let nativeEventNames: Array<string> = [];
12
+ if (isBrowser()) {
13
+ Object.keys(HTMLElement.prototype)
14
+ .filter((key) => /^on/.test(key))
15
+ .forEach((eventName) => nativeEventNames.push(eventName));
16
+ }
17
+ return nativeEventNames;
17
18
  }
18
19
 
19
20
  export interface HTMLMcElement extends HTMLElement {
20
21
  _mc: LooseObject;
21
22
  }
22
23
 
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
24
  function isDOM(element: { [key: string]: any }) {
64
25
  return element && element instanceof HTMLElement;
65
26
  }
66
27
 
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
28
  // add a microcomponent to a target DOM node
96
- function add(target: HTMLElement, key: string, element = {}): any {
29
+ function add( target: HTMLElement, key: string, element: any = {} ): HTMLMcElement {
97
30
  let node = target as HTMLMcElement;
98
31
 
99
32
  // create the _mc property if necessary
100
33
  if (!node._mc) {
101
- let debug = (DC as any)?.debug;
102
- (DC as any).debug = false;
103
34
  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
35
  }
107
36
 
108
37
  const _mc = node._mc;
@@ -111,11 +40,12 @@ function add(target: HTMLElement, key: string, element = {}): any {
111
40
  if (key.length && !_mc[key]) {
112
41
  _mc[key] = element;
113
42
  // add attribute if HTMLElement
114
- if (target instanceof HTMLElement && ! target.getAttribute('_mc') ) {
115
- target.setAttribute('_mc', '');
43
+ if (target instanceof HTMLElement && ! target.getAttribute('data-mc') ) {
44
+ target.setAttribute('data-mc', '');
116
45
  }
117
46
  }
118
- return element;
47
+
48
+ return node;
119
49
  }
120
50
 
121
51
  // remove a micro component from the DOM
@@ -133,63 +63,90 @@ function remove(target: HTMLMcElement, key: string) {
133
63
  if (
134
64
  !Object.keys(_mc).length &&
135
65
  target instanceof HTMLElement &&
136
- target.hasAttribute('_mc')
66
+ target.hasAttribute('data-mc')
137
67
  ) {
138
- target.removeAttribute('_mc');
68
+ target.removeAttribute('data-mc');
139
69
  }
140
70
  return;
141
71
  }
142
72
 
143
- // trigger an event
144
- function trigger(
145
- target: HTMLElement,
146
- ev: McEvent | string,
147
- data: any = {},
148
- bubble: string = 'l'
149
- ) {
150
- let _mc = (target as any)?._mc;
151
- if (!_mc) return;
152
-
153
- let event =
154
- ev instanceof McEvent
155
- ? new McEvent(ev.type, ev.data, 'l')
156
- : new McEvent(ev, data, 'l'),
157
- mcEvent: McEvent =
158
- typeof ev !== 'string' ? (ev as McEvent) : new McEvent(ev, data, bubble);
159
-
160
- [...Object.values(_mc)].forEach((mc: any) => {
161
- //console.log( 'mc [', mc.constructor.name, ']', mc.constructor.prototype?.oneInit );
162
- if ((mc as any)?.trigger && typeof (mc as any)?.trigger === 'function') {
163
- (mc as any)?.trigger(event);
164
- }
165
- });
73
+ // run the "init" lifecycle event on the complete _mc structure
74
+ function init(element: DC) {
75
+ setTimeout(() => {
76
+ if (element.constructor === DC) return;
77
+ element.trigger('Init');
78
+ }, 0);
79
+ }
166
80
 
167
- if (/[ud]/.test(mcEvent.bubble)) {
168
- bubbleEvent(target, mcEvent);
169
- }
81
+ // 'eventName' => '_mcEventName'
82
+ function getMcEventName( eventName: string ): string {
83
+ return '_mc' + eventName[0].toUpperCase() + eventName.substring(1);
84
+ }
170
85
 
171
- return;
86
+ /*
87
+ CustomEvent Section...
88
+ */
89
+ function off( domNode: Node, eventName: string, handler: EventListenerOrEventListenerObject ){
90
+ domNode.removeEventListener( getMcEventName(eventName), handler );
172
91
  }
173
92
 
174
- // run the "init" lifecycle event on the complete _mc structure
175
- function init(element: MC | DC) {
176
- if (element.constructor === DC) return;
93
+ function on( domNode: Node, eventName: string, handler: EventListenerOrEventListenerObject, once: boolean = false ) {
94
+ domNode.addEventListener( getMcEventName(eventName), handler, { capture: false, once });
95
+ }
96
+
97
+ function one( domNode: Node, eventName: string, handler: EventListenerOrEventListenerObject ) {
98
+ on(domNode, eventName, handler, true );
99
+ }
100
+
101
+ // create and dispatch custom event
102
+ function trigger(
103
+ domNode: HTMLElement,
104
+ event: CustomEvent | string,
105
+ data: any = {},
106
+ bubble: string = 'l'
107
+ ){
108
+ const ev = typeof event === 'string'
109
+ ? new CustomEvent( getMcEventName( event ), { detail: {data, bubble} } )
110
+ : event;
111
+
112
+ // execute locally if 'l' or nothing is given as bubble
113
+ if( bubble.length && bubble.indexOf('l') > -1 ){
114
+ domNode.dispatchEvent( ev );
115
+ }
116
+
117
+ // bubble if up or down is indicated
118
+ if( /[u|d]/.test( bubble ) ){
119
+ bubbleEvent( domNode, ev );
120
+ }
121
+ }
177
122
 
123
+ function bubbleEvent( domNode: HTMLElement, ev: CustomEvent) {
124
+ // at this point, either 'u' or 'd' bubbling should be indicated
125
+ // event bubbling is asynchronous!
178
126
  setTimeout(() => {
179
- element.trigger('Init');
180
- /*
181
- let keys = Object.keys( ( element as any)?._mc );
182
- if ( keys.length ){
183
- //console.log( 'inner Inits on [', mc.constructor.name, ']', keys );
184
- keys?.forEach( (key: string) => {
185
- let mc = ( element as any)?._mc?.[key];
186
- //console.log( key, typeof mc?.oneInit, mc );
187
- if ( ( mc as any )['oneInit'] && typeof ( mc as any ).oneInit == 'function' ){
188
- ( mc as any ).oneInit( new McEvent('Init') );
189
- }
190
- });
191
- };
192
- */
127
+
128
+ // add missing 'l', or else no handlers are executed
129
+ if (ev.detail.bubble.indexOf('l') === -1) {
130
+ ev.detail.bubble += 'l';
131
+ }
132
+
133
+ // bubble up towards root
134
+ if (ev.detail.bubble.indexOf('u') > -1 ) {
135
+ domNode.closest('[data-mc]')?.dispatchEvent( ev );
136
+ }
137
+
138
+ // bubble down
139
+ if (ev.detail.bubble.indexOf('d') > -1) {
140
+ let targets = new Set<HTMLMcElement>(
141
+ (domNode as HTMLMcElement)._mc
142
+ .children()
143
+ .map((c: unknown) => (c as any)?.target)
144
+ );
145
+ targets.forEach((target: HTMLMcElement) => {
146
+ if (target) target._mc.trigger(target, ev);
147
+ });
148
+ }
149
+
193
150
  }, 0);
194
151
  }
195
152
 
@@ -209,74 +166,46 @@ function autoAttachListeners(element: MC | DC) {
209
166
  .forEach((key) => {
210
167
  let once = /^one/.test(key),
211
168
  withoutOnOne = key.replace(/^on[e]{0,1}/, ''), // preserves upper/lowercase for non-native events
212
- nativeEventName = withoutOnOne.toLowerCase(),
213
- listener = (ev: McEvent | Event | CustomEvent) => {
214
- that.trigger(withoutOnOne, ev);
215
- };
216
- if (once) {
217
- // console.log( '...is only called once', that.constructor.prototype[key] );
218
- Object.defineProperty(element, 'on' + withoutOnOne, {
219
- configurable: true,
220
- enumerable: false,
221
- writable: true,
222
- value: (ev: any) => {
223
- // console.log( 'onceHandler execute:', that.constructor.prototype[key] );
224
- that.constructor.prototype[key].bind(that)(ev);
225
- },
226
- });
227
- }
169
+ nativeEventName = withoutOnOne.toLowerCase(); // lowercase for native event names
228
170
 
229
- if (nativeEventNames.has('on' + nativeEventName)) {
230
- // native event defined in HTMLElement
231
- // console.log('added as native listener', target, nativeEventName );
232
- addListener(target, nativeEventName, listener, false, once);
171
+ let listener = (ev: Event | CustomEvent) => {
172
+ that[key]( ev );
173
+ }
174
+
175
+ if ( !!( target as any )['on' + nativeEventName] ) {
176
+ // it is a native HTML event
177
+ //console.log( 'AAL: attach native event listener', nativeEventName, 'to', target );
178
+ target.addEventListener( nativeEventName, listener);
179
+ } else {
180
+ // it is a customEvent
181
+ //console.log( 'AAL: attach custom event listener', '_mc' + withoutOnOne , 'to key', key, 'in', element );
182
+ on( target, withoutOnOne, listener, once );
233
183
  }
234
184
  });
235
185
  }
236
186
  }
237
187
 
238
- function bubbleEvent(target: HTMLElement, ev: McEvent) {
239
- // at this point, either 'u' or 'd' bubbling should be indicated
240
- // mcEvent bubbling is asynchronous, and the order of target MC execution in case of multiple matches is not guaranteed!
241
- if (/[ud]/.test(ev.bubble)) {
242
- setTimeout(() => {
243
- // bubbling must include 'l' for local, or else no handlers are executed'
244
- if (ev.bubble.indexOf('l') === -1) {
245
- ev.bubble += 'l';
246
- }
247
-
248
- // bubble up towards root
249
- if (ev.bubble.indexOf('u') > -1) {
250
- let parent = traverseNodes(target, '', true)?.[0].target;
251
- if (parent) DC.trigger(parent, ev);
252
- }
253
-
254
- // bubble down
255
- if (ev.bubble.indexOf('d') > -1) {
256
- let targets = new Set<HTMLMcElement>(
257
- (target as HTMLMcElement)._mc
258
- .children()
259
- .map((c: unknown) => (c as any)?.target)
260
- );
261
- targets.forEach((target: HTMLMcElement) => {
262
- if (target) DC.trigger(target, ev);
263
- });
264
- }
265
- }, 0);
266
- }
188
+ function getMcChildNodes(domNode: HTMLElement): DC[] | null {
189
+ const id = Math.random().toString().replace('.', '');
190
+ const selector = '[data-mc]:not([temp_id="' + id + '"] [data-mc] [data-mc])';
191
+ domNode.setAttribute('temp_id', id);
192
+ const mcArray: unknown[] =
193
+ ( [ ...domNode.querySelectorAll(selector) ] as HTMLMcElement[])
194
+ .filter( (e) => !!e._mc )
195
+ .map( e => e._mc );
196
+ domNode.removeAttribute('temp_id');
197
+ return mcArray.length ? mcArray as DC[] : null;
267
198
  }
268
199
 
269
200
  class McBase {
270
201
  private _target: WeakRef<any>; // avoid circular reference
271
- private __mc: LooseObject = {};
272
202
 
273
- constructor(target?: { [key: string]: any }, debug: boolean = false) {
274
- let that: unknown = this,
275
- element = that as MC | DC;
203
+ constructor(target?: { [key: string]: any } ) {
204
+ let element = this as unknown as MC | DC;
276
205
 
277
206
  this._target = new WeakRef(target || {});
278
207
 
279
- init(element); // async lifecycle event
208
+ init(element as DC); // async lifecycle event
280
209
 
281
210
  autoAttachListeners(element);
282
211
  }
@@ -285,85 +214,12 @@ class McBase {
285
214
  return this._target.deref();
286
215
  }
287
216
 
288
- get _mc(): any {
289
- return this.__mc;
290
- }
291
217
  }
292
218
 
293
219
  class MC extends McBase {
294
220
  constructor(target?: any) {
295
221
  super(target);
296
222
  }
297
-
298
- static trigger = trigger;
299
-
300
- trigger(ev: McEvent | string, data: any = {}, bubble: string = 'l') {
301
- let that = this;
302
-
303
- //console.log( that, '.trigger(', ev, data, bubble, ')' );
304
-
305
- // run all triggers
306
- if (that.constructor === MC || that.constructor === DC) {
307
- let event =
308
- ev instanceof McEvent
309
- ? new McEvent(ev.type, ev.data, 'l')
310
- : new McEvent(ev, data, 'l'),
311
- mcEvent: McEvent =
312
- typeof ev !== 'string'
313
- ? (ev as McEvent)
314
- : new McEvent(ev, data, bubble);
315
- [...Object.getOwnPropertyNames(that)].forEach((mc) => {
316
- if (
317
- (that as any)[mc]?.trigger &&
318
- typeof (that as any)[mc]?.trigger === 'function'
319
- ) {
320
- (that as any)[mc]?.trigger(event);
321
- }
322
- });
323
-
324
- if (/[ud]/.test(mcEvent.bubble)) {
325
- bubbleEvent(that.target, mcEvent);
326
- }
327
-
328
- return; // must return here!
329
- }
330
-
331
- // only this instance
332
- if ((that as any) instanceof MC || (that as any) instanceof DC) {
333
- const that = this,
334
- mcEvent: McEvent =
335
- typeof ev !== 'string'
336
- ? (ev as McEvent)
337
- : new McEvent(ev, data, bubble),
338
- handlerName =
339
- 'on' + mcEvent.type[0].toUpperCase() + mcEvent.type.slice(1);
340
- // console.log('trigger', handlerName, mcEvent, data, bubble );
341
-
342
- if (mcEvent.bubble.indexOf('l') > -1) {
343
- if (
344
- !mcEvent.immediateStopped &&
345
- typeof (that as any)[handlerName] === 'function'
346
- ) {
347
- // console.log( 'execute handler:', handlerName );
348
- (that as any)[handlerName](mcEvent);
349
- if ((that as any).hasOwnProperty(handlerName)) {
350
- // it is a once handler
351
- delete (that as any)[handlerName]; // remove after first execution
352
- }
353
- }
354
- }
355
-
356
- // if event stopped or local only, handling is cancelled
357
- if (mcEvent.stopped || mcEvent.bubble === 'l') {
358
- return that;
359
- }
360
-
361
- //console.log('bubble', mcEvent);
362
- if (/[ud]/.test(mcEvent.bubble)) {
363
- bubbleEvent(that.target, mcEvent);
364
- }
365
- }
366
- }
367
223
  }
368
224
 
369
225
  class DC extends McBase {
@@ -373,69 +229,77 @@ class DC extends McBase {
373
229
 
374
230
  static add: Function = add;
375
231
  static remove: Function = remove;
376
- static trigger: Function = trigger;
377
232
 
378
- trigger(ev: McEvent | string, data: any = {}, bubble?: string) {
379
- MC.prototype.trigger.call(this, ev, data, bubble);
233
+ /* event handling */
234
+ off( eventName: string, handler: EventListenerOrEventListenerObject ) {
235
+ off( this.target, eventName, handler );
380
236
  }
381
237
 
382
- parent(search: string = ''): any[] {
383
- let target: HTMLElement = (this as any).target;
384
- if (!isDOM(target)) return [];
385
- return traverseNodes((target as any).parentNode, search, true);
238
+ on( eventName: string, handler: EventListenerOrEventListenerObject ) {
239
+ on( this.target, eventName, handler );
386
240
  }
387
241
 
388
- ancestors(search: string = ''): any[] {
389
- let target: any = (this as any)?.target;
390
- if (!isDOM(target)) return [];
391
- return traverseNodes((this as any).target.parentNode, search, false);
242
+ one( eventName: string, handler: EventListenerOrEventListenerObject ) {
243
+ one( this.target, eventName, handler );
392
244
  }
393
245
 
394
- children(search: string = ''): any[] {
395
- let target: any = (this as any)?.target;
396
- if (!isDOM(target)) return [];
397
- const id = Math.random().toString().replace('.', '');
398
- const selector = '[_mc]:not([temp_id="' + id + '"] [_mc] [_mc])';
399
- target.setAttribute('temp_id', id);
400
- const myDomElements = target.querySelectorAll(selector);
401
- const mcValues = getMicroComponents([...myDomElements], search);
402
- target.removeAttribute('temp_id');
403
- return mcValues;
246
+ trigger( eventName: string, data: any = {}, bubble: string = 'l') {
247
+ trigger( this.target, eventName, data, bubble);
404
248
  }
405
249
 
406
- descendants(search: string = ''): any[] {
407
- let target: any = (this as any)?.target;
408
- if (!isDOM(target)) return [];
409
- const myDomElements = target.querySelectorAll('*[_mc]');
410
- return getMicroComponents([...myDomElements], search);
250
+ /* DOM traversal */
251
+ parent(): DC | null {
252
+ let
253
+ target: HTMLElement = (this as DC).target;
254
+ if (!isDOM(target)) return null;
255
+ return (target.closest('[data-mc]') as HTMLMcElement)?._mc as DC || null;
411
256
  }
412
- }
413
257
 
414
- const loadingMCs = new Set<string>();
258
+ ancestors(): DC[] | null {
259
+ let
260
+ currentNode: HTMLElement | null = (this as DC)?.target as HTMLMcElement,
261
+ result: DC[] = [];
415
262
 
416
- function makeLoadScript( element: string ) {
263
+ if (!isDOM( currentNode )) return [];
417
264
 
418
- if ( loadingMCs.has( element ) ) return; // already loading
265
+ while ( currentNode = (currentNode.closest('[data-mc]') ) ){
266
+ if ( (currentNode as HTMLMcElement)?._mc ){
267
+ result.push( (currentNode as HTMLMcElement)?._mc as DC );
268
+ }
269
+ }
419
270
 
420
- loadingMCs.add( element );
271
+ return result.length ? result : null;
272
+ }
421
273
 
422
- //console.log( 'makeLoadScript:', element);
423
- const fileName: string = './' + element.split('-').join('/')+'.js';
274
+ children(): DC[] | null {
275
+ let target: any = (this as any)?.target;
276
+ if (!isDOM(target)) return null;
277
+ return getMcChildNodes(target);
278
+ }
424
279
 
425
- const se: HTMLScriptElement = document.createElement('script');
280
+ descendants(): DC[] | null {
281
+ const target: any = (this as DC)?.target;
282
+ if (!isDOM(target)) return [];
283
+ const mcArray: unknown[] =
284
+ ( [ ...target.querySelectorAll( '[data-mc]' ) ] as HTMLMcElement[])
285
+ .filter( (e) => !!e._mc )
286
+ .map( e => e._mc );
287
+ return mcArray.length ? mcArray as DC[] : null;
288
+ }
289
+ }
426
290
 
427
- se.setAttribute('src', fileName);
428
- se.setAttribute('blocking', 'render');
429
- se.async = true;
430
- se.setAttribute('type', 'module');
431
- se.setAttribute( 'data-name', element);
432
- se.setAttribute( 'loading', '');
291
+ /*
292
+ Autoload Section...
293
+ */
433
294
 
434
- const loadedPromise = customElements.whenDefined( element );
295
+ const loadingDCs = new Set<string>();
435
296
 
436
- loadedPromise.then( () => {
297
+ function attachDC(element: string): Function {
298
+
299
+ //@ts-ignore
300
+ return () => {
437
301
  const elements: HTMLElement[] = Array
438
- .from(document.querySelectorAll(`[_mc*="${element}"]`))
302
+ .from(document.querySelectorAll(`[data-mc*="${element}"]`))
439
303
  .filter( element => element instanceof HTMLElement );
440
304
 
441
305
  if ( elements.length === 0 ) return;
@@ -450,28 +314,53 @@ function makeLoadScript( element: string ) {
450
314
 
451
315
  //@ts-ignore
452
316
  const new_mc = node
453
- .getAttribute( '_mc' )
317
+ .getAttribute( 'data-mc' )
454
318
  .split(' ')
455
319
  .filter( (name) => name !== element && name !== '' )
456
- .join(' ');
320
+ .join(' ')
321
+ .trim();
457
322
 
458
323
  //@ts-ignore
459
324
  node.setAttribute(
460
- '_mc',
325
+ 'data-mc',
461
326
  //@ts-ignore
462
327
  new_mc
463
328
  )
464
329
  });
330
+ };
331
+ };
465
332
 
466
- document.head.querySelector('script[data-name="${elementName}]"')?.remove();
467
- });
333
+ function makeLoadScript( element: string ) {
334
+
335
+ if ( loadingDCs.has( element ) ) return; // already loading
336
+
337
+ loadingDCs.add( element );
338
+
339
+ //console.log( 'makeLoadScript:', element);
340
+ const fileName: string = './' + element.split('-').join('/')+'.js';
341
+
342
+ const se: HTMLScriptElement = document.createElement('script');
343
+
344
+ se.setAttribute('src', fileName);
345
+ se.setAttribute('blocking', 'render');
346
+ se.async = true;
347
+ se.setAttribute('type', 'module');
348
+ se.setAttribute( 'data-name', element);
349
+ se.setAttribute( 'loading', '');
350
+
351
+ const loadedPromise = customElements.whenDefined( element );
352
+
353
+ //@ts-ignore
354
+ loadedPromise.then( attachDC( element ) );
468
355
 
469
- addListener( se, 'load', (ev) => {
470
- loadingMCs.delete( element );
356
+ se.addEventListener( 'load', (ev: Event) => {
357
+ loadingDCs.delete( element );
358
+
359
+ document.head.querySelector(`script[data-name="${element}"]`)?.remove();
471
360
  });
472
361
 
473
- addListener( se, 'error', (ev) => {
474
- console.error('could not load MC code from', fileName);
362
+ se.addEventListener( 'error', (ev: Event) => {
363
+ console.error('could not load DC code from', fileName);
475
364
  });
476
365
 
477
366
  document.head.append(se);
@@ -483,21 +372,26 @@ function loadUndefinedMCs() {
483
372
  [ ...document.querySelectorAll(':not(:defined)') ]
484
373
  .filter( (element) => !!element
485
374
  && !customElements.get(element.tagName.toLowerCase()) // not in CustomElementsRegistry
486
- && !loadingMCs.has(element.tagName.toLowerCase()) // not in loading list
375
+ && !loadingDCs.has(element.tagName.toLowerCase()) // not in loading list
487
376
  )
488
377
  .forEach((el) => {
489
378
  //console.log( 'detected CE', el.tagName.toLowerCase() );
490
- makeLoadScript( el.tagName.toLowerCase() );
379
+ makeLoadScript( el.tagName.toLowerCase() ); // will automatically be instanciated
491
380
  });
492
381
 
493
- // load unresolved MCs defined in _mc attribute
494
- [ ...document.querySelectorAll('[_mc]:not([_mc=""]') ]
382
+ // if defined in _mc attribute: instanciate DCs, load if necessary
383
+ [ ...document.querySelectorAll('[data-mc]:not([data-mc=""]') ]
495
384
  .filter( (element) => !!element )
496
385
  .forEach((el) => {
497
- const _mc = el.getAttribute('_mc')?.split(' ').filter( name => name !== '' );
498
- _mc?.forEach( dc => {
386
+ const _mc = el.getAttribute('data-mc')?.split(' ').filter( name => name !== '' );
387
+ _mc?.forEach( element => {
499
388
  //console.log( 'detected DC', dc );
500
- makeLoadScript( dc );
389
+ const isDefined = customElements.get(element);
390
+ if ( !loadingDCs.has(element) && !isDefined ) {
391
+ makeLoadScript( element );
392
+ } else if ( isDefined ) {
393
+ attachDC(element)();
394
+ }
501
395
  });
502
396
  });
503
397
  }
@@ -526,7 +420,7 @@ function autoload(enable: boolean = true): boolean {
526
420
  return autoloadEnabled;
527
421
  }
528
422
 
529
- (autoload as LooseObject).state = { loadingMCs };
423
+ (autoload as LooseObject).state = loadingDCs;
530
424
 
531
- export { addListener, removeListener, McBase, MC, DC, McEvent, autoload };
425
+ export { McBase, MC, DC, autoload, on, one, off, trigger };
532
426