@elementor/frontend-handlers 3.35.0-425 → 3.35.0-427
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/index.js +22 -21
- package/dist/index.mjs +22 -21
- package/package.json +1 -1
- package/src/__tests__/index.test.ts +126 -26
- package/src/handlers-registry.ts +4 -4
- package/src/init.ts +2 -18
- package/src/lifecycle-events.ts +22 -6
package/dist/index.js
CHANGED
|
@@ -69,12 +69,12 @@ var unregisterBySelector = ({ selector, id }) => {
|
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
71
|
if (id) {
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
|
|
72
|
+
elementSelectorHandlers.get(selector)?.delete(id);
|
|
73
|
+
if (elementSelectorHandlers.get(selector)?.size === 0) {
|
|
74
|
+
elementSelectorHandlers.delete(selector);
|
|
75
75
|
}
|
|
76
76
|
} else {
|
|
77
|
-
|
|
77
|
+
elementSelectorHandlers.delete(selector);
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
80
|
|
|
@@ -90,6 +90,7 @@ var onElementRender = ({
|
|
|
90
90
|
const controller = new AbortController();
|
|
91
91
|
const manualUnmount = [];
|
|
92
92
|
const dispatchRenderedEvent = () => {
|
|
93
|
+
onElementSelectorRender({ element, elementId, controller });
|
|
93
94
|
element.dispatchEvent(
|
|
94
95
|
new CustomEvent(ELEMENT_RENDERED_EVENT_NAME, {
|
|
95
96
|
bubbles: true,
|
|
@@ -167,8 +168,11 @@ var onElementSelectorRender = ({
|
|
|
167
168
|
manualUnmount.push(unmount);
|
|
168
169
|
}
|
|
169
170
|
});
|
|
170
|
-
if (!
|
|
171
|
-
|
|
171
|
+
if (!manualUnmount.length) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (!unmountElementSelectorCallbacks.get(elementId)) {
|
|
175
|
+
unmountElementSelectorCallbacks.set(elementId, /* @__PURE__ */ new Map());
|
|
172
176
|
}
|
|
173
177
|
unmountElementSelectorCallbacks.get(elementId)?.set(selector, () => {
|
|
174
178
|
controller.abort();
|
|
@@ -178,14 +182,23 @@ var onElementSelectorRender = ({
|
|
|
178
182
|
};
|
|
179
183
|
var onElementDestroy = ({ elementType, elementId }) => {
|
|
180
184
|
const unmount = unmountElementTypeCallbacks.get(elementType)?.get(elementId);
|
|
181
|
-
|
|
182
|
-
|
|
185
|
+
const unmountSelector = unmountElementSelectorCallbacks.get(elementId);
|
|
186
|
+
if (unmount) {
|
|
187
|
+
unmount();
|
|
188
|
+
}
|
|
189
|
+
if (unmountSelector?.size) {
|
|
190
|
+
Array.from(unmountSelector.values()).forEach((selectorUnmount) => {
|
|
191
|
+
selectorUnmount();
|
|
192
|
+
});
|
|
183
193
|
}
|
|
184
|
-
unmount();
|
|
185
194
|
unmountElementTypeCallbacks.get(elementType)?.delete(elementId);
|
|
195
|
+
unmountElementSelectorCallbacks.delete(elementId);
|
|
186
196
|
if (unmountElementTypeCallbacks.get(elementType)?.size === 0) {
|
|
187
197
|
unmountElementTypeCallbacks.delete(elementType);
|
|
188
198
|
}
|
|
199
|
+
if (unmountElementSelectorCallbacks.size === 0) {
|
|
200
|
+
unmountElementSelectorCallbacks.delete(elementId);
|
|
201
|
+
}
|
|
189
202
|
};
|
|
190
203
|
|
|
191
204
|
// src/init.ts
|
|
@@ -202,7 +215,6 @@ function init() {
|
|
|
202
215
|
onElementDestroy({ elementType: type, elementId: id });
|
|
203
216
|
});
|
|
204
217
|
document.addEventListener("DOMContentLoaded", () => {
|
|
205
|
-
const controller = new AbortController();
|
|
206
218
|
document.querySelectorAll("[data-e-type]").forEach((element) => {
|
|
207
219
|
const el = element;
|
|
208
220
|
const { eType, id } = el.dataset;
|
|
@@ -219,17 +231,6 @@ function init() {
|
|
|
219
231
|
})
|
|
220
232
|
);
|
|
221
233
|
});
|
|
222
|
-
Array.from(elementSelectorHandlers.keys()).forEach((selector) => {
|
|
223
|
-
Array.from(document.querySelectorAll(selector)).forEach((element) => {
|
|
224
|
-
const el = element;
|
|
225
|
-
const elementId = el?.closest("[data-id]")?.getAttribute("data-id") ?? "";
|
|
226
|
-
onElementSelectorRender({
|
|
227
|
-
element,
|
|
228
|
-
controller,
|
|
229
|
-
elementId
|
|
230
|
-
});
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
234
|
});
|
|
234
235
|
}
|
|
235
236
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.mjs
CHANGED
|
@@ -39,12 +39,12 @@ var unregisterBySelector = ({ selector, id }) => {
|
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
41
|
if (id) {
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
|
|
42
|
+
elementSelectorHandlers.get(selector)?.delete(id);
|
|
43
|
+
if (elementSelectorHandlers.get(selector)?.size === 0) {
|
|
44
|
+
elementSelectorHandlers.delete(selector);
|
|
45
45
|
}
|
|
46
46
|
} else {
|
|
47
|
-
|
|
47
|
+
elementSelectorHandlers.delete(selector);
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
50
|
|
|
@@ -60,6 +60,7 @@ var onElementRender = ({
|
|
|
60
60
|
const controller = new AbortController();
|
|
61
61
|
const manualUnmount = [];
|
|
62
62
|
const dispatchRenderedEvent = () => {
|
|
63
|
+
onElementSelectorRender({ element, elementId, controller });
|
|
63
64
|
element.dispatchEvent(
|
|
64
65
|
new CustomEvent(ELEMENT_RENDERED_EVENT_NAME, {
|
|
65
66
|
bubbles: true,
|
|
@@ -137,8 +138,11 @@ var onElementSelectorRender = ({
|
|
|
137
138
|
manualUnmount.push(unmount);
|
|
138
139
|
}
|
|
139
140
|
});
|
|
140
|
-
if (!
|
|
141
|
-
|
|
141
|
+
if (!manualUnmount.length) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (!unmountElementSelectorCallbacks.get(elementId)) {
|
|
145
|
+
unmountElementSelectorCallbacks.set(elementId, /* @__PURE__ */ new Map());
|
|
142
146
|
}
|
|
143
147
|
unmountElementSelectorCallbacks.get(elementId)?.set(selector, () => {
|
|
144
148
|
controller.abort();
|
|
@@ -148,14 +152,23 @@ var onElementSelectorRender = ({
|
|
|
148
152
|
};
|
|
149
153
|
var onElementDestroy = ({ elementType, elementId }) => {
|
|
150
154
|
const unmount = unmountElementTypeCallbacks.get(elementType)?.get(elementId);
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
const unmountSelector = unmountElementSelectorCallbacks.get(elementId);
|
|
156
|
+
if (unmount) {
|
|
157
|
+
unmount();
|
|
158
|
+
}
|
|
159
|
+
if (unmountSelector?.size) {
|
|
160
|
+
Array.from(unmountSelector.values()).forEach((selectorUnmount) => {
|
|
161
|
+
selectorUnmount();
|
|
162
|
+
});
|
|
153
163
|
}
|
|
154
|
-
unmount();
|
|
155
164
|
unmountElementTypeCallbacks.get(elementType)?.delete(elementId);
|
|
165
|
+
unmountElementSelectorCallbacks.delete(elementId);
|
|
156
166
|
if (unmountElementTypeCallbacks.get(elementType)?.size === 0) {
|
|
157
167
|
unmountElementTypeCallbacks.delete(elementType);
|
|
158
168
|
}
|
|
169
|
+
if (unmountElementSelectorCallbacks.size === 0) {
|
|
170
|
+
unmountElementSelectorCallbacks.delete(elementId);
|
|
171
|
+
}
|
|
159
172
|
};
|
|
160
173
|
|
|
161
174
|
// src/init.ts
|
|
@@ -172,7 +185,6 @@ function init() {
|
|
|
172
185
|
onElementDestroy({ elementType: type, elementId: id });
|
|
173
186
|
});
|
|
174
187
|
document.addEventListener("DOMContentLoaded", () => {
|
|
175
|
-
const controller = new AbortController();
|
|
176
188
|
document.querySelectorAll("[data-e-type]").forEach((element) => {
|
|
177
189
|
const el = element;
|
|
178
190
|
const { eType, id } = el.dataset;
|
|
@@ -189,17 +201,6 @@ function init() {
|
|
|
189
201
|
})
|
|
190
202
|
);
|
|
191
203
|
});
|
|
192
|
-
Array.from(elementSelectorHandlers.keys()).forEach((selector) => {
|
|
193
|
-
Array.from(document.querySelectorAll(selector)).forEach((element) => {
|
|
194
|
-
const el = element;
|
|
195
|
-
const elementId = el?.closest("[data-id]")?.getAttribute("data-id") ?? "";
|
|
196
|
-
onElementSelectorRender({
|
|
197
|
-
element,
|
|
198
|
-
controller,
|
|
199
|
-
elementId
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
204
|
});
|
|
204
205
|
}
|
|
205
206
|
export {
|
package/package.json
CHANGED
|
@@ -1,20 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { init, register, unregister } from '../index';
|
|
1
|
+
import { init, register, registerBySelector, unregister, unregisterBySelector } from '../index';
|
|
3
2
|
|
|
4
3
|
describe( 'Frontend Handlers', () => {
|
|
5
4
|
const PARENT_ELEMENT_TYPE = 'e-parent-element';
|
|
6
5
|
const CHILD_ELEMENT_TYPE = 'e-child-element';
|
|
7
6
|
const WIDGET_ELEMENT_TYPE = 'e-widget';
|
|
7
|
+
const ELEMENT_CLASS = 'selector-target';
|
|
8
|
+
const SELECTOR_TARGET = `.${ ELEMENT_CLASS }`;
|
|
9
|
+
const HANDLER_IDS = {
|
|
10
|
+
handler_1: 'handler-1',
|
|
11
|
+
handler_2: 'handler-2',
|
|
12
|
+
parent_handler: 'parent-handler',
|
|
13
|
+
};
|
|
8
14
|
|
|
9
15
|
beforeAll( () => {
|
|
10
16
|
init();
|
|
11
17
|
} );
|
|
12
18
|
|
|
13
19
|
beforeEach( () => {
|
|
14
|
-
elementTypeHandlers.clear();
|
|
15
20
|
document.body.innerHTML = '';
|
|
16
21
|
} );
|
|
17
22
|
|
|
23
|
+
afterEach( () => {
|
|
24
|
+
[ WIDGET_ELEMENT_TYPE, PARENT_ELEMENT_TYPE, CHILD_ELEMENT_TYPE ].forEach( ( elementType ) => {
|
|
25
|
+
unregister( { elementType } );
|
|
26
|
+
} );
|
|
27
|
+
|
|
28
|
+
Object.values( HANDLER_IDS ).forEach( ( handler ) => {
|
|
29
|
+
unregisterBySelector( { selector: SELECTOR_TARGET, id: handler } );
|
|
30
|
+
} );
|
|
31
|
+
} );
|
|
32
|
+
|
|
18
33
|
describe( 'Handler Registration', () => {
|
|
19
34
|
it( 'should register and execute handler callback', () => {
|
|
20
35
|
// Arrange
|
|
@@ -57,13 +72,13 @@ describe( 'Frontend Handlers', () => {
|
|
|
57
72
|
|
|
58
73
|
register( {
|
|
59
74
|
elementType: WIDGET_ELEMENT_TYPE,
|
|
60
|
-
id:
|
|
75
|
+
id: HANDLER_IDS.handler_1,
|
|
61
76
|
callback: handler1,
|
|
62
77
|
} );
|
|
63
78
|
|
|
64
79
|
register( {
|
|
65
80
|
elementType: WIDGET_ELEMENT_TYPE,
|
|
66
|
-
id:
|
|
81
|
+
id: HANDLER_IDS.handler_2,
|
|
67
82
|
callback: handler2,
|
|
68
83
|
} );
|
|
69
84
|
|
|
@@ -91,11 +106,11 @@ describe( 'Frontend Handlers', () => {
|
|
|
91
106
|
|
|
92
107
|
register( {
|
|
93
108
|
elementType: WIDGET_ELEMENT_TYPE,
|
|
94
|
-
id:
|
|
109
|
+
id: HANDLER_IDS.handler_1,
|
|
95
110
|
callback: handlerCallback,
|
|
96
111
|
} );
|
|
97
112
|
|
|
98
|
-
unregister( { elementType: WIDGET_ELEMENT_TYPE, id:
|
|
113
|
+
unregister( { elementType: WIDGET_ELEMENT_TYPE, id: HANDLER_IDS.handler_1 } );
|
|
99
114
|
|
|
100
115
|
const element = document.createElement( 'div' );
|
|
101
116
|
element.setAttribute( 'data-e-type', WIDGET_ELEMENT_TYPE );
|
|
@@ -123,7 +138,7 @@ describe( 'Frontend Handlers', () => {
|
|
|
123
138
|
|
|
124
139
|
register( {
|
|
125
140
|
elementType: WIDGET_ELEMENT_TYPE,
|
|
126
|
-
id:
|
|
141
|
+
id: HANDLER_IDS.handler_1,
|
|
127
142
|
callback: handlerCallback,
|
|
128
143
|
} );
|
|
129
144
|
|
|
@@ -157,7 +172,7 @@ describe( 'Frontend Handlers', () => {
|
|
|
157
172
|
|
|
158
173
|
register( {
|
|
159
174
|
elementType: WIDGET_ELEMENT_TYPE,
|
|
160
|
-
id:
|
|
175
|
+
id: HANDLER_IDS.handler_1,
|
|
161
176
|
callback: ( { settings } ) => {
|
|
162
177
|
settingsHistory.push( { ...settings } );
|
|
163
178
|
return undefined;
|
|
@@ -193,6 +208,37 @@ describe( 'Frontend Handlers', () => {
|
|
|
193
208
|
} );
|
|
194
209
|
|
|
195
210
|
describe( 'Cleanup and Unmount', () => {
|
|
211
|
+
it( 'should call selector unmount callback when element is destroyed', () => {
|
|
212
|
+
const ELEMENT_ID = 'selector-1';
|
|
213
|
+
const unmountSelector = jest.fn();
|
|
214
|
+
|
|
215
|
+
registerBySelector( {
|
|
216
|
+
selector: SELECTOR_TARGET,
|
|
217
|
+
id: HANDLER_IDS.handler_1,
|
|
218
|
+
callback: () => unmountSelector,
|
|
219
|
+
} );
|
|
220
|
+
|
|
221
|
+
const element = document.createElement( 'div' );
|
|
222
|
+
element.classList.add( ELEMENT_CLASS );
|
|
223
|
+
element.setAttribute( 'data-e-type', WIDGET_ELEMENT_TYPE );
|
|
224
|
+
element.setAttribute( 'data-id', ELEMENT_ID );
|
|
225
|
+
document.body.appendChild( element );
|
|
226
|
+
|
|
227
|
+
window.dispatchEvent(
|
|
228
|
+
new CustomEvent( 'elementor/element/render', {
|
|
229
|
+
detail: { id: ELEMENT_ID, type: WIDGET_ELEMENT_TYPE, element },
|
|
230
|
+
} )
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
window.dispatchEvent(
|
|
234
|
+
new CustomEvent( 'elementor/element/destroy', {
|
|
235
|
+
detail: { id: ELEMENT_ID, type: WIDGET_ELEMENT_TYPE },
|
|
236
|
+
} )
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
expect( unmountSelector ).toHaveBeenCalledTimes( 1 );
|
|
240
|
+
} );
|
|
241
|
+
|
|
196
242
|
it( 'should call unmount callback when element is destroyed', () => {
|
|
197
243
|
// Arrange
|
|
198
244
|
const ELEMENT_ID = 'element-1';
|
|
@@ -200,7 +246,7 @@ describe( 'Frontend Handlers', () => {
|
|
|
200
246
|
|
|
201
247
|
register( {
|
|
202
248
|
elementType: WIDGET_ELEMENT_TYPE,
|
|
203
|
-
id:
|
|
249
|
+
id: HANDLER_IDS.handler_1,
|
|
204
250
|
callback: () => unmountCallback,
|
|
205
251
|
} );
|
|
206
252
|
|
|
@@ -233,7 +279,7 @@ describe( 'Frontend Handlers', () => {
|
|
|
233
279
|
|
|
234
280
|
register( {
|
|
235
281
|
elementType: WIDGET_ELEMENT_TYPE,
|
|
236
|
-
id:
|
|
282
|
+
id: HANDLER_IDS.handler_1,
|
|
237
283
|
callback: () => {
|
|
238
284
|
lifecycleEvents.push( 'init' );
|
|
239
285
|
return () => {
|
|
@@ -279,7 +325,7 @@ describe( 'Frontend Handlers', () => {
|
|
|
279
325
|
|
|
280
326
|
register( {
|
|
281
327
|
elementType: WIDGET_ELEMENT_TYPE,
|
|
282
|
-
id:
|
|
328
|
+
id: HANDLER_IDS.handler_1,
|
|
283
329
|
callback: ( { signal } ) => {
|
|
284
330
|
receivedSignal = signal;
|
|
285
331
|
return undefined;
|
|
@@ -310,7 +356,7 @@ describe( 'Frontend Handlers', () => {
|
|
|
310
356
|
|
|
311
357
|
register( {
|
|
312
358
|
elementType: WIDGET_ELEMENT_TYPE,
|
|
313
|
-
id:
|
|
359
|
+
id: HANDLER_IDS.handler_1,
|
|
314
360
|
callback: ( { signal } ) => {
|
|
315
361
|
signal.addEventListener( 'abort', () => {
|
|
316
362
|
signalAborted = true;
|
|
@@ -351,7 +397,7 @@ describe( 'Frontend Handlers', () => {
|
|
|
351
397
|
|
|
352
398
|
register( {
|
|
353
399
|
elementType: PARENT_ELEMENT_TYPE,
|
|
354
|
-
id:
|
|
400
|
+
id: HANDLER_IDS.handler_1,
|
|
355
401
|
callback: ( { listenToChildren } ) => {
|
|
356
402
|
listenToChildren( [ CHILD_ELEMENT_TYPE ] ).render( childRenderCallback );
|
|
357
403
|
return undefined;
|
|
@@ -394,7 +440,7 @@ describe( 'Frontend Handlers', () => {
|
|
|
394
440
|
|
|
395
441
|
register( {
|
|
396
442
|
elementType: PARENT_ELEMENT_TYPE,
|
|
397
|
-
id:
|
|
443
|
+
id: HANDLER_IDS.parent_handler,
|
|
398
444
|
callback: ( { listenToChildren } ) => {
|
|
399
445
|
listenToChildren( [ CHILD_ELEMENT_TYPE ] ).render( childRenderCallback );
|
|
400
446
|
return undefined;
|
|
@@ -436,7 +482,7 @@ describe( 'Frontend Handlers', () => {
|
|
|
436
482
|
|
|
437
483
|
register( {
|
|
438
484
|
elementType: PARENT_ELEMENT_TYPE,
|
|
439
|
-
id:
|
|
485
|
+
id: HANDLER_IDS.parent_handler,
|
|
440
486
|
callback: ( { listenToChildren } ) => {
|
|
441
487
|
listenToChildren( [ CHILD_ELEMENT_TYPE ] ).render( childRenderCallback );
|
|
442
488
|
return undefined;
|
|
@@ -490,7 +536,7 @@ describe( 'Frontend Handlers', () => {
|
|
|
490
536
|
|
|
491
537
|
register( {
|
|
492
538
|
elementType: PARENT_ELEMENT_TYPE,
|
|
493
|
-
id:
|
|
539
|
+
id: HANDLER_IDS.parent_handler,
|
|
494
540
|
callback: ( { element, listenToChildren } ) => {
|
|
495
541
|
const parentId = element.getAttribute( 'data-id' ) || 'unknown';
|
|
496
542
|
callbackCounts.set( parentId, 0 );
|
|
@@ -543,16 +589,70 @@ describe( 'Frontend Handlers', () => {
|
|
|
543
589
|
} );
|
|
544
590
|
|
|
545
591
|
describe( 'DOMContentLoaded Initialization', () => {
|
|
546
|
-
it( 'should
|
|
592
|
+
it( 'should skip selector initialization on page load when in editor', () => {
|
|
547
593
|
// Arrange
|
|
548
|
-
|
|
549
|
-
|
|
594
|
+
const ELEMENT_ID = 'element-1';
|
|
595
|
+
const selectorHandler = jest.fn();
|
|
596
|
+
|
|
597
|
+
registerBySelector( {
|
|
598
|
+
selector: SELECTOR_TARGET,
|
|
599
|
+
id: HANDLER_IDS.handler_1,
|
|
600
|
+
callback: selectorHandler,
|
|
601
|
+
} );
|
|
550
602
|
|
|
603
|
+
const element = document.createElement( 'div' );
|
|
604
|
+
element.classList.add( ELEMENT_CLASS );
|
|
605
|
+
element.setAttribute( 'data-id', ELEMENT_ID );
|
|
606
|
+
element.setAttribute( 'data-e-type', WIDGET_ELEMENT_TYPE );
|
|
607
|
+
document.body.appendChild( element );
|
|
608
|
+
|
|
609
|
+
const editorWindow = window as Window & { elementor?: unknown };
|
|
610
|
+
|
|
611
|
+
editorWindow.elementor = {};
|
|
612
|
+
|
|
613
|
+
document.dispatchEvent( new Event( 'DOMContentLoaded' ) );
|
|
614
|
+
|
|
615
|
+
expect( selectorHandler ).toHaveBeenCalledTimes( 1 );
|
|
616
|
+
} );
|
|
617
|
+
|
|
618
|
+
it( 'should initialize selector handlers on page load', () => {
|
|
619
|
+
// Arrange
|
|
620
|
+
const ELEMENT_ID = 'element-1';
|
|
621
|
+
const selectorHandler = jest.fn();
|
|
622
|
+
|
|
623
|
+
registerBySelector( {
|
|
624
|
+
selector: SELECTOR_TARGET,
|
|
625
|
+
id: HANDLER_IDS.handler_1,
|
|
626
|
+
callback: selectorHandler,
|
|
627
|
+
} );
|
|
628
|
+
|
|
629
|
+
const element = document.createElement( 'div' );
|
|
630
|
+
element.classList.add( ELEMENT_CLASS );
|
|
631
|
+
element.setAttribute( 'data-id', ELEMENT_ID );
|
|
632
|
+
element.setAttribute( 'data-e-type', WIDGET_ELEMENT_TYPE );
|
|
633
|
+
document.body.appendChild( element );
|
|
634
|
+
|
|
635
|
+
document.dispatchEvent( new Event( 'DOMContentLoaded' ) );
|
|
636
|
+
|
|
637
|
+
expect( selectorHandler ).toHaveBeenCalledTimes( 1 );
|
|
638
|
+
expect( selectorHandler ).toHaveBeenCalledWith(
|
|
639
|
+
expect.objectContaining( {
|
|
640
|
+
element,
|
|
641
|
+
settings: {},
|
|
642
|
+
signal: expect.any( AbortSignal ),
|
|
643
|
+
} )
|
|
644
|
+
);
|
|
645
|
+
} );
|
|
646
|
+
|
|
647
|
+
it( 'should initialize all existing elements on page load', () => {
|
|
648
|
+
// Arrange
|
|
649
|
+
const PARENT_ID = 'parent-1';
|
|
650
|
+
const WIDGET_ID = 'widget-1';
|
|
551
651
|
const initializedElements: string[] = [];
|
|
552
652
|
|
|
553
653
|
register( {
|
|
554
654
|
elementType: PARENT_ELEMENT_TYPE,
|
|
555
|
-
id:
|
|
655
|
+
id: HANDLER_IDS.parent_handler,
|
|
556
656
|
callback: ( { element } ) => {
|
|
557
657
|
const id = element.getAttribute( 'data-id' ) || 'unknown';
|
|
558
658
|
initializedElements.push( id );
|
|
@@ -562,7 +662,7 @@ describe( 'Frontend Handlers', () => {
|
|
|
562
662
|
|
|
563
663
|
register( {
|
|
564
664
|
elementType: WIDGET_ELEMENT_TYPE,
|
|
565
|
-
id:
|
|
665
|
+
id: HANDLER_IDS.handler_1,
|
|
566
666
|
callback: ( { element } ) => {
|
|
567
667
|
const id = element.getAttribute( 'data-id' ) || 'unknown';
|
|
568
668
|
initializedElements.push( id );
|
|
@@ -572,12 +672,12 @@ describe( 'Frontend Handlers', () => {
|
|
|
572
672
|
|
|
573
673
|
const parent = document.createElement( 'div' );
|
|
574
674
|
parent.setAttribute( 'data-e-type', PARENT_ELEMENT_TYPE );
|
|
575
|
-
parent.setAttribute( 'data-id',
|
|
675
|
+
parent.setAttribute( 'data-id', PARENT_ID );
|
|
576
676
|
document.body.appendChild( parent );
|
|
577
677
|
|
|
578
678
|
const widget = document.createElement( 'div' );
|
|
579
679
|
widget.setAttribute( 'data-e-type', WIDGET_ELEMENT_TYPE );
|
|
580
|
-
widget.setAttribute( 'data-id',
|
|
680
|
+
widget.setAttribute( 'data-id', WIDGET_ID );
|
|
581
681
|
document.body.appendChild( widget );
|
|
582
682
|
|
|
583
683
|
init();
|
|
@@ -586,8 +686,8 @@ describe( 'Frontend Handlers', () => {
|
|
|
586
686
|
document.dispatchEvent( new Event( 'DOMContentLoaded' ) );
|
|
587
687
|
|
|
588
688
|
// Assert
|
|
589
|
-
expect( initializedElements ).toContain(
|
|
590
|
-
expect( initializedElements ).toContain(
|
|
689
|
+
expect( initializedElements ).toContain( PARENT_ID );
|
|
690
|
+
expect( initializedElements ).toContain( WIDGET_ID );
|
|
591
691
|
} );
|
|
592
692
|
} );
|
|
593
693
|
} );
|
package/src/handlers-registry.ts
CHANGED
|
@@ -77,12 +77,12 @@ export const unregisterBySelector = ( { selector, id }: { selector: string; id?:
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
if ( id ) {
|
|
80
|
-
|
|
80
|
+
elementSelectorHandlers.get( selector )?.delete( id );
|
|
81
81
|
|
|
82
|
-
if (
|
|
83
|
-
|
|
82
|
+
if ( elementSelectorHandlers.get( selector )?.size === 0 ) {
|
|
83
|
+
elementSelectorHandlers.delete( selector );
|
|
84
84
|
}
|
|
85
85
|
} else {
|
|
86
|
-
|
|
86
|
+
elementSelectorHandlers.delete( selector );
|
|
87
87
|
}
|
|
88
88
|
};
|
package/src/init.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { onElementDestroy, onElementRender, onElementSelectorRender } from './lifecycle-events';
|
|
1
|
+
import { onElementDestroy, onElementRender } from './lifecycle-events';
|
|
3
2
|
|
|
4
3
|
export function init() {
|
|
5
4
|
window.addEventListener( 'elementor/element/render', ( _event ) => {
|
|
@@ -19,12 +18,10 @@ export function init() {
|
|
|
19
18
|
onElementDestroy( { elementType: type, elementId: id } );
|
|
20
19
|
} );
|
|
21
20
|
|
|
21
|
+
// 'elementor/element/render' doesn't fire on the frontend
|
|
22
22
|
document.addEventListener( 'DOMContentLoaded', () => {
|
|
23
|
-
const controller = new AbortController();
|
|
24
|
-
|
|
25
23
|
document.querySelectorAll( '[data-e-type]' ).forEach( ( element ) => {
|
|
26
24
|
const el = element as HTMLElement;
|
|
27
|
-
|
|
28
25
|
const { eType, id } = el.dataset;
|
|
29
26
|
|
|
30
27
|
if ( ! eType || ! id ) {
|
|
@@ -41,18 +38,5 @@ export function init() {
|
|
|
41
38
|
} )
|
|
42
39
|
);
|
|
43
40
|
} );
|
|
44
|
-
|
|
45
|
-
Array.from( elementSelectorHandlers.keys() ).forEach( ( selector ) => {
|
|
46
|
-
Array.from( document.querySelectorAll( selector ) ).forEach( ( element ) => {
|
|
47
|
-
const el = element as HTMLElement;
|
|
48
|
-
const elementId = el?.closest( '[data-id]' )?.getAttribute( 'data-id' ) ?? '';
|
|
49
|
-
|
|
50
|
-
onElementSelectorRender( {
|
|
51
|
-
element,
|
|
52
|
-
controller,
|
|
53
|
-
elementId,
|
|
54
|
-
} );
|
|
55
|
-
} );
|
|
56
|
-
} );
|
|
57
41
|
} );
|
|
58
42
|
}
|
package/src/lifecycle-events.ts
CHANGED
|
@@ -18,6 +18,8 @@ export const onElementRender = ( {
|
|
|
18
18
|
const manualUnmount: ( () => void )[] = [];
|
|
19
19
|
|
|
20
20
|
const dispatchRenderedEvent = () => {
|
|
21
|
+
onElementSelectorRender( { element, elementId, controller } );
|
|
22
|
+
|
|
21
23
|
element.dispatchEvent(
|
|
22
24
|
new CustomEvent( ELEMENT_RENDERED_EVENT_NAME, {
|
|
23
25
|
bubbles: true,
|
|
@@ -30,7 +32,7 @@ export const onElementRender = ( {
|
|
|
30
32
|
);
|
|
31
33
|
};
|
|
32
34
|
|
|
33
|
-
// When the rendered event is dispatched, the element is not yet connected to the DOM (
|
|
35
|
+
// When the rendered event is dispatched, the element is not yet connected to the DOM (marionette view case)
|
|
34
36
|
if ( ! element.isConnected ) {
|
|
35
37
|
requestAnimationFrame( () => {
|
|
36
38
|
dispatchRenderedEvent();
|
|
@@ -117,8 +119,12 @@ export const onElementSelectorRender = ( {
|
|
|
117
119
|
}
|
|
118
120
|
} );
|
|
119
121
|
|
|
120
|
-
if ( !
|
|
121
|
-
|
|
122
|
+
if ( ! manualUnmount.length ) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if ( ! unmountElementSelectorCallbacks.get( elementId ) ) {
|
|
127
|
+
unmountElementSelectorCallbacks.set( elementId, new Map() );
|
|
122
128
|
}
|
|
123
129
|
|
|
124
130
|
unmountElementSelectorCallbacks.get( elementId )?.set( selector, () => {
|
|
@@ -131,16 +137,26 @@ export const onElementSelectorRender = ( {
|
|
|
131
137
|
|
|
132
138
|
export const onElementDestroy = ( { elementType, elementId }: { elementType: string; elementId: string } ) => {
|
|
133
139
|
const unmount = unmountElementTypeCallbacks.get( elementType )?.get( elementId );
|
|
140
|
+
const unmountSelector = unmountElementSelectorCallbacks.get( elementId );
|
|
134
141
|
|
|
135
|
-
if (
|
|
136
|
-
|
|
142
|
+
if ( unmount ) {
|
|
143
|
+
unmount();
|
|
137
144
|
}
|
|
138
145
|
|
|
139
|
-
|
|
146
|
+
if ( unmountSelector?.size ) {
|
|
147
|
+
Array.from( unmountSelector.values() ).forEach( ( selectorUnmount ) => {
|
|
148
|
+
selectorUnmount();
|
|
149
|
+
} );
|
|
150
|
+
}
|
|
140
151
|
|
|
141
152
|
unmountElementTypeCallbacks.get( elementType )?.delete( elementId );
|
|
153
|
+
unmountElementSelectorCallbacks.delete( elementId );
|
|
142
154
|
|
|
143
155
|
if ( unmountElementTypeCallbacks.get( elementType )?.size === 0 ) {
|
|
144
156
|
unmountElementTypeCallbacks.delete( elementType );
|
|
145
157
|
}
|
|
158
|
+
|
|
159
|
+
if ( unmountElementSelectorCallbacks.size === 0 ) {
|
|
160
|
+
unmountElementSelectorCallbacks.delete( elementId );
|
|
161
|
+
}
|
|
146
162
|
};
|