@elementor/frontend-handlers 3.35.0-429 → 3.35.0-431

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 CHANGED
@@ -82,6 +82,15 @@ var unregisterBySelector = ({ selector, id }) => {
82
82
  var unmountElementTypeCallbacks = /* @__PURE__ */ new Map();
83
83
  var unmountElementSelectorCallbacks = /* @__PURE__ */ new Map();
84
84
  var ELEMENT_RENDERED_EVENT_NAME = "elementor/element/rendered";
85
+ var ELEMENT_DESTROYED_EVENT_NAME = "elementor/element/destroyed";
86
+ var dispatchDestroyedEvent = (params) => {
87
+ params.element.dispatchEvent(
88
+ new CustomEvent(ELEMENT_DESTROYED_EVENT_NAME, {
89
+ bubbles: true,
90
+ detail: params
91
+ })
92
+ );
93
+ };
85
94
  var onElementRender = ({
86
95
  element,
87
96
  elementType,
@@ -116,17 +125,15 @@ var onElementRender = ({
116
125
  const settings = element.getAttribute("data-e-settings");
117
126
  const listenToChildren = (elementTypes) => ({
118
127
  render: (callback) => {
119
- element.addEventListener(
120
- ELEMENT_RENDERED_EVENT_NAME,
121
- (event) => {
122
- const { elementType: childType } = event.detail;
123
- if (!elementTypes.includes(childType)) {
124
- return;
125
- }
126
- callback();
127
- },
128
- { signal: controller.signal }
129
- );
128
+ const listener = (event) => {
129
+ const { elementType: childType } = event.detail;
130
+ if (!elementTypes.includes(childType)) {
131
+ return;
132
+ }
133
+ callback();
134
+ };
135
+ element.addEventListener(ELEMENT_RENDERED_EVENT_NAME, listener, { signal: controller.signal });
136
+ element.addEventListener(ELEMENT_DESTROYED_EVENT_NAME, listener, { signal: controller.signal });
130
137
  }
131
138
  });
132
139
  const unmount = handler({
@@ -180,9 +187,16 @@ var onElementSelectorRender = ({
180
187
  });
181
188
  });
182
189
  };
183
- var onElementDestroy = ({ elementType, elementId }) => {
190
+ var onElementDestroy = ({
191
+ elementType,
192
+ elementId,
193
+ element
194
+ }) => {
184
195
  const unmount = unmountElementTypeCallbacks.get(elementType)?.get(elementId);
185
196
  const unmountSelector = unmountElementSelectorCallbacks.get(elementId);
197
+ if (element) {
198
+ dispatchDestroyedEvent({ element, elementType, elementId });
199
+ }
186
200
  if (unmount) {
187
201
  unmount();
188
202
  }
@@ -211,8 +225,8 @@ function init() {
211
225
  });
212
226
  window.addEventListener("elementor/element/destroy", (_event) => {
213
227
  const event = _event;
214
- const { id, type } = event.detail;
215
- onElementDestroy({ elementType: type, elementId: id });
228
+ const { id, type, element } = event.detail;
229
+ onElementDestroy({ elementType: type, elementId: id, element });
216
230
  });
217
231
  document.addEventListener("DOMContentLoaded", () => {
218
232
  document.querySelectorAll("[data-e-type]").forEach((element) => {
package/dist/index.mjs CHANGED
@@ -52,6 +52,15 @@ var unregisterBySelector = ({ selector, id }) => {
52
52
  var unmountElementTypeCallbacks = /* @__PURE__ */ new Map();
53
53
  var unmountElementSelectorCallbacks = /* @__PURE__ */ new Map();
54
54
  var ELEMENT_RENDERED_EVENT_NAME = "elementor/element/rendered";
55
+ var ELEMENT_DESTROYED_EVENT_NAME = "elementor/element/destroyed";
56
+ var dispatchDestroyedEvent = (params) => {
57
+ params.element.dispatchEvent(
58
+ new CustomEvent(ELEMENT_DESTROYED_EVENT_NAME, {
59
+ bubbles: true,
60
+ detail: params
61
+ })
62
+ );
63
+ };
55
64
  var onElementRender = ({
56
65
  element,
57
66
  elementType,
@@ -86,17 +95,15 @@ var onElementRender = ({
86
95
  const settings = element.getAttribute("data-e-settings");
87
96
  const listenToChildren = (elementTypes) => ({
88
97
  render: (callback) => {
89
- element.addEventListener(
90
- ELEMENT_RENDERED_EVENT_NAME,
91
- (event) => {
92
- const { elementType: childType } = event.detail;
93
- if (!elementTypes.includes(childType)) {
94
- return;
95
- }
96
- callback();
97
- },
98
- { signal: controller.signal }
99
- );
98
+ const listener = (event) => {
99
+ const { elementType: childType } = event.detail;
100
+ if (!elementTypes.includes(childType)) {
101
+ return;
102
+ }
103
+ callback();
104
+ };
105
+ element.addEventListener(ELEMENT_RENDERED_EVENT_NAME, listener, { signal: controller.signal });
106
+ element.addEventListener(ELEMENT_DESTROYED_EVENT_NAME, listener, { signal: controller.signal });
100
107
  }
101
108
  });
102
109
  const unmount = handler({
@@ -150,9 +157,16 @@ var onElementSelectorRender = ({
150
157
  });
151
158
  });
152
159
  };
153
- var onElementDestroy = ({ elementType, elementId }) => {
160
+ var onElementDestroy = ({
161
+ elementType,
162
+ elementId,
163
+ element
164
+ }) => {
154
165
  const unmount = unmountElementTypeCallbacks.get(elementType)?.get(elementId);
155
166
  const unmountSelector = unmountElementSelectorCallbacks.get(elementId);
167
+ if (element) {
168
+ dispatchDestroyedEvent({ element, elementType, elementId });
169
+ }
156
170
  if (unmount) {
157
171
  unmount();
158
172
  }
@@ -181,8 +195,8 @@ function init() {
181
195
  });
182
196
  window.addEventListener("elementor/element/destroy", (_event) => {
183
197
  const event = _event;
184
- const { id, type } = event.detail;
185
- onElementDestroy({ elementType: type, elementId: id });
198
+ const { id, type, element } = event.detail;
199
+ onElementDestroy({ elementType: type, elementId: id, element });
186
200
  });
187
201
  document.addEventListener("DOMContentLoaded", () => {
188
202
  document.querySelectorAll("[data-e-type]").forEach((element) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/frontend-handlers",
3
3
  "description": "Elementor Frontend Handlers",
4
- "version": "3.35.0-429",
4
+ "version": "3.35.0-431",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -264,7 +264,7 @@ describe( 'Frontend Handlers', () => {
264
264
  // Act
265
265
  window.dispatchEvent(
266
266
  new CustomEvent( 'elementor/element/destroy', {
267
- detail: { id: ELEMENT_ID, type: WIDGET_ELEMENT_TYPE },
267
+ detail: { id: ELEMENT_ID, type: WIDGET_ELEMENT_TYPE, element },
268
268
  } )
269
269
  );
270
270
 
@@ -272,6 +272,50 @@ describe( 'Frontend Handlers', () => {
272
272
  expect( unmountCallback ).toHaveBeenCalledTimes( 1 );
273
273
  } );
274
274
 
275
+ it( 'should dispatch destroyed event when element is destroyed', () => {
276
+ // Arrange
277
+ const ELEMENT_ID = 'element-1';
278
+ const destroyedEventCallback = jest.fn();
279
+
280
+ register( {
281
+ elementType: WIDGET_ELEMENT_TYPE,
282
+ id: 'widget-handler',
283
+ callback: () => undefined,
284
+ } );
285
+
286
+ const element = document.createElement( 'div' );
287
+ element.setAttribute( 'data-e-type', WIDGET_ELEMENT_TYPE );
288
+ element.setAttribute( 'data-id', ELEMENT_ID );
289
+ document.body.appendChild( element );
290
+
291
+ window.dispatchEvent(
292
+ new CustomEvent( 'elementor/element/render', {
293
+ detail: { id: ELEMENT_ID, type: WIDGET_ELEMENT_TYPE, element },
294
+ } )
295
+ );
296
+
297
+ element.addEventListener( 'elementor/element/destroyed', destroyedEventCallback );
298
+
299
+ // Act
300
+ window.dispatchEvent(
301
+ new CustomEvent( 'elementor/element/destroy', {
302
+ detail: { id: ELEMENT_ID, type: WIDGET_ELEMENT_TYPE, element },
303
+ } )
304
+ );
305
+
306
+ // Assert
307
+ expect( destroyedEventCallback ).toHaveBeenCalledTimes( 1 );
308
+ expect( destroyedEventCallback ).toHaveBeenCalledWith(
309
+ expect.objectContaining( {
310
+ detail: expect.objectContaining( {
311
+ element,
312
+ elementType: WIDGET_ELEMENT_TYPE,
313
+ elementId: ELEMENT_ID,
314
+ } ),
315
+ } )
316
+ );
317
+ } );
318
+
275
319
  it( 'should cleanup on re-render before new initialization', () => {
276
320
  // Arrange
277
321
  const ELEMENT_ID = 'element-1';
@@ -379,7 +423,7 @@ describe( 'Frontend Handlers', () => {
379
423
  // Act
380
424
  window.dispatchEvent(
381
425
  new CustomEvent( 'elementor/element/destroy', {
382
- detail: { id: ELEMENT_ID, type: WIDGET_ELEMENT_TYPE },
426
+ detail: { id: ELEMENT_ID, type: WIDGET_ELEMENT_TYPE, element },
383
427
  } )
384
428
  );
385
429
 
@@ -432,6 +476,62 @@ describe( 'Frontend Handlers', () => {
432
476
  expect( childRenderCallback ).toHaveBeenCalledTimes( 1 );
433
477
  } );
434
478
 
479
+ it( 'should trigger destroy callback when child of specified type is destroyed', () => {
480
+ // Arrange
481
+ const PARENT_ID = 'parent-1';
482
+ const CHILD_ID = 'child-1';
483
+ const childDestroyCallback = jest.fn();
484
+
485
+ register( {
486
+ elementType: PARENT_ELEMENT_TYPE,
487
+ id: 'parent-handler',
488
+ callback: ( { listenToChildren } ) => {
489
+ listenToChildren( [ CHILD_ELEMENT_TYPE ] ).render( childDestroyCallback );
490
+ return undefined;
491
+ },
492
+ } );
493
+
494
+ register( {
495
+ elementType: CHILD_ELEMENT_TYPE,
496
+ id: 'child-handler',
497
+ callback: () => undefined,
498
+ } );
499
+
500
+ const parent = document.createElement( 'div' );
501
+ parent.setAttribute( 'data-e-type', PARENT_ELEMENT_TYPE );
502
+ parent.setAttribute( 'data-id', PARENT_ID );
503
+ document.body.appendChild( parent );
504
+
505
+ const child = document.createElement( 'div' );
506
+ child.setAttribute( 'data-e-type', CHILD_ELEMENT_TYPE );
507
+ child.setAttribute( 'data-id', CHILD_ID );
508
+ parent.appendChild( child );
509
+
510
+ window.dispatchEvent(
511
+ new CustomEvent( 'elementor/element/render', {
512
+ detail: { id: PARENT_ID, type: PARENT_ELEMENT_TYPE, element: parent },
513
+ } )
514
+ );
515
+
516
+ window.dispatchEvent(
517
+ new CustomEvent( 'elementor/element/render', {
518
+ detail: { id: CHILD_ID, type: CHILD_ELEMENT_TYPE, element: child },
519
+ } )
520
+ );
521
+
522
+ childDestroyCallback.mockClear();
523
+
524
+ // Act
525
+ window.dispatchEvent(
526
+ new CustomEvent( 'elementor/element/destroy', {
527
+ detail: { id: CHILD_ID, type: CHILD_ELEMENT_TYPE, element: child },
528
+ } )
529
+ );
530
+
531
+ // Assert
532
+ expect( childDestroyCallback ).toHaveBeenCalledTimes( 1 );
533
+ } );
534
+
435
535
  it( 'should not trigger callback for non-descendant elements', () => {
436
536
  // Arrange
437
537
  const PARENT_ID = 'parent-1';
@@ -509,7 +609,7 @@ describe( 'Frontend Handlers', () => {
509
609
  // Destroy Parent (should remove listener)
510
610
  window.dispatchEvent(
511
611
  new CustomEvent( 'elementor/element/destroy', {
512
- detail: { id: PARENT_ID, type: PARENT_ELEMENT_TYPE },
612
+ detail: { id: PARENT_ID, type: PARENT_ELEMENT_TYPE, element: parent },
513
613
  } )
514
614
  );
515
615
 
package/src/init.ts CHANGED
@@ -12,10 +12,10 @@ export function init() {
12
12
  } );
13
13
 
14
14
  window.addEventListener( 'elementor/element/destroy', ( _event ) => {
15
- const event = _event as CustomEvent< { id: string; type: string } >;
16
- const { id, type } = event.detail;
15
+ const event = _event as CustomEvent< { id: string; type: string; element: Element } >;
16
+ const { id, type, element } = event.detail;
17
17
 
18
- onElementDestroy( { elementType: type, elementId: id } );
18
+ onElementDestroy( { elementType: type, elementId: id, element } );
19
19
  } );
20
20
 
21
21
  // 'elementor/element/render' doesn't fire on the frontend
@@ -4,6 +4,22 @@ const unmountElementTypeCallbacks: Map< string, Map< string, () => void > > = ne
4
4
  const unmountElementSelectorCallbacks: Map< string, Map< string, () => void > > = new Map();
5
5
 
6
6
  const ELEMENT_RENDERED_EVENT_NAME = 'elementor/element/rendered';
7
+ const ELEMENT_DESTROYED_EVENT_NAME = 'elementor/element/destroyed';
8
+
9
+ type LifecycleEventParams = {
10
+ element: Element;
11
+ elementType: string;
12
+ elementId: string;
13
+ };
14
+
15
+ const dispatchDestroyedEvent = ( params: LifecycleEventParams ) => {
16
+ params.element.dispatchEvent(
17
+ new CustomEvent( ELEMENT_DESTROYED_EVENT_NAME, {
18
+ bubbles: true,
19
+ detail: params,
20
+ } )
21
+ );
22
+ };
7
23
 
8
24
  export const onElementRender = ( {
9
25
  element,
@@ -50,19 +66,18 @@ export const onElementRender = ( {
50
66
 
51
67
  const listenToChildren = ( elementTypes: string[] ) => ( {
52
68
  render: ( callback: () => void ) => {
53
- element.addEventListener(
54
- ELEMENT_RENDERED_EVENT_NAME,
55
- ( event ) => {
56
- const { elementType: childType } = ( event as CustomEvent ).detail;
57
-
58
- if ( ! elementTypes.includes( childType ) ) {
59
- return;
60
- }
61
-
62
- callback();
63
- },
64
- { signal: controller.signal }
65
- );
69
+ const listener = ( event: Event ) => {
70
+ const { elementType: childType } = ( event as CustomEvent ).detail;
71
+
72
+ if ( ! elementTypes.includes( childType ) ) {
73
+ return;
74
+ }
75
+
76
+ callback();
77
+ };
78
+
79
+ element.addEventListener( ELEMENT_RENDERED_EVENT_NAME, listener, { signal: controller.signal } );
80
+ element.addEventListener( ELEMENT_DESTROYED_EVENT_NAME, listener, { signal: controller.signal } );
66
81
  },
67
82
  } );
68
83
 
@@ -135,10 +150,22 @@ export const onElementSelectorRender = ( {
135
150
  } );
136
151
  };
137
152
 
138
- export const onElementDestroy = ( { elementType, elementId }: { elementType: string; elementId: string } ) => {
153
+ export const onElementDestroy = ( {
154
+ elementType,
155
+ elementId,
156
+ element,
157
+ }: {
158
+ elementType: string;
159
+ elementId: string;
160
+ element?: Element;
161
+ } ) => {
139
162
  const unmount = unmountElementTypeCallbacks.get( elementType )?.get( elementId );
140
163
  const unmountSelector = unmountElementSelectorCallbacks.get( elementId );
141
164
 
165
+ if ( element ) {
166
+ dispatchDestroyedEvent( { element, elementType, elementId } );
167
+ }
168
+
142
169
  if ( unmount ) {
143
170
  unmount();
144
171
  }