@elementor/editor-canvas 4.4.0-1112 → 4.4.0-1114

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
@@ -2835,14 +2835,17 @@ function isRecord(value) {
2835
2835
  var import_editor_elements5 = require("@elementor/editor-elements");
2836
2836
  function createPendingElement(wrapperView, data, options = {}) {
2837
2837
  const parentContainer = wrapperView.getContainer();
2838
- const model = { ...data };
2839
- if (!model.id) {
2838
+ const model = options.clone ? (0, import_editor_elements5.cloneElementTree)(data) : { ...data };
2839
+ if (!options.clone && !model.id) {
2840
2840
  model.id = (0, import_editor_elements5.generateElementId)();
2841
2841
  }
2842
2842
  if (!model.elements) {
2843
2843
  model.elements = [];
2844
2844
  }
2845
- const added = (0, import_editor_elements5.addModelToParent)(parentContainer.id, model, options);
2845
+ const added = (0, import_editor_elements5.addModelToParent)(parentContainer.id, model, {
2846
+ ...options,
2847
+ clone: false
2848
+ });
2846
2849
  if (!added) {
2847
2850
  return void 0;
2848
2851
  }
package/dist/index.mjs CHANGED
@@ -2791,20 +2791,24 @@ function isRecord(value) {
2791
2791
  // src/legacy/create-pending-element.ts
2792
2792
  import {
2793
2793
  addModelToParent,
2794
+ cloneElementTree,
2794
2795
  findModelInDocument,
2795
2796
  generateElementId,
2796
2797
  getContainer
2797
2798
  } from "@elementor/editor-elements";
2798
2799
  function createPendingElement(wrapperView, data, options = {}) {
2799
2800
  const parentContainer = wrapperView.getContainer();
2800
- const model = { ...data };
2801
- if (!model.id) {
2801
+ const model = options.clone ? cloneElementTree(data) : { ...data };
2802
+ if (!options.clone && !model.id) {
2802
2803
  model.id = generateElementId();
2803
2804
  }
2804
2805
  if (!model.elements) {
2805
2806
  model.elements = [];
2806
2807
  }
2807
- const added = addModelToParent(parentContainer.id, model, options);
2808
+ const added = addModelToParent(parentContainer.id, model, {
2809
+ ...options,
2810
+ clone: false
2811
+ });
2808
2812
  if (!added) {
2809
2813
  return void 0;
2810
2814
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-canvas",
3
3
  "description": "Elementor Editor Canvas",
4
- "version": "4.4.0-1112",
4
+ "version": "4.4.0-1114",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -37,26 +37,26 @@
37
37
  "react-dom": "^18.3.1"
38
38
  },
39
39
  "dependencies": {
40
- "@elementor/editor": "4.4.0-1112",
41
- "@elementor/editor-controls": "4.4.0-1112",
42
- "@elementor/editor-documents": "4.4.0-1112",
43
- "@elementor/editor-elements": "4.4.0-1112",
44
- "@elementor/editor-interactions": "4.4.0-1112",
45
- "@elementor/editor-mcp": "4.4.0-1112",
46
- "@elementor/editor-notifications": "4.4.0-1112",
47
- "@elementor/editor-props": "4.4.0-1112",
48
- "@elementor/editor-responsive": "4.4.0-1112",
49
- "@elementor/editor-styles": "4.4.0-1112",
50
- "@elementor/editor-styles-repository": "4.4.0-1112",
51
- "@elementor/editor-ui": "4.4.0-1112",
52
- "@elementor/editor-v1-adapters": "4.4.0-1112",
53
- "@elementor/events": "4.4.0-1112",
54
- "@elementor/http-client": "4.4.0-1112",
55
- "@elementor/schema": "4.4.0-1112",
56
- "@elementor/twing": "4.4.0-1112",
40
+ "@elementor/editor": "4.4.0-1114",
41
+ "@elementor/editor-controls": "4.4.0-1114",
42
+ "@elementor/editor-documents": "4.4.0-1114",
43
+ "@elementor/editor-elements": "4.4.0-1114",
44
+ "@elementor/editor-interactions": "4.4.0-1114",
45
+ "@elementor/editor-mcp": "4.4.0-1114",
46
+ "@elementor/editor-notifications": "4.4.0-1114",
47
+ "@elementor/editor-props": "4.4.0-1114",
48
+ "@elementor/editor-responsive": "4.4.0-1114",
49
+ "@elementor/editor-styles": "4.4.0-1114",
50
+ "@elementor/editor-styles-repository": "4.4.0-1114",
51
+ "@elementor/editor-ui": "4.4.0-1114",
52
+ "@elementor/editor-v1-adapters": "4.4.0-1114",
53
+ "@elementor/events": "4.4.0-1114",
54
+ "@elementor/http-client": "4.4.0-1114",
55
+ "@elementor/schema": "4.4.0-1114",
56
+ "@elementor/twing": "4.4.0-1114",
57
57
  "@elementor/ui": "1.37.5",
58
- "@elementor/utils": "4.4.0-1112",
59
- "@elementor/wp-media": "4.4.0-1112",
58
+ "@elementor/utils": "4.4.0-1114",
59
+ "@elementor/wp-media": "4.4.0-1114",
60
60
  "@floating-ui/react": "^0.27.5",
61
61
  "@wordpress/i18n": "^5.13.0",
62
62
  "dompurify": "^3.2.6"
@@ -0,0 +1,128 @@
1
+ import { createMockElement } from 'test-utils';
2
+ import { addModelToParent, findModelInDocument, type V1ElementModelProps } from '@elementor/editor-elements';
3
+
4
+ import { createPendingElement } from '../create-pending-element';
5
+ import { type ElementView } from '../types';
6
+
7
+ jest.mock( '@elementor/editor-elements', () => ( {
8
+ ...jest.requireActual( '@elementor/editor-elements' ),
9
+ addModelToParent: jest.fn(),
10
+ findModelInDocument: jest.fn(),
11
+ getContainer: jest.fn(),
12
+ } ) );
13
+
14
+ const mockAddModelToParent = jest.mocked( addModelToParent );
15
+ const mockFindModelInDocument = jest.mocked( findModelInDocument );
16
+
17
+ describe( 'createPendingElement', () => {
18
+ beforeEach( () => {
19
+ (
20
+ window as typeof window & {
21
+ elementorCommon?: { helpers?: { getUniqueId?: jest.Mock } };
22
+ }
23
+ ).elementorCommon = {
24
+ helpers: {
25
+ getUniqueId: jest
26
+ .fn()
27
+ .mockReturnValueOnce( 'cloned-parent-id' )
28
+ .mockReturnValueOnce( 'cloned-child-id' ),
29
+ },
30
+ };
31
+
32
+ mockAddModelToParent.mockClear();
33
+ mockFindModelInDocument.mockClear();
34
+ mockAddModelToParent.mockReturnValue( true );
35
+ mockFindModelInDocument.mockReturnValue( createMockElement( {} ) as never );
36
+ } );
37
+
38
+ afterEach( () => {
39
+ delete ( window as typeof window & { elementorCommon?: unknown } ).elementorCommon;
40
+ } );
41
+
42
+ it( 'regenerates ids before pending clone insertion', () => {
43
+ // Arrange.
44
+ const wrapperView = {
45
+ getContainer: () => ( { id: 'parent-id' } ),
46
+ once: jest.fn(),
47
+ model: {
48
+ trigger: jest.fn(),
49
+ },
50
+ } as unknown as ElementView;
51
+
52
+ const source = {
53
+ id: 'original-parent-id',
54
+ elType: 'container',
55
+ settings: { _element_id: 'original-parent-element-id' },
56
+ elements: [
57
+ {
58
+ id: 'original-child-id',
59
+ elType: 'widget',
60
+ widgetType: 'button',
61
+ settings: { _element_id: 'original-child-element-id' },
62
+ elements: [],
63
+ },
64
+ ],
65
+ } as unknown as Partial< V1ElementModelProps >;
66
+
67
+ // Act.
68
+ const pendingElement = createPendingElement( wrapperView, source, { clone: true } );
69
+
70
+ // Assert.
71
+ expect( pendingElement?.getContainer().id ).toBe( 'cloned-parent-id' );
72
+ expect( mockAddModelToParent ).toHaveBeenCalledWith(
73
+ 'parent-id',
74
+ expect.objectContaining( {
75
+ id: 'cloned-parent-id',
76
+ settings: expect.objectContaining( { _element_id: '' } ),
77
+ elements: [
78
+ expect.objectContaining( {
79
+ id: 'cloned-child-id',
80
+ settings: expect.objectContaining( { _element_id: '' } ),
81
+ } ),
82
+ ],
83
+ } ),
84
+ expect.objectContaining( {
85
+ clone: false,
86
+ } )
87
+ );
88
+ expect( mockFindModelInDocument ).toHaveBeenCalledWith( 'cloned-parent-id' );
89
+ } );
90
+
91
+ it( 'preserves the source id when clone is false', () => {
92
+ // Arrange.
93
+ const wrapperView = {
94
+ getContainer: () => ( { id: 'parent-id' } ),
95
+ once: jest.fn(),
96
+ model: {
97
+ trigger: jest.fn(),
98
+ },
99
+ } as unknown as ElementView;
100
+
101
+ const source = {
102
+ id: 'original-parent-id',
103
+ elType: 'widget',
104
+ widgetType: 'button',
105
+ settings: { _element_id: 'original-parent-element-id' },
106
+ elements: [],
107
+ };
108
+
109
+ // Act.
110
+ const pendingElement = createPendingElement( wrapperView, source, { clone: false } );
111
+
112
+ // Assert.
113
+ expect( pendingElement?.getContainer().id ).toBe( 'original-parent-id' );
114
+ expect( mockAddModelToParent ).toHaveBeenCalledWith(
115
+ 'parent-id',
116
+ expect.objectContaining( {
117
+ id: 'original-parent-id',
118
+ settings: expect.objectContaining( {
119
+ _element_id: 'original-parent-element-id',
120
+ } ),
121
+ } ),
122
+ expect.objectContaining( {
123
+ clone: false,
124
+ } )
125
+ );
126
+ expect( mockFindModelInDocument ).toHaveBeenCalledWith( 'original-parent-id' );
127
+ } );
128
+ } );
@@ -422,7 +422,7 @@ export function createNestedTemplatedElementView( {
422
422
  this._doAfterRender( () => parentOpenEditingPanel.call( this, options ) );
423
423
  },
424
424
 
425
- addElement( data: Partial< V1ElementModelProps >, options?: { edit?: boolean; at?: number } ) {
425
+ addElement( data: Partial< V1ElementModelProps >, options?: { edit?: boolean; at?: number; clone?: boolean } ) {
426
426
  if ( this.isRendered ) {
427
427
  return parentAddElement.call( this, data, options );
428
428
  }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  addModelToParent,
3
+ cloneElementTree,
3
4
  findModelInDocument,
4
5
  generateElementId,
5
6
  getContainer,
@@ -12,12 +13,12 @@ import { type ElementView } from './types';
12
13
  export function createPendingElement(
13
14
  wrapperView: ElementView,
14
15
  data: Partial< V1ElementModelProps >,
15
- options: { edit?: boolean; at?: number } = {}
16
+ options: { edit?: boolean; at?: number; clone?: boolean } = {}
16
17
  ): { getContainer: () => V1Element } | undefined {
17
18
  const parentContainer = wrapperView.getContainer();
18
- const model: Partial< V1ElementModelProps > = { ...data };
19
+ const model: Partial< V1ElementModelProps > = options.clone ? cloneElementTree( data ) : { ...data };
19
20
 
20
- if ( ! model.id ) {
21
+ if ( ! options.clone && ! model.id ) {
21
22
  model.id = generateElementId();
22
23
  }
23
24
 
@@ -25,13 +26,16 @@ export function createPendingElement(
25
26
  model.elements = [];
26
27
  }
27
28
 
28
- const added = addModelToParent( parentContainer.id, model as V1ElementModelProps, options );
29
+ const added = addModelToParent( parentContainer.id, model as V1ElementModelProps, {
30
+ ...options,
31
+ clone: false,
32
+ } );
29
33
 
30
34
  if ( ! added ) {
31
35
  return undefined;
32
36
  }
33
37
 
34
- const childId = model.id;
38
+ const childId = model.id as string;
35
39
  const childModel = findModelInDocument( childId );
36
40
 
37
41
  if ( ! childModel ) {