@elementor/editor-elements 3.33.0-99 → 3.35.0-324
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.d.mts +200 -99
- package/dist/index.d.ts +200 -99
- package/dist/index.js +1161 -394
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1158 -401
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -5
- package/src/errors.ts +10 -0
- package/src/hooks/use-element-children.ts +12 -12
- package/src/hooks/use-element-editor-settings.ts +12 -0
- package/src/hooks/use-element-interactions.ts +25 -0
- package/src/hooks/use-element-setting.ts +1 -1
- package/src/hooks/use-selected-element.ts +2 -2
- package/src/index.ts +38 -27
- package/src/mcp/elements-tool.ts +345 -0
- package/src/mcp/handlers/common-style-utils.ts +23 -0
- package/src/mcp/handlers/create-element.ts +96 -0
- package/src/mcp/handlers/create-style.ts +42 -0
- package/src/mcp/handlers/delete-element.ts +17 -0
- package/src/mcp/handlers/delete-style.ts +22 -0
- package/src/mcp/handlers/deselect-element.ts +21 -0
- package/src/mcp/handlers/duplicate-element.ts +22 -0
- package/src/mcp/handlers/get-element-props.ts +28 -0
- package/src/mcp/handlers/get-element-schema.ts +17 -0
- package/src/mcp/handlers/get-selected.ts +5 -0
- package/src/mcp/handlers/get-styles.ts +26 -0
- package/src/mcp/handlers/list-available-types.ts +27 -0
- package/src/mcp/handlers/move-element.ts +30 -0
- package/src/mcp/handlers/select-element.ts +25 -0
- package/src/mcp/handlers/update-props.ts +22 -0
- package/src/mcp/handlers/update-styles.ts +45 -0
- package/src/mcp/index.ts +9 -0
- package/src/sync/delete-element.ts +8 -2
- package/src/sync/drop-element.ts +30 -0
- package/src/sync/duplicate-elements.ts +3 -4
- package/src/sync/get-current-document-container.ts +1 -1
- package/src/sync/get-element-editor-settings.ts +8 -0
- package/src/sync/get-element-interactions.ts +15 -0
- package/src/sync/get-element-label.ts +6 -1
- package/src/sync/get-element-type.ts +28 -0
- package/src/sync/get-elements.ts +1 -1
- package/src/sync/get-widgets-cache.ts +4 -3
- package/src/sync/move-elements.ts +9 -1
- package/src/sync/remove-elements.ts +11 -0
- package/src/sync/replace-element.ts +50 -12
- package/src/sync/types.ts +32 -3
- package/src/sync/update-element-editor-settings.ts +28 -0
- package/src/sync/update-element-interactions.ts +32 -0
- package/src/types.ts +16 -1
- package/src/hooks/use-element-type.ts +0 -35
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// src/hooks/use-element-
|
|
2
|
-
import { __privateUseListenTo as useListenTo, commandEndEvent } from "@elementor/editor-v1-adapters";
|
|
1
|
+
// src/hooks/use-element-children.ts
|
|
2
|
+
import { __privateUseListenTo as useListenTo, commandEndEvent, v1ReadyEvent } from "@elementor/editor-v1-adapters";
|
|
3
3
|
|
|
4
4
|
// src/sync/get-container.ts
|
|
5
5
|
import { __privateRunCommand as runCommand } from "@elementor/editor-v1-adapters";
|
|
@@ -16,6 +16,53 @@ var selectElement = (elementId) => {
|
|
|
16
16
|
}
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
// src/hooks/use-element-children.ts
|
|
20
|
+
function useElementChildren(elementId, childrenTypes) {
|
|
21
|
+
return useListenTo(
|
|
22
|
+
[
|
|
23
|
+
v1ReadyEvent(),
|
|
24
|
+
commandEndEvent("document/elements/create"),
|
|
25
|
+
commandEndEvent("document/elements/delete"),
|
|
26
|
+
commandEndEvent("document/elements/update"),
|
|
27
|
+
commandEndEvent("document/elements/set-settings")
|
|
28
|
+
],
|
|
29
|
+
() => {
|
|
30
|
+
const container = getContainer(elementId);
|
|
31
|
+
const elementChildren = Object.entries(childrenTypes).reduce((acc, [parentType, childType]) => {
|
|
32
|
+
const parent = container?.children?.findRecursive?.(
|
|
33
|
+
({ model }) => model.get("elType") === parentType
|
|
34
|
+
);
|
|
35
|
+
const children = parent?.children ?? [];
|
|
36
|
+
acc[childType] = children.filter(({ model }) => model.get("elType") === childType).map(({ id }) => ({ id }));
|
|
37
|
+
return acc;
|
|
38
|
+
}, {});
|
|
39
|
+
return elementChildren;
|
|
40
|
+
},
|
|
41
|
+
[elementId]
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/hooks/use-element-editor-settings.ts
|
|
46
|
+
import { __privateUseListenTo as useListenTo2, windowEvent } from "@elementor/editor-v1-adapters";
|
|
47
|
+
|
|
48
|
+
// src/sync/get-element-editor-settings.ts
|
|
49
|
+
function getElementEditorSettings(elementId) {
|
|
50
|
+
const container = getContainer(elementId);
|
|
51
|
+
return container?.model.get("editor_settings") ?? {};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/hooks/use-element-editor-settings.ts
|
|
55
|
+
var useElementEditorSettings = (elementId) => {
|
|
56
|
+
return useListenTo2(
|
|
57
|
+
windowEvent("elementor/element/update_editor_settings"),
|
|
58
|
+
() => getElementEditorSettings(elementId),
|
|
59
|
+
[elementId]
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// src/hooks/use-element-setting.ts
|
|
64
|
+
import { __privateUseListenTo as useListenTo3, commandEndEvent as commandEndEvent2 } from "@elementor/editor-v1-adapters";
|
|
65
|
+
|
|
19
66
|
// src/sync/get-element-setting.ts
|
|
20
67
|
var getElementSetting = (elementId, settingKey) => {
|
|
21
68
|
const container = getContainer(elementId);
|
|
@@ -27,15 +74,15 @@ var getElementSettings = (elementId, settingKey) => {
|
|
|
27
74
|
|
|
28
75
|
// src/hooks/use-element-setting.ts
|
|
29
76
|
var useElementSetting = (elementId, settingKey) => {
|
|
30
|
-
return
|
|
31
|
-
|
|
77
|
+
return useListenTo3(
|
|
78
|
+
commandEndEvent2("document/elements/set-settings"),
|
|
32
79
|
() => getElementSetting(elementId, settingKey),
|
|
33
80
|
[elementId, settingKey]
|
|
34
81
|
);
|
|
35
82
|
};
|
|
36
83
|
var useElementSettings = (elementId, settingKeys) => {
|
|
37
|
-
return
|
|
38
|
-
|
|
84
|
+
return useListenTo3(
|
|
85
|
+
commandEndEvent2("document/elements/set-settings"),
|
|
39
86
|
() => settingKeys.reduce((settings, key) => {
|
|
40
87
|
const value = getElementSetting(elementId, key);
|
|
41
88
|
if (value !== null) {
|
|
@@ -43,49 +90,61 @@ var useElementSettings = (elementId, settingKeys) => {
|
|
|
43
90
|
}
|
|
44
91
|
return settings;
|
|
45
92
|
}, {}),
|
|
46
|
-
[elementId,
|
|
93
|
+
[elementId, settingKeys.join(",")]
|
|
47
94
|
);
|
|
48
95
|
};
|
|
49
96
|
|
|
50
|
-
// src/hooks/use-element
|
|
51
|
-
import { __privateUseListenTo as
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const extendedWindow = window;
|
|
56
|
-
return extendedWindow?.elementor?.widgetsCache || null;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// src/hooks/use-element-type.ts
|
|
60
|
-
function useElementType(type) {
|
|
61
|
-
return useListenTo2(
|
|
62
|
-
commandEndEvent2("editor/documents/load"),
|
|
97
|
+
// src/hooks/use-parent-element.ts
|
|
98
|
+
import { __privateUseListenTo as useListenTo4, commandEndEvent as commandEndEvent3 } from "@elementor/editor-v1-adapters";
|
|
99
|
+
function useParentElement(elementId) {
|
|
100
|
+
return useListenTo4(
|
|
101
|
+
[commandEndEvent3("document/elements/create")],
|
|
63
102
|
() => {
|
|
64
|
-
if (!
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
const widgetsCache = getWidgetsCache();
|
|
68
|
-
const elementType = widgetsCache?.[type];
|
|
69
|
-
if (!elementType?.atomic_controls) {
|
|
103
|
+
if (!elementId) {
|
|
70
104
|
return null;
|
|
71
105
|
}
|
|
72
|
-
|
|
106
|
+
const extendedWindow = window;
|
|
107
|
+
const element = extendedWindow?.elementor?.getContainer?.(elementId);
|
|
108
|
+
if (!element) {
|
|
73
109
|
return null;
|
|
74
110
|
}
|
|
75
|
-
return
|
|
76
|
-
key: type,
|
|
77
|
-
controls: elementType.atomic_controls,
|
|
78
|
-
propsSchema: elementType.atomic_props_schema,
|
|
79
|
-
dependenciesPerTargetMapping: elementType.dependencies_per_target_mapping ?? {},
|
|
80
|
-
title: elementType.title
|
|
81
|
-
};
|
|
111
|
+
return element.parent;
|
|
82
112
|
},
|
|
83
|
-
[
|
|
113
|
+
[elementId]
|
|
84
114
|
);
|
|
85
115
|
}
|
|
86
116
|
|
|
87
117
|
// src/hooks/use-selected-element.ts
|
|
88
|
-
import { __privateUseListenTo as
|
|
118
|
+
import { __privateUseListenTo as useListenTo5, commandEndEvent as commandEndEvent4 } from "@elementor/editor-v1-adapters";
|
|
119
|
+
|
|
120
|
+
// src/sync/get-widgets-cache.ts
|
|
121
|
+
function getWidgetsCache() {
|
|
122
|
+
const extendedWindow = window;
|
|
123
|
+
return extendedWindow?.elementor?.widgetsCache || null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// src/sync/get-element-type.ts
|
|
127
|
+
function getElementType(type) {
|
|
128
|
+
if (!type) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const widgetsCache = getWidgetsCache();
|
|
132
|
+
const elementType = widgetsCache?.[type];
|
|
133
|
+
if (!elementType?.atomic_controls) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
if (!elementType?.atomic_props_schema) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
key: type,
|
|
141
|
+
controls: elementType.atomic_controls,
|
|
142
|
+
propsSchema: elementType.atomic_props_schema,
|
|
143
|
+
dependenciesPerTargetMapping: elementType.dependencies_per_target_mapping ?? {},
|
|
144
|
+
title: elementType.title,
|
|
145
|
+
styleStates: elementType.atomic_style_states ?? []
|
|
146
|
+
};
|
|
147
|
+
}
|
|
89
148
|
|
|
90
149
|
// src/sync/get-selected-elements.ts
|
|
91
150
|
function getSelectedElements() {
|
|
@@ -105,72 +164,23 @@ function getSelectedElements() {
|
|
|
105
164
|
|
|
106
165
|
// src/hooks/use-selected-element.ts
|
|
107
166
|
function useSelectedElement() {
|
|
108
|
-
const elements =
|
|
167
|
+
const elements = useListenTo5(
|
|
109
168
|
[
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
169
|
+
commandEndEvent4("document/elements/select"),
|
|
170
|
+
commandEndEvent4("document/elements/deselect"),
|
|
171
|
+
commandEndEvent4("document/elements/select-all"),
|
|
172
|
+
commandEndEvent4("document/elements/deselect-all")
|
|
114
173
|
],
|
|
115
174
|
getSelectedElements
|
|
116
175
|
);
|
|
117
176
|
const [element] = elements;
|
|
118
|
-
const elementType =
|
|
177
|
+
const elementType = getElementType(element?.type);
|
|
119
178
|
if (elements.length !== 1 || !elementType) {
|
|
120
179
|
return { element: null, elementType: null };
|
|
121
180
|
}
|
|
122
181
|
return { element, elementType };
|
|
123
182
|
}
|
|
124
183
|
|
|
125
|
-
// src/hooks/use-parent-element.ts
|
|
126
|
-
import { __privateUseListenTo as useListenTo4, commandEndEvent as commandEndEvent4 } from "@elementor/editor-v1-adapters";
|
|
127
|
-
function useParentElement(elementId) {
|
|
128
|
-
return useListenTo4(
|
|
129
|
-
[commandEndEvent4("document/elements/create")],
|
|
130
|
-
() => {
|
|
131
|
-
if (!elementId) {
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
const extendedWindow = window;
|
|
135
|
-
const element = extendedWindow?.elementor?.getContainer?.(elementId);
|
|
136
|
-
if (!element) {
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
return element.parent;
|
|
140
|
-
},
|
|
141
|
-
[elementId]
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// src/hooks/use-element-children.ts
|
|
146
|
-
import { __privateUseListenTo as useListenTo5, commandEndEvent as commandEndEvent5, v1ReadyEvent } from "@elementor/editor-v1-adapters";
|
|
147
|
-
function useElementChildren(elementId, childrenTypes) {
|
|
148
|
-
return useListenTo5(
|
|
149
|
-
[
|
|
150
|
-
v1ReadyEvent(),
|
|
151
|
-
commandEndEvent5("document/elements/create"),
|
|
152
|
-
commandEndEvent5("document/elements/delete"),
|
|
153
|
-
commandEndEvent5("document/elements/update"),
|
|
154
|
-
commandEndEvent5("document/elements/set-settings")
|
|
155
|
-
],
|
|
156
|
-
() => {
|
|
157
|
-
const container = getContainer(elementId);
|
|
158
|
-
const elementChildren = childrenTypes.reduce((acc, type) => {
|
|
159
|
-
acc[type] = [];
|
|
160
|
-
return acc;
|
|
161
|
-
}, {});
|
|
162
|
-
container?.children?.forEachRecursive?.(({ model, id }) => {
|
|
163
|
-
const elType = model.get("elType");
|
|
164
|
-
if (elType && elType in elementChildren) {
|
|
165
|
-
elementChildren[elType].push({ id });
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
return elementChildren;
|
|
169
|
-
},
|
|
170
|
-
[elementId]
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
184
|
// src/sync/create-element.ts
|
|
175
185
|
import { __privateRunCommandSync as runCommandSync } from "@elementor/editor-v1-adapters";
|
|
176
186
|
function createElement({ containerId, model, options }) {
|
|
@@ -185,152 +195,33 @@ function createElement({ containerId, model, options }) {
|
|
|
185
195
|
});
|
|
186
196
|
}
|
|
187
197
|
|
|
198
|
+
// src/sync/create-elements.ts
|
|
199
|
+
import { undoable } from "@elementor/editor-v1-adapters";
|
|
200
|
+
import { __ } from "@wordpress/i18n";
|
|
201
|
+
|
|
188
202
|
// src/sync/delete-element.ts
|
|
189
203
|
import { __privateRunCommand as runCommand2 } from "@elementor/editor-v1-adapters";
|
|
190
|
-
function deleteElement({
|
|
204
|
+
function deleteElement({
|
|
205
|
+
elementId,
|
|
206
|
+
options = {}
|
|
207
|
+
}) {
|
|
191
208
|
const container = getContainer(elementId);
|
|
192
209
|
if (!container) {
|
|
193
210
|
throw new Error(`Element with ID "${elementId}" not found`);
|
|
194
211
|
}
|
|
195
|
-
runCommand2("document/elements/delete", {
|
|
212
|
+
return runCommand2("document/elements/delete", {
|
|
196
213
|
container,
|
|
197
214
|
options
|
|
198
215
|
});
|
|
199
216
|
}
|
|
200
217
|
|
|
201
|
-
// src/sync/move-element.ts
|
|
202
|
-
function moveElement({ elementId, targetContainerId, options = {} }) {
|
|
203
|
-
const container = getContainer(elementId);
|
|
204
|
-
const target = getContainer(targetContainerId);
|
|
205
|
-
if (!container) {
|
|
206
|
-
throw new Error(`Element with ID "${elementId}" not found`);
|
|
207
|
-
}
|
|
208
|
-
if (!target) {
|
|
209
|
-
throw new Error(`Target container with ID "${targetContainerId}" not found`);
|
|
210
|
-
}
|
|
211
|
-
const modelToRecreate = container.model.toJSON();
|
|
212
|
-
deleteElement({
|
|
213
|
-
elementId,
|
|
214
|
-
// prevent inner history from being created
|
|
215
|
-
options: { ...options, useHistory: false }
|
|
216
|
-
});
|
|
217
|
-
const newContainer = createElement({
|
|
218
|
-
containerId: targetContainerId,
|
|
219
|
-
model: modelToRecreate,
|
|
220
|
-
// prevent inner history from being created
|
|
221
|
-
options: { edit: false, ...options, useHistory: false }
|
|
222
|
-
});
|
|
223
|
-
return newContainer;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// src/sync/move-elements.ts
|
|
227
|
-
import { undoable } from "@elementor/editor-v1-adapters";
|
|
228
|
-
import { __ } from "@wordpress/i18n";
|
|
229
|
-
var moveElements = ({
|
|
230
|
-
moves: movesToMake,
|
|
231
|
-
title,
|
|
232
|
-
subtitle = __("Elements moved", "elementor")
|
|
233
|
-
}) => {
|
|
234
|
-
const undoableMove = undoable(
|
|
235
|
-
{
|
|
236
|
-
do: ({ moves }) => {
|
|
237
|
-
const movedElements = [];
|
|
238
|
-
moves.forEach((move) => {
|
|
239
|
-
const { elementId } = move;
|
|
240
|
-
const sourceContainer = getContainer(elementId);
|
|
241
|
-
if (!sourceContainer) {
|
|
242
|
-
throw new Error(`Element with ID "${elementId}" not found`);
|
|
243
|
-
}
|
|
244
|
-
const originalContainerId = sourceContainer.parent?.id || "";
|
|
245
|
-
const originalIndex = sourceContainer.parent?.children?.indexOf(sourceContainer) ?? -1;
|
|
246
|
-
const originalPosition = {
|
|
247
|
-
elementId,
|
|
248
|
-
originalContainerId,
|
|
249
|
-
originalIndex
|
|
250
|
-
};
|
|
251
|
-
const element = moveElement({
|
|
252
|
-
...move,
|
|
253
|
-
options: { ...move.options, useHistory: false }
|
|
254
|
-
});
|
|
255
|
-
movedElements.push({
|
|
256
|
-
elementId,
|
|
257
|
-
originalPosition,
|
|
258
|
-
move,
|
|
259
|
-
element
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
return { movedElements };
|
|
263
|
-
},
|
|
264
|
-
undo: (_, { movedElements }) => {
|
|
265
|
-
[...movedElements].reverse().forEach(({ originalPosition }) => {
|
|
266
|
-
const { elementId, originalContainerId, originalIndex } = originalPosition;
|
|
267
|
-
moveElement({
|
|
268
|
-
elementId,
|
|
269
|
-
targetContainerId: originalContainerId,
|
|
270
|
-
options: {
|
|
271
|
-
useHistory: false,
|
|
272
|
-
at: originalIndex >= 0 ? originalIndex : void 0
|
|
273
|
-
}
|
|
274
|
-
});
|
|
275
|
-
});
|
|
276
|
-
},
|
|
277
|
-
redo: (_, { movedElements }) => {
|
|
278
|
-
const newMovedElements = [];
|
|
279
|
-
movedElements.forEach(({ move, originalPosition }) => {
|
|
280
|
-
const element = moveElement({
|
|
281
|
-
...move,
|
|
282
|
-
options: { ...move.options, useHistory: false }
|
|
283
|
-
});
|
|
284
|
-
newMovedElements.push({
|
|
285
|
-
elementId: move.elementId,
|
|
286
|
-
originalPosition,
|
|
287
|
-
move,
|
|
288
|
-
element
|
|
289
|
-
});
|
|
290
|
-
});
|
|
291
|
-
return { movedElements: newMovedElements };
|
|
292
|
-
}
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
title,
|
|
296
|
-
subtitle
|
|
297
|
-
}
|
|
298
|
-
);
|
|
299
|
-
return undoableMove({ moves: movesToMake });
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
// src/sync/duplicate-element.ts
|
|
303
|
-
function duplicateElement({ elementId, options = {} }) {
|
|
304
|
-
const elementToDuplicate = getContainer(elementId);
|
|
305
|
-
if (!elementToDuplicate) {
|
|
306
|
-
throw new Error(`Element with ID "${elementId}" not found`);
|
|
307
|
-
}
|
|
308
|
-
if (!elementToDuplicate.parent) {
|
|
309
|
-
throw new Error(`Element with ID "${elementId}" has no parent container`);
|
|
310
|
-
}
|
|
311
|
-
const parentContainer = elementToDuplicate.parent;
|
|
312
|
-
const elementModel = elementToDuplicate.model.toJSON();
|
|
313
|
-
const currentIndex = elementToDuplicate.view?._index ?? 0;
|
|
314
|
-
const insertPosition = options.clone !== false ? currentIndex + 1 : void 0;
|
|
315
|
-
return createElement({
|
|
316
|
-
containerId: parentContainer.id,
|
|
317
|
-
model: elementModel,
|
|
318
|
-
options: {
|
|
319
|
-
at: insertPosition,
|
|
320
|
-
...options
|
|
321
|
-
}
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
|
|
325
218
|
// src/sync/create-elements.ts
|
|
326
|
-
import { undoable as undoable2 } from "@elementor/editor-v1-adapters";
|
|
327
|
-
import { __ as __2 } from "@wordpress/i18n";
|
|
328
219
|
var createElements = ({
|
|
329
220
|
elements,
|
|
330
221
|
title,
|
|
331
|
-
subtitle =
|
|
222
|
+
subtitle = __("Item added", "elementor")
|
|
332
223
|
}) => {
|
|
333
|
-
const undoableCreate =
|
|
224
|
+
const undoableCreate = undoable(
|
|
334
225
|
{
|
|
335
226
|
do: ({ elements: elementsParam }) => {
|
|
336
227
|
const createdElements = [];
|
|
@@ -388,37 +279,73 @@ var createElements = ({
|
|
|
388
279
|
return undoableCreate({ elements });
|
|
389
280
|
};
|
|
390
281
|
|
|
391
|
-
// src/sync/
|
|
392
|
-
import {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
282
|
+
// src/sync/drop-element.ts
|
|
283
|
+
import { __privateRunCommandSync as runCommandSync2 } from "@elementor/editor-v1-adapters";
|
|
284
|
+
function dropElement({ containerId, model, options }) {
|
|
285
|
+
const container = getContainer(containerId);
|
|
286
|
+
if (!container) {
|
|
287
|
+
throw new Error(`Container with ID "${containerId}" not found`);
|
|
288
|
+
}
|
|
289
|
+
return runCommandSync2("preview/drop", {
|
|
290
|
+
container,
|
|
291
|
+
model,
|
|
292
|
+
options
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/sync/duplicate-element.ts
|
|
297
|
+
function duplicateElement({ elementId, options = {} }) {
|
|
298
|
+
const elementToDuplicate = getContainer(elementId);
|
|
299
|
+
if (!elementToDuplicate) {
|
|
300
|
+
throw new Error(`Element with ID "${elementId}" not found`);
|
|
301
|
+
}
|
|
302
|
+
if (!elementToDuplicate.parent) {
|
|
303
|
+
throw new Error(`Element with ID "${elementId}" has no parent container`);
|
|
304
|
+
}
|
|
305
|
+
const parentContainer = elementToDuplicate.parent;
|
|
306
|
+
const elementModel = elementToDuplicate.model.toJSON();
|
|
307
|
+
const currentIndex = elementToDuplicate.view?._index ?? 0;
|
|
308
|
+
const insertPosition = options.clone !== false ? currentIndex + 1 : void 0;
|
|
309
|
+
return createElement({
|
|
310
|
+
containerId: parentContainer.id,
|
|
311
|
+
model: elementModel,
|
|
312
|
+
options: {
|
|
313
|
+
at: insertPosition,
|
|
314
|
+
...options
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/sync/duplicate-elements.ts
|
|
320
|
+
import { undoable as undoable2 } from "@elementor/editor-v1-adapters";
|
|
321
|
+
import { __ as __2 } from "@wordpress/i18n";
|
|
322
|
+
var duplicateElements = ({
|
|
323
|
+
elementIds,
|
|
324
|
+
title,
|
|
325
|
+
subtitle = __2("Item duplicated", "elementor")
|
|
326
|
+
}) => {
|
|
327
|
+
const undoableDuplicate = undoable2(
|
|
328
|
+
{
|
|
329
|
+
do: ({ elementIds: elementIdsToDuplicate }) => {
|
|
330
|
+
const duplicatedElements = elementIdsToDuplicate.reduce((acc, elementId) => {
|
|
331
|
+
const originalContainer = getContainer(elementId);
|
|
332
|
+
if (originalContainer?.parent) {
|
|
333
|
+
const duplicatedElement = duplicateElement({
|
|
334
|
+
elementId,
|
|
335
|
+
options: { useHistory: false, clone: true }
|
|
336
|
+
});
|
|
337
|
+
acc.push({
|
|
338
|
+
id: duplicatedElement.id,
|
|
339
|
+
model: duplicatedElement.model.toJSON(),
|
|
340
|
+
originalElementId: elementId,
|
|
341
|
+
modelToRestore: duplicatedElement.model.toJSON(),
|
|
342
|
+
parentContainerId: duplicatedElement.parent?.id,
|
|
343
|
+
at: duplicatedElement.view?._index
|
|
344
|
+
});
|
|
418
345
|
}
|
|
419
346
|
return acc;
|
|
420
347
|
}, []);
|
|
421
|
-
return { duplicatedElements
|
|
348
|
+
return { duplicatedElements };
|
|
422
349
|
},
|
|
423
350
|
undo: (_, { duplicatedElements }) => {
|
|
424
351
|
[...duplicatedElements].reverse().forEach(({ id }) => {
|
|
@@ -451,7 +378,7 @@ var duplicateElements = ({
|
|
|
451
378
|
}
|
|
452
379
|
return acc;
|
|
453
380
|
}, []);
|
|
454
|
-
return { duplicatedElements
|
|
381
|
+
return { duplicatedElements };
|
|
455
382
|
}
|
|
456
383
|
},
|
|
457
384
|
{
|
|
@@ -462,13 +389,201 @@ var duplicateElements = ({
|
|
|
462
389
|
return undoableDuplicate({ elementIds });
|
|
463
390
|
};
|
|
464
391
|
|
|
392
|
+
// src/sync/generate-element-id.ts
|
|
393
|
+
var generateElementId = () => {
|
|
394
|
+
const extendedWindow = window;
|
|
395
|
+
return extendedWindow.elementorCommon?.helpers?.getUniqueId?.() ?? `el-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// src/sync/get-current-document-container.ts
|
|
399
|
+
function getCurrentDocumentContainer() {
|
|
400
|
+
const extendedWindow = window;
|
|
401
|
+
return extendedWindow.elementor?.documents?.getCurrent?.()?.container ?? null;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// src/sync/get-current-document-id.ts
|
|
405
|
+
function getCurrentDocumentId() {
|
|
406
|
+
const extendedWindow = window;
|
|
407
|
+
return extendedWindow.elementor?.documents?.getCurrentId?.() ?? null;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// src/errors.ts
|
|
411
|
+
import { createError } from "@elementor/utils";
|
|
412
|
+
var ElementNotFoundError = createError({
|
|
413
|
+
code: "element_not_found",
|
|
414
|
+
message: "Element not found."
|
|
415
|
+
});
|
|
416
|
+
var StyleNotFoundError = createError({
|
|
417
|
+
code: "style_not_found",
|
|
418
|
+
message: "Style not found."
|
|
419
|
+
});
|
|
420
|
+
var ElementTypeNotExistsError = createError({
|
|
421
|
+
code: "element_type_not_exists",
|
|
422
|
+
message: "Element type does not exist."
|
|
423
|
+
});
|
|
424
|
+
var ElementLabelNotExistsError = createError({
|
|
425
|
+
code: "element_label_not_exists",
|
|
426
|
+
message: "Element label does not exist."
|
|
427
|
+
});
|
|
428
|
+
var ElementParentNotFoundError = createError({
|
|
429
|
+
code: "element_parent_not_found",
|
|
430
|
+
message: "Element parent not found."
|
|
431
|
+
});
|
|
432
|
+
var ElementIndexNotFoundError = createError({
|
|
433
|
+
code: "element_index_not_found",
|
|
434
|
+
message: "Element index not found."
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// src/sync/get-element-label.ts
|
|
438
|
+
function getElementLabel(elementId) {
|
|
439
|
+
if (!elementId) {
|
|
440
|
+
elementId = getSelectedElements()?.[0]?.id;
|
|
441
|
+
}
|
|
442
|
+
const container = getContainer(elementId);
|
|
443
|
+
const type = container?.model.get("widgetType") || container?.model.get("elType");
|
|
444
|
+
if (!type) {
|
|
445
|
+
throw new ElementTypeNotExistsError({ context: { elementId } });
|
|
446
|
+
}
|
|
447
|
+
const label = getWidgetsCache()?.[type]?.title;
|
|
448
|
+
if (!label) {
|
|
449
|
+
throw new ElementLabelNotExistsError({ context: { elementType: type } });
|
|
450
|
+
}
|
|
451
|
+
return label;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// src/sync/get-element-styles.ts
|
|
455
|
+
var getElementStyles = (elementID) => {
|
|
456
|
+
const container = getContainer(elementID);
|
|
457
|
+
return container?.model.get("styles") || null;
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
// src/sync/get-elements.ts
|
|
461
|
+
function getElements(root) {
|
|
462
|
+
const container = root ? getContainer(root) : getCurrentDocumentContainer();
|
|
463
|
+
if (!container) {
|
|
464
|
+
return [];
|
|
465
|
+
}
|
|
466
|
+
const children = [...container.model.get("elements") ?? []].flatMap(
|
|
467
|
+
(childModel) => getElements(childModel.get("id"))
|
|
468
|
+
);
|
|
469
|
+
return [container, ...children];
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// src/sync/move-element.ts
|
|
473
|
+
function moveElement({ elementId, targetContainerId, options = {} }) {
|
|
474
|
+
const container = getContainer(elementId);
|
|
475
|
+
const target = getContainer(targetContainerId);
|
|
476
|
+
if (!container) {
|
|
477
|
+
throw new Error(`Element with ID "${elementId}" not found`);
|
|
478
|
+
}
|
|
479
|
+
if (!target) {
|
|
480
|
+
throw new Error(`Target container with ID "${targetContainerId}" not found`);
|
|
481
|
+
}
|
|
482
|
+
const modelToRecreate = container.model.toJSON();
|
|
483
|
+
deleteElement({
|
|
484
|
+
elementId,
|
|
485
|
+
// prevent inner history from being created
|
|
486
|
+
options: { ...options, useHistory: false }
|
|
487
|
+
});
|
|
488
|
+
const newContainer = createElement({
|
|
489
|
+
containerId: targetContainerId,
|
|
490
|
+
model: modelToRecreate,
|
|
491
|
+
// prevent inner history from being created
|
|
492
|
+
options: { edit: false, ...options, useHistory: false }
|
|
493
|
+
});
|
|
494
|
+
return newContainer;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// src/sync/move-elements.ts
|
|
498
|
+
import { undoable as undoable3 } from "@elementor/editor-v1-adapters";
|
|
499
|
+
import { __ as __3 } from "@wordpress/i18n";
|
|
500
|
+
var moveElements = ({
|
|
501
|
+
moves: movesToMake,
|
|
502
|
+
title,
|
|
503
|
+
subtitle = __3("Elements moved", "elementor"),
|
|
504
|
+
onMoveElements,
|
|
505
|
+
onRestoreElements
|
|
506
|
+
}) => {
|
|
507
|
+
const undoableMove = undoable3(
|
|
508
|
+
{
|
|
509
|
+
do: ({ moves }) => {
|
|
510
|
+
const movedElements = [];
|
|
511
|
+
onMoveElements?.();
|
|
512
|
+
moves.forEach((move) => {
|
|
513
|
+
const { elementId } = move;
|
|
514
|
+
const sourceContainer = getContainer(elementId);
|
|
515
|
+
if (!sourceContainer) {
|
|
516
|
+
throw new Error(`Element with ID "${elementId}" not found`);
|
|
517
|
+
}
|
|
518
|
+
const originalContainerId = sourceContainer.parent?.id || "";
|
|
519
|
+
const originalIndex = sourceContainer.parent?.children?.indexOf(sourceContainer) ?? -1;
|
|
520
|
+
const originalPosition = {
|
|
521
|
+
elementId,
|
|
522
|
+
originalContainerId,
|
|
523
|
+
originalIndex
|
|
524
|
+
};
|
|
525
|
+
const element = moveElement({
|
|
526
|
+
...move,
|
|
527
|
+
options: { ...move.options, useHistory: false }
|
|
528
|
+
});
|
|
529
|
+
movedElements.push({
|
|
530
|
+
elementId,
|
|
531
|
+
originalPosition,
|
|
532
|
+
move,
|
|
533
|
+
element
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
return { movedElements };
|
|
537
|
+
},
|
|
538
|
+
undo: (_, { movedElements }) => {
|
|
539
|
+
onRestoreElements?.();
|
|
540
|
+
[...movedElements].reverse().forEach(({ originalPosition }) => {
|
|
541
|
+
const { elementId, originalContainerId, originalIndex } = originalPosition;
|
|
542
|
+
moveElement({
|
|
543
|
+
elementId,
|
|
544
|
+
targetContainerId: originalContainerId,
|
|
545
|
+
options: {
|
|
546
|
+
useHistory: false,
|
|
547
|
+
at: originalIndex >= 0 ? originalIndex : void 0
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
},
|
|
552
|
+
redo: (_, { movedElements }) => {
|
|
553
|
+
const newMovedElements = [];
|
|
554
|
+
onMoveElements?.();
|
|
555
|
+
movedElements.forEach(({ move, originalPosition }) => {
|
|
556
|
+
const element = moveElement({
|
|
557
|
+
...move,
|
|
558
|
+
options: { ...move.options, useHistory: false }
|
|
559
|
+
});
|
|
560
|
+
newMovedElements.push({
|
|
561
|
+
elementId: move.elementId,
|
|
562
|
+
originalPosition,
|
|
563
|
+
move,
|
|
564
|
+
element
|
|
565
|
+
});
|
|
566
|
+
});
|
|
567
|
+
return { movedElements: newMovedElements };
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
title,
|
|
572
|
+
subtitle
|
|
573
|
+
}
|
|
574
|
+
);
|
|
575
|
+
return undoableMove({ moves: movesToMake });
|
|
576
|
+
};
|
|
577
|
+
|
|
465
578
|
// src/sync/remove-elements.ts
|
|
466
579
|
import { undoable as undoable4 } from "@elementor/editor-v1-adapters";
|
|
467
580
|
import { __ as __4 } from "@wordpress/i18n";
|
|
468
581
|
var removeElements = ({
|
|
469
582
|
elementIds,
|
|
470
583
|
title,
|
|
471
|
-
subtitle = __4("Item removed", "elementor")
|
|
584
|
+
subtitle = __4("Item removed", "elementor"),
|
|
585
|
+
onRemoveElements,
|
|
586
|
+
onRestoreElements
|
|
472
587
|
}) => {
|
|
473
588
|
const undoableRemove = undoable4(
|
|
474
589
|
{
|
|
@@ -488,6 +603,7 @@ var removeElements = ({
|
|
|
488
603
|
});
|
|
489
604
|
}
|
|
490
605
|
});
|
|
606
|
+
onRemoveElements?.();
|
|
491
607
|
elementIdsParam.forEach((elementId) => {
|
|
492
608
|
deleteElement({
|
|
493
609
|
elementId,
|
|
@@ -497,6 +613,7 @@ var removeElements = ({
|
|
|
497
613
|
return { elementIds: elementIdsParam, removedElements };
|
|
498
614
|
},
|
|
499
615
|
undo: (_, { removedElements }) => {
|
|
616
|
+
onRestoreElements?.();
|
|
500
617
|
[...removedElements].reverse().forEach(({ model, parent, at }) => {
|
|
501
618
|
if (parent && model) {
|
|
502
619
|
createElement({
|
|
@@ -508,6 +625,7 @@ var removeElements = ({
|
|
|
508
625
|
});
|
|
509
626
|
},
|
|
510
627
|
redo: (_, { elementIds: originalElementIds, removedElements }) => {
|
|
628
|
+
onRemoveElements?.();
|
|
511
629
|
originalElementIds.forEach((elementId) => {
|
|
512
630
|
deleteElement({
|
|
513
631
|
elementId,
|
|
@@ -525,71 +643,65 @@ var removeElements = ({
|
|
|
525
643
|
return undoableRemove({ elementIds });
|
|
526
644
|
};
|
|
527
645
|
|
|
528
|
-
// src/sync/
|
|
529
|
-
var
|
|
530
|
-
const
|
|
531
|
-
|
|
646
|
+
// src/sync/replace-element.ts
|
|
647
|
+
var replaceElement = ({ currentElement, newElement, withHistory = true }) => {
|
|
648
|
+
const { containerId, index } = getNewElementLocation(currentElement, newElement);
|
|
649
|
+
createElement({
|
|
650
|
+
containerId,
|
|
651
|
+
model: newElement,
|
|
652
|
+
options: { at: index, useHistory: withHistory }
|
|
653
|
+
});
|
|
654
|
+
deleteElement({ elementId: currentElement.id, options: { useHistory: withHistory } });
|
|
532
655
|
};
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
message: "Element not found."
|
|
539
|
-
});
|
|
540
|
-
var StyleNotFoundError = createError({
|
|
541
|
-
code: "style_not_found",
|
|
542
|
-
message: "Style not found."
|
|
543
|
-
});
|
|
544
|
-
var ElementTypeNotExistsError = createError({
|
|
545
|
-
code: "element_type_not_exists",
|
|
546
|
-
message: "Element type does not exist."
|
|
547
|
-
});
|
|
548
|
-
var ElementLabelNotExistsError = createError({
|
|
549
|
-
code: "element_label_not_exists",
|
|
550
|
-
message: "Element label does not exist."
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
// src/sync/get-element-label.ts
|
|
554
|
-
function getElementLabel(elementId) {
|
|
555
|
-
const container = getContainer(elementId);
|
|
556
|
-
const type = container?.model.get("widgetType") || container?.model.get("elType");
|
|
557
|
-
if (!type) {
|
|
558
|
-
throw new ElementTypeNotExistsError({ context: { elementId } });
|
|
656
|
+
function getNewElementLocation(currentElement, newElement) {
|
|
657
|
+
let location;
|
|
658
|
+
const currentElementContainer = getContainer(currentElement.id);
|
|
659
|
+
if (!currentElementContainer) {
|
|
660
|
+
throw new ElementNotFoundError({ context: { elementId: currentElement.id } });
|
|
559
661
|
}
|
|
560
|
-
const
|
|
561
|
-
if (!
|
|
562
|
-
throw new
|
|
662
|
+
const parent = currentElementContainer.parent;
|
|
663
|
+
if (!parent) {
|
|
664
|
+
throw new ElementParentNotFoundError({ context: { elementId: currentElement.id } });
|
|
563
665
|
}
|
|
564
|
-
|
|
666
|
+
const elementIndex = currentElementContainer.view?._index ?? 0;
|
|
667
|
+
if (elementIndex === void 0 || elementIndex === -1) {
|
|
668
|
+
throw new ElementIndexNotFoundError({ context: { elementId: currentElement.id } });
|
|
669
|
+
}
|
|
670
|
+
location = { containerId: parent.id, index: elementIndex };
|
|
671
|
+
if (parent.id === "document" && newElement.elType === "widget") {
|
|
672
|
+
location = createWrapperForWidget(parent.id, elementIndex);
|
|
673
|
+
}
|
|
674
|
+
return location;
|
|
565
675
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
676
|
+
function createWrapperForWidget(parentId, elementIndex) {
|
|
677
|
+
const container = createElement({
|
|
678
|
+
containerId: parentId,
|
|
679
|
+
model: { elType: "container" },
|
|
680
|
+
options: { at: elementIndex, useHistory: false }
|
|
681
|
+
});
|
|
682
|
+
return { containerId: container.id, index: 0 };
|
|
571
683
|
}
|
|
572
684
|
|
|
573
|
-
// src/sync/
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
685
|
+
// src/sync/update-element-editor-settings.ts
|
|
686
|
+
import { __privateRunCommandSync as runCommandSync3 } from "@elementor/editor-v1-adapters";
|
|
687
|
+
var updateElementEditorSettings = ({
|
|
688
|
+
elementId,
|
|
689
|
+
settings
|
|
690
|
+
}) => {
|
|
691
|
+
const element = getContainer(elementId);
|
|
692
|
+
if (!element) {
|
|
693
|
+
throw new Error(`Element with id ${elementId} not found`);
|
|
578
694
|
}
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
);
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
// src/sync/get-current-document-id.ts
|
|
586
|
-
function getCurrentDocumentId() {
|
|
587
|
-
const extendedWindow = window;
|
|
588
|
-
return extendedWindow.elementor?.documents?.getCurrentId?.() ?? null;
|
|
695
|
+
const editorSettings = element.model.get("editor_settings") ?? {};
|
|
696
|
+
element.model.set("editor_settings", { ...editorSettings, ...settings });
|
|
697
|
+
setDocumentModifiedStatus(true);
|
|
698
|
+
};
|
|
699
|
+
function setDocumentModifiedStatus(status) {
|
|
700
|
+
runCommandSync3("document/save/set-is-modified", { status }, { internal: true });
|
|
589
701
|
}
|
|
590
702
|
|
|
591
703
|
// src/sync/update-element-settings.ts
|
|
592
|
-
import { __privateRunCommandSync as
|
|
704
|
+
import { __privateRunCommandSync as runCommandSync4 } from "@elementor/editor-v1-adapters";
|
|
593
705
|
var updateElementSettings = ({ id, props, withHistory = true }) => {
|
|
594
706
|
const container = getContainer(id);
|
|
595
707
|
const args = {
|
|
@@ -597,45 +709,105 @@ var updateElementSettings = ({ id, props, withHistory = true }) => {
|
|
|
597
709
|
settings: { ...props }
|
|
598
710
|
};
|
|
599
711
|
if (withHistory) {
|
|
600
|
-
|
|
712
|
+
runCommandSync4("document/elements/settings", args);
|
|
601
713
|
} else {
|
|
602
|
-
|
|
714
|
+
runCommandSync4("document/elements/set-settings", args, { internal: true });
|
|
603
715
|
}
|
|
604
716
|
};
|
|
605
717
|
|
|
606
|
-
// src/
|
|
607
|
-
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
if (!parent) {
|
|
616
|
-
throw new Error(`Parent not found for element ${currentElement.id}. Cannot replace element.`);
|
|
718
|
+
// src/link-restriction.ts
|
|
719
|
+
function getLinkInLinkRestriction(elementId) {
|
|
720
|
+
const anchoredDescendantId = getAnchoredDescendantId(elementId);
|
|
721
|
+
if (anchoredDescendantId) {
|
|
722
|
+
return {
|
|
723
|
+
shouldRestrict: true,
|
|
724
|
+
reason: "descendant",
|
|
725
|
+
elementId: anchoredDescendantId
|
|
726
|
+
};
|
|
617
727
|
}
|
|
618
|
-
const
|
|
619
|
-
if (
|
|
620
|
-
|
|
728
|
+
const ancestor = getAnchoredAncestorId(elementId);
|
|
729
|
+
if (ancestor) {
|
|
730
|
+
return {
|
|
731
|
+
shouldRestrict: true,
|
|
732
|
+
reason: "ancestor",
|
|
733
|
+
elementId: ancestor
|
|
734
|
+
};
|
|
621
735
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
736
|
+
return {
|
|
737
|
+
shouldRestrict: false
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
function getAnchoredDescendantId(elementId) {
|
|
741
|
+
const element = getElementDOM(elementId);
|
|
742
|
+
if (!element) {
|
|
743
|
+
return null;
|
|
744
|
+
}
|
|
745
|
+
for (const childAnchorElement of Array.from(element.querySelectorAll("a"))) {
|
|
746
|
+
const childElementId = findElementIdOf(childAnchorElement);
|
|
747
|
+
if (childElementId !== elementId) {
|
|
748
|
+
return childElementId;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return null;
|
|
752
|
+
}
|
|
753
|
+
function getAnchoredAncestorId(elementId) {
|
|
754
|
+
const element = getElementDOM(elementId);
|
|
755
|
+
if (!element || element.parentElement === null) {
|
|
756
|
+
return null;
|
|
757
|
+
}
|
|
758
|
+
const parentAnchor = element.parentElement.closest("a");
|
|
759
|
+
return parentAnchor ? findElementIdOf(parentAnchor) : null;
|
|
760
|
+
}
|
|
761
|
+
function isElementAnchored(elementId) {
|
|
762
|
+
const element = getElementDOM(elementId);
|
|
763
|
+
if (!element) {
|
|
764
|
+
return false;
|
|
765
|
+
}
|
|
766
|
+
if (isAnchorTag(element.tagName)) {
|
|
767
|
+
return true;
|
|
768
|
+
}
|
|
769
|
+
return doesElementContainAnchor(element);
|
|
770
|
+
}
|
|
771
|
+
function doesElementContainAnchor(element) {
|
|
772
|
+
for (const child of element.children) {
|
|
773
|
+
if (isElementorElement(child)) {
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
if (isAnchorTag(child.tagName)) {
|
|
777
|
+
return true;
|
|
778
|
+
}
|
|
779
|
+
if (doesElementContainAnchor(child)) {
|
|
780
|
+
return true;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return false;
|
|
784
|
+
}
|
|
785
|
+
function findElementIdOf(element) {
|
|
786
|
+
return element.closest("[data-id]")?.dataset.id || null;
|
|
787
|
+
}
|
|
788
|
+
function getElementDOM(id) {
|
|
789
|
+
try {
|
|
790
|
+
return getContainer(id)?.view?.el || null;
|
|
791
|
+
} catch {
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
function isAnchorTag(tagName) {
|
|
796
|
+
return tagName.toLowerCase() === "a";
|
|
797
|
+
}
|
|
798
|
+
function isElementorElement(element) {
|
|
799
|
+
return element.hasAttribute("data-id");
|
|
800
|
+
}
|
|
629
801
|
|
|
630
802
|
// src/styles/consts.ts
|
|
631
|
-
import { commandEndEvent as
|
|
803
|
+
import { commandEndEvent as commandEndEvent5, windowEvent as windowEvent2 } from "@elementor/editor-v1-adapters";
|
|
632
804
|
var ELEMENT_STYLE_CHANGE_EVENT = "elementor/editor-v2/editor-elements/style";
|
|
633
805
|
var styleRerenderEvents = [
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
806
|
+
commandEndEvent5("document/elements/create"),
|
|
807
|
+
commandEndEvent5("document/elements/duplicate"),
|
|
808
|
+
commandEndEvent5("document/elements/import"),
|
|
809
|
+
commandEndEvent5("document/elements/paste"),
|
|
810
|
+
windowEvent2(ELEMENT_STYLE_CHANGE_EVENT)
|
|
639
811
|
];
|
|
640
812
|
|
|
641
813
|
// src/styles/create-element-style.ts
|
|
@@ -646,7 +818,7 @@ import {
|
|
|
646
818
|
|
|
647
819
|
// src/styles/mutate-element-styles.ts
|
|
648
820
|
import { classesPropTypeUtil } from "@elementor/editor-props";
|
|
649
|
-
import { __privateRunCommandSync as
|
|
821
|
+
import { __privateRunCommandSync as runCommandSync5 } from "@elementor/editor-v1-adapters";
|
|
650
822
|
function mutateElementStyles(elementId, mutator) {
|
|
651
823
|
const container = getContainer(elementId);
|
|
652
824
|
if (!container) {
|
|
@@ -702,7 +874,7 @@ function getClassesProps(container) {
|
|
|
702
874
|
}
|
|
703
875
|
function notifyChanges() {
|
|
704
876
|
dispatchChangeEvent();
|
|
705
|
-
|
|
877
|
+
runCommandSync5("document/save/set-is-modified", { status: true }, { internal: true });
|
|
706
878
|
}
|
|
707
879
|
function dispatchChangeEvent() {
|
|
708
880
|
window.dispatchEvent(new CustomEvent(ELEMENT_STYLE_CHANGE_EVENT));
|
|
@@ -754,6 +926,14 @@ function shouldCreateNewLocalStyle(payload) {
|
|
|
754
926
|
return !payload?.styleId && !payload?.provider;
|
|
755
927
|
}
|
|
756
928
|
|
|
929
|
+
// src/styles/delete-element-style.ts
|
|
930
|
+
function deleteElementStyle(elementId, styleId) {
|
|
931
|
+
mutateElementStyles(elementId, (styles) => {
|
|
932
|
+
delete styles[styleId];
|
|
933
|
+
return styles;
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
|
|
757
937
|
// src/styles/update-element-style.ts
|
|
758
938
|
import { mergeProps } from "@elementor/editor-props";
|
|
759
939
|
import { getVariantByMeta } from "@elementor/editor-styles";
|
|
@@ -775,96 +955,663 @@ function updateElementStyle(args) {
|
|
|
775
955
|
});
|
|
776
956
|
}
|
|
777
957
|
|
|
778
|
-
// src/
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
958
|
+
// src/hooks/use-element-interactions.ts
|
|
959
|
+
import { useState } from "react";
|
|
960
|
+
import { __privateUseListenTo as useListenTo6, windowEvent as windowEvent3 } from "@elementor/editor-v1-adapters";
|
|
961
|
+
|
|
962
|
+
// src/sync/get-element-interactions.ts
|
|
963
|
+
function getElementInteractions(elementId) {
|
|
964
|
+
const container = getContainer(elementId);
|
|
965
|
+
const interactions = container?.model?.get("interactions");
|
|
966
|
+
if (typeof interactions === "string") {
|
|
967
|
+
return JSON.parse(interactions);
|
|
968
|
+
}
|
|
969
|
+
return interactions;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// src/hooks/use-element-interactions.ts
|
|
973
|
+
var useElementInteractions = (elementId) => {
|
|
974
|
+
const [interactions, setInteractions] = useState(() => {
|
|
975
|
+
const initial = getElementInteractions(elementId);
|
|
976
|
+
return initial ?? { version: 1, items: [] };
|
|
783
977
|
});
|
|
978
|
+
useListenTo6(
|
|
979
|
+
windowEvent3("elementor/element/update_interactions"),
|
|
980
|
+
() => {
|
|
981
|
+
const newInteractions = getElementInteractions(elementId);
|
|
982
|
+
setInteractions(newInteractions ?? { version: 1, items: [] });
|
|
983
|
+
},
|
|
984
|
+
[elementId]
|
|
985
|
+
);
|
|
986
|
+
return interactions;
|
|
987
|
+
};
|
|
988
|
+
|
|
989
|
+
// src/sync/update-element-interactions.ts
|
|
990
|
+
import { __privateRunCommandSync as runCommandSync6 } from "@elementor/editor-v1-adapters";
|
|
991
|
+
var updateElementInteractions = ({
|
|
992
|
+
elementId,
|
|
993
|
+
interactions
|
|
994
|
+
}) => {
|
|
995
|
+
const element = getContainer(elementId);
|
|
996
|
+
if (!element) {
|
|
997
|
+
throw new Error(`Element with id ${elementId} not found`);
|
|
998
|
+
}
|
|
999
|
+
element.model.set("interactions", interactions);
|
|
1000
|
+
window.dispatchEvent(new CustomEvent("elementor/element/update_interactions"));
|
|
1001
|
+
setDocumentModifiedStatus2(true);
|
|
1002
|
+
};
|
|
1003
|
+
var playElementInteractions = (elementId, animationId) => {
|
|
1004
|
+
window.top?.dispatchEvent(new CustomEvent("atomic/play_interactions", { detail: { elementId, animationId } }));
|
|
1005
|
+
};
|
|
1006
|
+
function setDocumentModifiedStatus2(status) {
|
|
1007
|
+
runCommandSync6("document/save/set-is-modified", { status }, { internal: true });
|
|
784
1008
|
}
|
|
785
1009
|
|
|
786
|
-
// src/
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
1010
|
+
// src/mcp/index.ts
|
|
1011
|
+
import { getMCPByDomain as getMCPByDomain2 } from "@elementor/editor-mcp";
|
|
1012
|
+
|
|
1013
|
+
// src/mcp/elements-tool.ts
|
|
1014
|
+
import { getMCPByDomain } from "@elementor/editor-mcp";
|
|
1015
|
+
import { z } from "@elementor/schema";
|
|
1016
|
+
|
|
1017
|
+
// src/mcp/handlers/create-element.ts
|
|
1018
|
+
function handleCreateElement({
|
|
1019
|
+
elementType,
|
|
1020
|
+
containerId,
|
|
1021
|
+
props = {},
|
|
1022
|
+
styles
|
|
1023
|
+
}) {
|
|
1024
|
+
let container = containerId === "document" ? getCurrentDocumentContainer() : getContainer(containerId);
|
|
1025
|
+
if (!container) {
|
|
1026
|
+
if (containerId === "document") {
|
|
1027
|
+
throw new Error("Document container not found. Please ensure the editor is initialized.");
|
|
1028
|
+
}
|
|
1029
|
+
throw new Error(`Container with ID "${containerId}" not found`);
|
|
795
1030
|
}
|
|
796
|
-
const
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
elementId: ancestor
|
|
1031
|
+
const containerElType = container.model.get("elType");
|
|
1032
|
+
const isDocument = container.id === "document" || containerElType === "document";
|
|
1033
|
+
if (isDocument) {
|
|
1034
|
+
const containerModel = {
|
|
1035
|
+
elType: "e-div-block"
|
|
802
1036
|
};
|
|
1037
|
+
const createdContainer = createElement({
|
|
1038
|
+
containerId: container.id,
|
|
1039
|
+
model: containerModel,
|
|
1040
|
+
options: { useHistory: true }
|
|
1041
|
+
});
|
|
1042
|
+
createElementStyle({
|
|
1043
|
+
elementId: createdContainer.id,
|
|
1044
|
+
classesProp: "classes",
|
|
1045
|
+
label: "local",
|
|
1046
|
+
meta: { breakpoint: "desktop", state: null },
|
|
1047
|
+
props: {
|
|
1048
|
+
display: { $$type: "string", value: "flex" },
|
|
1049
|
+
"flex-direction": { $$type: "string", value: "row" },
|
|
1050
|
+
"flex-wrap": { $$type: "string", value: "wrap" }
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
container = getContainer(createdContainer.id);
|
|
1054
|
+
if (!container) {
|
|
1055
|
+
throw new Error("Failed to create container for widget. Cannot create widgets directly in the document.");
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
const actualContainerId = container.id;
|
|
1059
|
+
const elementTypeData = getElementType(elementType);
|
|
1060
|
+
if (!elementTypeData) {
|
|
1061
|
+
throw new Error(`Element type "${elementType}" not found or is not atomic`);
|
|
1062
|
+
}
|
|
1063
|
+
const model = {
|
|
1064
|
+
widgetType: elementType,
|
|
1065
|
+
elType: "widget",
|
|
1066
|
+
settings: props
|
|
1067
|
+
};
|
|
1068
|
+
const createdElement = createElement({
|
|
1069
|
+
containerId: actualContainerId,
|
|
1070
|
+
model,
|
|
1071
|
+
options: { useHistory: true }
|
|
1072
|
+
});
|
|
1073
|
+
if (styles) {
|
|
1074
|
+
createElementStyle({
|
|
1075
|
+
elementId: createdElement.id,
|
|
1076
|
+
classesProp: "classes",
|
|
1077
|
+
label: "local",
|
|
1078
|
+
meta: { breakpoint: "desktop", state: null },
|
|
1079
|
+
props: styles
|
|
1080
|
+
});
|
|
803
1081
|
}
|
|
804
1082
|
return {
|
|
805
|
-
|
|
1083
|
+
elementId: createdElement.id,
|
|
1084
|
+
type: elementType
|
|
806
1085
|
};
|
|
807
1086
|
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
1087
|
+
|
|
1088
|
+
// src/mcp/handlers/common-style-utils.ts
|
|
1089
|
+
var VALID_BREAKPOINTS = [
|
|
1090
|
+
"widescreen",
|
|
1091
|
+
"desktop",
|
|
1092
|
+
"laptop",
|
|
1093
|
+
"tablet_extra",
|
|
1094
|
+
"tablet",
|
|
1095
|
+
"mobile_extra",
|
|
1096
|
+
"mobile"
|
|
1097
|
+
];
|
|
1098
|
+
function resolveBreakpointId(breakpoint) {
|
|
1099
|
+
if (breakpoint === null) {
|
|
811
1100
|
return null;
|
|
812
1101
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
if (childElementId !== elementId) {
|
|
816
|
-
return childElementId;
|
|
817
|
-
}
|
|
1102
|
+
if (VALID_BREAKPOINTS.includes(breakpoint)) {
|
|
1103
|
+
return breakpoint;
|
|
818
1104
|
}
|
|
819
|
-
return
|
|
1105
|
+
return "desktop";
|
|
820
1106
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
1107
|
+
|
|
1108
|
+
// src/mcp/handlers/create-style.ts
|
|
1109
|
+
function handleCreateStyle({
|
|
1110
|
+
elementId,
|
|
1111
|
+
styleId,
|
|
1112
|
+
classesProp = "classes",
|
|
1113
|
+
label = "local",
|
|
1114
|
+
styles,
|
|
1115
|
+
breakpoint = "desktop",
|
|
1116
|
+
state = null,
|
|
1117
|
+
customCss = null
|
|
1118
|
+
}) {
|
|
1119
|
+
const resolvedBreakpoint = resolveBreakpointId(breakpoint);
|
|
1120
|
+
const resolvedState = state === null || state === void 0 ? null : state;
|
|
1121
|
+
const createdStyleId = createElementStyle({
|
|
1122
|
+
styleId,
|
|
1123
|
+
elementId,
|
|
1124
|
+
classesProp,
|
|
1125
|
+
label,
|
|
1126
|
+
meta: { breakpoint: resolvedBreakpoint, state: resolvedState },
|
|
1127
|
+
props: styles,
|
|
1128
|
+
custom_css: customCss
|
|
1129
|
+
});
|
|
1130
|
+
return { styleId: createdStyleId };
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
// src/mcp/handlers/delete-element.ts
|
|
1134
|
+
function handleDeleteElement(elementId) {
|
|
1135
|
+
const container = getContainer(elementId);
|
|
1136
|
+
if (!container) {
|
|
1137
|
+
throw new Error(`Element with ID "${elementId}" not found`);
|
|
825
1138
|
}
|
|
826
|
-
|
|
827
|
-
|
|
1139
|
+
deleteElement({
|
|
1140
|
+
elementId,
|
|
1141
|
+
options: { useHistory: true }
|
|
1142
|
+
});
|
|
1143
|
+
return { success: true };
|
|
828
1144
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
1145
|
+
|
|
1146
|
+
// src/mcp/handlers/delete-style.ts
|
|
1147
|
+
function handleDeleteStyle({ elementId, styleId }) {
|
|
1148
|
+
const elementStyles = getElementStyles(elementId);
|
|
1149
|
+
if (!elementStyles) {
|
|
1150
|
+
throw new Error(`Element with ID "${elementId}" has no styles.`);
|
|
833
1151
|
}
|
|
834
|
-
|
|
835
|
-
|
|
1152
|
+
const resolvedStyleId = styleId || Object.keys(elementStyles)[0];
|
|
1153
|
+
if (!resolvedStyleId) {
|
|
1154
|
+
throw new Error(`Element with ID "${elementId}" has no styles to delete.`);
|
|
836
1155
|
}
|
|
837
|
-
|
|
1156
|
+
deleteElementStyle(elementId, resolvedStyleId);
|
|
1157
|
+
return { success: true };
|
|
838
1158
|
}
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
1159
|
+
|
|
1160
|
+
// src/mcp/handlers/deselect-element.ts
|
|
1161
|
+
import { __privateRunCommand as runCommand3 } from "@elementor/editor-v1-adapters";
|
|
1162
|
+
function handleDeselectElement(elementId) {
|
|
1163
|
+
const container = getContainer(elementId);
|
|
1164
|
+
if (!container) {
|
|
1165
|
+
throw new Error(`Element with ID "${elementId}" not found`);
|
|
1166
|
+
}
|
|
1167
|
+
runCommand3("document/elements/deselect", { container });
|
|
1168
|
+
return { success: true };
|
|
1169
|
+
}
|
|
1170
|
+
function handleDeselectAllElements() {
|
|
1171
|
+
runCommand3("document/elements/deselect-all", {});
|
|
1172
|
+
return { success: true };
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
// src/mcp/handlers/duplicate-element.ts
|
|
1176
|
+
function handleDuplicateElement(elementId) {
|
|
1177
|
+
const container = getContainer(elementId);
|
|
1178
|
+
if (!container) {
|
|
1179
|
+
throw new Error(`Element with ID "${elementId}" not found`);
|
|
1180
|
+
}
|
|
1181
|
+
const duplicatedElement = duplicateElement({
|
|
1182
|
+
elementId,
|
|
1183
|
+
options: { useHistory: true }
|
|
1184
|
+
});
|
|
1185
|
+
const type = duplicatedElement.model.get("widgetType") || duplicatedElement.model.get("elType") || "";
|
|
1186
|
+
return {
|
|
1187
|
+
elementId: duplicatedElement.id,
|
|
1188
|
+
type
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// src/mcp/handlers/get-element-props.ts
|
|
1193
|
+
function handleGetElementProps(elementId) {
|
|
1194
|
+
const container = getContainer(elementId);
|
|
1195
|
+
if (!container) {
|
|
1196
|
+
throw new Error(`Element with ID "${elementId}" not found`);
|
|
1197
|
+
}
|
|
1198
|
+
const type = container.model.get("widgetType") || container.model.get("elType");
|
|
1199
|
+
if (!type) {
|
|
1200
|
+
throw new Error(`Element with ID "${elementId}" has no type`);
|
|
1201
|
+
}
|
|
1202
|
+
const elementType = getElementType(type);
|
|
1203
|
+
if (!elementType) {
|
|
1204
|
+
throw new Error(`Element type "${type}" is not atomic`);
|
|
1205
|
+
}
|
|
1206
|
+
const propsSchema = elementType.propsSchema;
|
|
1207
|
+
const propKeys = Object.keys(propsSchema);
|
|
1208
|
+
return getElementSettings(elementId, propKeys);
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// src/mcp/handlers/get-element-schema.ts
|
|
1212
|
+
import { getStylesSchema } from "@elementor/editor-styles";
|
|
1213
|
+
function handleGetElementSchema(elementType) {
|
|
1214
|
+
const elementTypeData = getElementType(elementType);
|
|
1215
|
+
if (!elementTypeData) {
|
|
1216
|
+
throw new Error(`Element type "${elementType}" not found or is not atomic`);
|
|
1217
|
+
}
|
|
1218
|
+
return { ...elementTypeData, stylesSchema: getStylesSchema() };
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
// src/mcp/handlers/get-selected.ts
|
|
1222
|
+
function handleGetSelected() {
|
|
1223
|
+
return getSelectedElements();
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
// src/mcp/handlers/get-styles.ts
|
|
1227
|
+
function handleGetStyles(elementId) {
|
|
1228
|
+
const styles = getElementStyles(elementId);
|
|
1229
|
+
if (!styles) {
|
|
1230
|
+
return null;
|
|
1231
|
+
}
|
|
1232
|
+
return Object.fromEntries(
|
|
1233
|
+
Object.entries(styles).map(([id, style]) => [
|
|
1234
|
+
id,
|
|
1235
|
+
{
|
|
1236
|
+
id: style.id,
|
|
1237
|
+
label: style.label,
|
|
1238
|
+
type: style.type,
|
|
1239
|
+
variants: style.variants.map((variant) => ({
|
|
1240
|
+
meta: variant.meta,
|
|
1241
|
+
props: variant.props,
|
|
1242
|
+
custom_css: variant.custom_css
|
|
1243
|
+
}))
|
|
1244
|
+
}
|
|
1245
|
+
])
|
|
1246
|
+
);
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
// src/mcp/handlers/list-available-types.ts
|
|
1250
|
+
function handleListAvailableTypes() {
|
|
1251
|
+
const widgetsCache = getWidgetsCache();
|
|
1252
|
+
if (!widgetsCache) {
|
|
1253
|
+
return [];
|
|
1254
|
+
}
|
|
1255
|
+
const availableTypes = [];
|
|
1256
|
+
Object.entries(widgetsCache).forEach(([type, config]) => {
|
|
1257
|
+
if (config?.atomic_controls && config?.atomic_props_schema) {
|
|
1258
|
+
availableTypes.push({
|
|
1259
|
+
type,
|
|
1260
|
+
title: config.title || type
|
|
1261
|
+
});
|
|
846
1262
|
}
|
|
847
|
-
|
|
848
|
-
|
|
1263
|
+
});
|
|
1264
|
+
return availableTypes;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
// src/mcp/handlers/move-element.ts
|
|
1268
|
+
function handleMoveElement({
|
|
1269
|
+
elementId,
|
|
1270
|
+
targetContainerId
|
|
1271
|
+
}) {
|
|
1272
|
+
const container = getContainer(elementId);
|
|
1273
|
+
if (!container) {
|
|
1274
|
+
throw new Error(`Element with ID "${elementId}" not found`);
|
|
1275
|
+
}
|
|
1276
|
+
const targetContainer = getContainer(targetContainerId);
|
|
1277
|
+
if (!targetContainer) {
|
|
1278
|
+
throw new Error(`Target container with ID "${targetContainerId}" not found`);
|
|
1279
|
+
}
|
|
1280
|
+
moveElement({
|
|
1281
|
+
elementId,
|
|
1282
|
+
targetContainerId,
|
|
1283
|
+
options: { useHistory: true }
|
|
1284
|
+
});
|
|
1285
|
+
return { success: true };
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
// src/mcp/handlers/select-element.ts
|
|
1289
|
+
function handleSelectElement(elementId) {
|
|
1290
|
+
const container = getContainer(elementId);
|
|
1291
|
+
if (!container) {
|
|
1292
|
+
throw new Error(`Element with ID "${elementId}" not found`);
|
|
1293
|
+
}
|
|
1294
|
+
selectElement(elementId);
|
|
1295
|
+
return { success: true };
|
|
1296
|
+
}
|
|
1297
|
+
function handleSelectMultipleElements(elementIds) {
|
|
1298
|
+
elementIds.forEach((elementId) => {
|
|
1299
|
+
const container = getContainer(elementId);
|
|
1300
|
+
if (container) {
|
|
1301
|
+
selectElement(elementId);
|
|
849
1302
|
}
|
|
1303
|
+
});
|
|
1304
|
+
return { success: true };
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
// src/mcp/handlers/update-props.ts
|
|
1308
|
+
function handleUpdateProps({ elementId, props }) {
|
|
1309
|
+
const container = getContainer(elementId);
|
|
1310
|
+
if (!container) {
|
|
1311
|
+
throw new Error(`Element with ID "${elementId}" not found`);
|
|
850
1312
|
}
|
|
851
|
-
|
|
1313
|
+
updateElementSettings({
|
|
1314
|
+
id: elementId,
|
|
1315
|
+
props,
|
|
1316
|
+
withHistory: true
|
|
1317
|
+
});
|
|
1318
|
+
return { success: true };
|
|
852
1319
|
}
|
|
853
|
-
|
|
854
|
-
|
|
1320
|
+
|
|
1321
|
+
// src/mcp/handlers/update-styles.ts
|
|
1322
|
+
function handleUpdateStyles({
|
|
1323
|
+
elementId,
|
|
1324
|
+
styleId,
|
|
1325
|
+
styles,
|
|
1326
|
+
breakpoint = "desktop",
|
|
1327
|
+
state = null
|
|
1328
|
+
}) {
|
|
1329
|
+
const resolvedBreakpoint = resolveBreakpointId(breakpoint);
|
|
1330
|
+
const resolvedState = state === null || state === void 0 ? null : state;
|
|
1331
|
+
const elementStyles = getElementStyles(elementId);
|
|
1332
|
+
if (!elementStyles) {
|
|
1333
|
+
throw new Error(`Element with ID "${elementId}" has no styles. Create a style first.`);
|
|
1334
|
+
}
|
|
1335
|
+
const resolvedStyleId = styleId || Object.keys(elementStyles)[0];
|
|
1336
|
+
if (!resolvedStyleId) {
|
|
1337
|
+
throw new Error(`Element with ID "${elementId}" has no styles. Create a style first.`);
|
|
1338
|
+
}
|
|
1339
|
+
updateElementStyle({
|
|
1340
|
+
elementId,
|
|
1341
|
+
styleId: resolvedStyleId,
|
|
1342
|
+
meta: { breakpoint: resolvedBreakpoint, state: resolvedState },
|
|
1343
|
+
props: styles
|
|
1344
|
+
});
|
|
1345
|
+
return { success: true };
|
|
855
1346
|
}
|
|
856
|
-
|
|
1347
|
+
|
|
1348
|
+
// src/mcp/elements-tool.ts
|
|
1349
|
+
var actionEnum = z.enum([
|
|
1350
|
+
"get-element-schema",
|
|
1351
|
+
"get-element-props",
|
|
1352
|
+
"create-element",
|
|
1353
|
+
"update-props",
|
|
1354
|
+
"create-style",
|
|
1355
|
+
"get-styles",
|
|
1356
|
+
"update-styles",
|
|
1357
|
+
"delete-style",
|
|
1358
|
+
"delete",
|
|
1359
|
+
"duplicate",
|
|
1360
|
+
"move",
|
|
1361
|
+
"select",
|
|
1362
|
+
"deselect",
|
|
1363
|
+
"deselect-all",
|
|
1364
|
+
"get-selected",
|
|
1365
|
+
"list-available-types"
|
|
1366
|
+
]);
|
|
1367
|
+
var schema = {
|
|
1368
|
+
action: actionEnum.describe("The element operation to perform."),
|
|
1369
|
+
elementId: z.string().optional().describe("The ID of the target element"),
|
|
1370
|
+
elementIds: z.array(z.string()).optional().describe("Array of element IDs for multi-element operations"),
|
|
1371
|
+
elementType: z.string().optional().describe(
|
|
1372
|
+
"The type of element to create. Must be an atomic element type (required for create-element and get-element-schema actions)"
|
|
1373
|
+
),
|
|
1374
|
+
props: z.record(z.any()).optional().describe("Props object for creating or updating an element. Must match the element type's propsSchema."),
|
|
1375
|
+
containerId: z.string().optional().describe(
|
|
1376
|
+
'Parent container ID for element creation or move operations. Use "document" if parent is the document root.'
|
|
1377
|
+
),
|
|
1378
|
+
targetContainerId: z.string().optional().describe("Target container ID for move operations"),
|
|
1379
|
+
styles: z.record(z.any()).optional().describe(
|
|
1380
|
+
"Styles object for creating or updating element styles. Must match the element type's stylesSchema."
|
|
1381
|
+
),
|
|
1382
|
+
styleId: z.string().optional().describe(
|
|
1383
|
+
"Style definition ID for style operations. If not provided, the first available style will be used (for update/delete)."
|
|
1384
|
+
),
|
|
1385
|
+
breakpoint: z.string().optional().describe('Breakpoint for style operations (e.g., "desktop", "tablet", "mobile"). Defaults to "desktop".'),
|
|
1386
|
+
state: z.string().optional().describe('State for style operations (e.g., "hover", "active", or null). Defaults to null.'),
|
|
1387
|
+
classesProp: z.string().optional().describe('Classes property name for create-style action. Defaults to "classes".'),
|
|
1388
|
+
label: z.string().optional().describe('Label for create-style action. Defaults to "local".'),
|
|
1389
|
+
custom_css: z.object({ raw: z.string() }).optional().describe("Custom CSS object with raw CSS string for create-style action.")
|
|
1390
|
+
};
|
|
1391
|
+
function routeAction(params) {
|
|
857
1392
|
try {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
1393
|
+
switch (params.action) {
|
|
1394
|
+
case "get-element-schema":
|
|
1395
|
+
if (!params.elementType) {
|
|
1396
|
+
throw new Error("elementType is required for get-element-schema action");
|
|
1397
|
+
}
|
|
1398
|
+
return handleGetElementSchema(params.elementType);
|
|
1399
|
+
case "get-element-props":
|
|
1400
|
+
if (!params.elementId) {
|
|
1401
|
+
throw new Error("elementId is required for get-element-props action");
|
|
1402
|
+
}
|
|
1403
|
+
return handleGetElementProps(params.elementId);
|
|
1404
|
+
case "create-element":
|
|
1405
|
+
if (!params.elementType) {
|
|
1406
|
+
throw new Error("elementType is required for create-element action");
|
|
1407
|
+
}
|
|
1408
|
+
if (!params.containerId) {
|
|
1409
|
+
throw new Error("containerId is required for create-element action");
|
|
1410
|
+
}
|
|
1411
|
+
return handleCreateElement({
|
|
1412
|
+
elementType: params.elementType,
|
|
1413
|
+
containerId: params.containerId,
|
|
1414
|
+
props: params.props,
|
|
1415
|
+
styles: params.styles
|
|
1416
|
+
});
|
|
1417
|
+
case "update-props":
|
|
1418
|
+
if (!params.elementId) {
|
|
1419
|
+
throw new Error("elementId is required for update-props action");
|
|
1420
|
+
}
|
|
1421
|
+
if (!params.props) {
|
|
1422
|
+
throw new Error("props is required for update-props action");
|
|
1423
|
+
}
|
|
1424
|
+
return handleUpdateProps({
|
|
1425
|
+
elementId: params.elementId,
|
|
1426
|
+
props: params.props
|
|
1427
|
+
});
|
|
1428
|
+
case "create-style":
|
|
1429
|
+
if (!params.elementId) {
|
|
1430
|
+
throw new Error("elementId is required for create-style action");
|
|
1431
|
+
}
|
|
1432
|
+
if (!params.styles) {
|
|
1433
|
+
throw new Error("styles is required for create-style action");
|
|
1434
|
+
}
|
|
1435
|
+
return handleCreateStyle({
|
|
1436
|
+
elementId: params.elementId,
|
|
1437
|
+
styleId: params.styleId,
|
|
1438
|
+
classesProp: params.classesProp,
|
|
1439
|
+
label: params.label,
|
|
1440
|
+
styles: params.styles,
|
|
1441
|
+
breakpoint: params.breakpoint,
|
|
1442
|
+
state: params.state,
|
|
1443
|
+
customCss: params.custom_css
|
|
1444
|
+
});
|
|
1445
|
+
case "get-styles":
|
|
1446
|
+
if (!params.elementId) {
|
|
1447
|
+
throw new Error("elementId is required for get-styles action");
|
|
1448
|
+
}
|
|
1449
|
+
return handleGetStyles(params.elementId);
|
|
1450
|
+
case "update-styles":
|
|
1451
|
+
if (!params.elementId) {
|
|
1452
|
+
throw new Error("elementId is required for update-styles action");
|
|
1453
|
+
}
|
|
1454
|
+
if (!params.styles) {
|
|
1455
|
+
throw new Error("styles is required for update-styles action");
|
|
1456
|
+
}
|
|
1457
|
+
return handleUpdateStyles({
|
|
1458
|
+
elementId: params.elementId,
|
|
1459
|
+
styleId: params.styleId,
|
|
1460
|
+
styles: params.styles,
|
|
1461
|
+
breakpoint: params.breakpoint,
|
|
1462
|
+
state: params.state
|
|
1463
|
+
});
|
|
1464
|
+
case "delete-style":
|
|
1465
|
+
if (!params.elementId) {
|
|
1466
|
+
throw new Error("elementId is required for delete-style action");
|
|
1467
|
+
}
|
|
1468
|
+
return handleDeleteStyle({
|
|
1469
|
+
elementId: params.elementId,
|
|
1470
|
+
styleId: params.styleId
|
|
1471
|
+
});
|
|
1472
|
+
case "delete":
|
|
1473
|
+
if (!params.elementId) {
|
|
1474
|
+
throw new Error("elementId is required for delete action");
|
|
1475
|
+
}
|
|
1476
|
+
return handleDeleteElement(params.elementId);
|
|
1477
|
+
case "duplicate":
|
|
1478
|
+
if (!params.elementId) {
|
|
1479
|
+
throw new Error("elementId is required for duplicate action");
|
|
1480
|
+
}
|
|
1481
|
+
return handleDuplicateElement(params.elementId);
|
|
1482
|
+
case "move":
|
|
1483
|
+
if (!params.elementId) {
|
|
1484
|
+
throw new Error("elementId is required for move action");
|
|
1485
|
+
}
|
|
1486
|
+
if (!params.targetContainerId) {
|
|
1487
|
+
throw new Error("targetContainerId is required for move action");
|
|
1488
|
+
}
|
|
1489
|
+
return handleMoveElement({
|
|
1490
|
+
elementId: params.elementId,
|
|
1491
|
+
targetContainerId: params.targetContainerId
|
|
1492
|
+
});
|
|
1493
|
+
case "select":
|
|
1494
|
+
if (params.elementIds && params.elementIds.length > 0) {
|
|
1495
|
+
return handleSelectMultipleElements(params.elementIds);
|
|
1496
|
+
}
|
|
1497
|
+
if (!params.elementId) {
|
|
1498
|
+
throw new Error("elementId or elementIds is required for select action");
|
|
1499
|
+
}
|
|
1500
|
+
return handleSelectElement(params.elementId);
|
|
1501
|
+
case "deselect":
|
|
1502
|
+
if (!params.elementId) {
|
|
1503
|
+
throw new Error("elementId is required for deselect action");
|
|
1504
|
+
}
|
|
1505
|
+
return handleDeselectElement(params.elementId);
|
|
1506
|
+
case "deselect-all":
|
|
1507
|
+
return handleDeselectAllElements();
|
|
1508
|
+
case "get-selected":
|
|
1509
|
+
return handleGetSelected();
|
|
1510
|
+
case "list-available-types":
|
|
1511
|
+
return handleListAvailableTypes();
|
|
1512
|
+
default:
|
|
1513
|
+
throw new Error(`Unknown action: ${params.action}`);
|
|
1514
|
+
}
|
|
1515
|
+
} catch (error) {
|
|
1516
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1517
|
+
throw new Error(`Failed to execute action "${params.action}": ${errorMessage}`);
|
|
861
1518
|
}
|
|
862
1519
|
}
|
|
863
|
-
function
|
|
864
|
-
|
|
1520
|
+
function initElementsTool() {
|
|
1521
|
+
getMCPByDomain("elements").addTool({
|
|
1522
|
+
name: "elements",
|
|
1523
|
+
schema,
|
|
1524
|
+
description: `This tool manages individual Elementor atomic elements (v4).
|
|
1525
|
+
|
|
1526
|
+
**When to use this tool:**
|
|
1527
|
+
|
|
1528
|
+
Use this tool to create, update, delete, duplicate, move, and select individual atomic elements, as well as retrieve their schemas and current props.
|
|
1529
|
+
|
|
1530
|
+
**Available actions:**
|
|
1531
|
+
|
|
1532
|
+
- \`list-available-types\`: List all available atomic element types.
|
|
1533
|
+
- \`get-element-schema\`: Get the propsSchema and controls for an element type. Required before creating elements of a new type.
|
|
1534
|
+
- \`get-element-props\`: Get the current prop values for an existing element.
|
|
1535
|
+
- \`create-element\`: Create a new atomic element with specified props and styles (Important to match props and styles by the schema, use get-element-schema to get the schema first).
|
|
1536
|
+
- \`update-props\`: Update props for an existing element.
|
|
1537
|
+
- \`create-style\`: Create a new style definition for an element.
|
|
1538
|
+
- \`get-styles\`: Get all style definitions for an element.
|
|
1539
|
+
- \`update-styles\`: Update styles for an existing element's style variant.
|
|
1540
|
+
- \`delete-style\`: Delete a style definition from an element.
|
|
1541
|
+
- \`delete\`: Delete an element.
|
|
1542
|
+
- \`duplicate\`: Duplicate an existing element.
|
|
1543
|
+
- \`move\`: Move an element to a different container.
|
|
1544
|
+
- \`select\`: Select one or more elements.
|
|
1545
|
+
- \`deselect\`: Deselect a specific element.
|
|
1546
|
+
- \`deselect-all\`: Deselect all selected elements.
|
|
1547
|
+
- \`get-selected\`: Get currently selected elements.
|
|
1548
|
+
|
|
1549
|
+
**Constraints:**
|
|
1550
|
+
|
|
1551
|
+
- Before creating an element of a certain type for the first time, you MUST call \`get-element-schema\` to retrieve its schema.
|
|
1552
|
+
- You can only update props for existing elements.
|
|
1553
|
+
- All props must match the element type's propsSchema keys.
|
|
1554
|
+
- Element types must be atomic (have atomic_controls and atomic_props_schema).
|
|
1555
|
+
- Container IDs must exist and be valid before create/move operations.
|
|
1556
|
+
|
|
1557
|
+
** Must do with every operation **
|
|
1558
|
+
As of the user can ask in multiple ways the creation of the element, you need to first get the list of available types with "list-available-types" action.
|
|
1559
|
+
After getting it, convert to the most relevant type that the user requested and if this is not clear, request for user input.
|
|
1560
|
+
After finding out the proper type, get the schema for it with "get-element-schema" action.
|
|
1561
|
+
|
|
1562
|
+
** Styles and Settings propUtils **
|
|
1563
|
+
Getting the schema is important as it introduces the propUtils for the styles and settings.
|
|
1564
|
+
You can use the propUtils to create, update, delete, and get the values of the styles and settings.
|
|
1565
|
+
Settings exists in the result of the get-element-schema action -> propsSchema.
|
|
1566
|
+
Styles exists in the result of the get-element-schema action -> stylesSchema.
|
|
1567
|
+
|
|
1568
|
+
**Examples:**
|
|
1569
|
+
|
|
1570
|
+
Get schema for heading element:
|
|
1571
|
+
\`\`\`json
|
|
1572
|
+
{ "action": "get-element-schema", "elementType": "e-heading" }
|
|
1573
|
+
\`\`\`
|
|
1574
|
+
|
|
1575
|
+
Create a heading element:
|
|
1576
|
+
\`\`\`json
|
|
1577
|
+
{ "action": "create-element", "elementType": "e-heading", "containerId": "document", "props": { "title": { $$type: "string", "value": "Hello World" } } }
|
|
1578
|
+
\`\`\`
|
|
1579
|
+
|
|
1580
|
+
Update element props:
|
|
1581
|
+
\`\`\`json
|
|
1582
|
+
{ "action": "update-props", "elementId": "abc123", "props": { "title": "Updated Title" } }
|
|
1583
|
+
\`\`\`
|
|
1584
|
+
|
|
1585
|
+
Create element style:
|
|
1586
|
+
\`\`\`json
|
|
1587
|
+
{ "action": "create-style", "elementId": "abc123", "styles": { "padding": "20px", "margin": "10px" } }
|
|
1588
|
+
\`\`\`
|
|
1589
|
+
|
|
1590
|
+
Get element styles:
|
|
1591
|
+
\`\`\`json
|
|
1592
|
+
{ "action": "get-styles", "elementId": "abc123" }
|
|
1593
|
+
\`\`\`
|
|
1594
|
+
|
|
1595
|
+
Update element styles:
|
|
1596
|
+
\`\`\`json
|
|
1597
|
+
{ "action": "update-styles", "elementId": "abc123", "styles": { "padding": "20px", "margin": "10px" } }
|
|
1598
|
+
\`\`\`
|
|
1599
|
+
|
|
1600
|
+
Delete element style:
|
|
1601
|
+
\`\`\`json
|
|
1602
|
+
{ "action": "delete-style", "elementId": "abc123", "styleId": "style-id-123" }
|
|
1603
|
+
\`\`\``,
|
|
1604
|
+
handler: async (params) => {
|
|
1605
|
+
return routeAction(params);
|
|
1606
|
+
}
|
|
1607
|
+
});
|
|
865
1608
|
}
|
|
866
|
-
|
|
867
|
-
|
|
1609
|
+
|
|
1610
|
+
// src/mcp/index.ts
|
|
1611
|
+
function initMcp() {
|
|
1612
|
+
const { setMCPDescription } = getMCPByDomain2("elements");
|
|
1613
|
+
setMCPDescription("Tools for managing atomic elements in Elementor v4 editor");
|
|
1614
|
+
initElementsTool();
|
|
868
1615
|
}
|
|
869
1616
|
export {
|
|
870
1617
|
ELEMENT_STYLE_CHANGE_EVENT,
|
|
@@ -873,35 +1620,45 @@ export {
|
|
|
873
1620
|
createElements,
|
|
874
1621
|
deleteElement,
|
|
875
1622
|
deleteElementStyle,
|
|
1623
|
+
dropElement,
|
|
876
1624
|
duplicateElement,
|
|
877
1625
|
duplicateElements,
|
|
878
1626
|
generateElementId,
|
|
879
1627
|
getAnchoredAncestorId,
|
|
880
1628
|
getAnchoredDescendantId,
|
|
881
1629
|
getContainer,
|
|
1630
|
+
getCurrentDocumentContainer,
|
|
882
1631
|
getCurrentDocumentId,
|
|
1632
|
+
getElementEditorSettings,
|
|
1633
|
+
getElementInteractions,
|
|
883
1634
|
getElementLabel,
|
|
884
1635
|
getElementSetting,
|
|
885
1636
|
getElementSettings,
|
|
886
1637
|
getElementStyles,
|
|
1638
|
+
getElementType,
|
|
887
1639
|
getElements,
|
|
888
1640
|
getLinkInLinkRestriction,
|
|
889
1641
|
getSelectedElements,
|
|
890
1642
|
getWidgetsCache,
|
|
1643
|
+
initMcp as initElementsMcp,
|
|
891
1644
|
isElementAnchored,
|
|
892
1645
|
moveElement,
|
|
893
1646
|
moveElements,
|
|
1647
|
+
playElementInteractions,
|
|
894
1648
|
removeElements,
|
|
895
1649
|
replaceElement,
|
|
896
1650
|
selectElement,
|
|
897
1651
|
shouldCreateNewLocalStyle,
|
|
898
1652
|
styleRerenderEvents,
|
|
1653
|
+
updateElementEditorSettings,
|
|
1654
|
+
updateElementInteractions,
|
|
899
1655
|
updateElementSettings,
|
|
900
1656
|
updateElementStyle,
|
|
901
1657
|
useElementChildren,
|
|
1658
|
+
useElementEditorSettings,
|
|
1659
|
+
useElementInteractions,
|
|
902
1660
|
useElementSetting,
|
|
903
1661
|
useElementSettings,
|
|
904
|
-
useElementType,
|
|
905
1662
|
useParentElement,
|
|
906
1663
|
useSelectedElement
|
|
907
1664
|
};
|