@elementor/editor-canvas 4.1.0-802 → 4.1.0-803
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 +625 -95
- package/dist/index.mjs +575 -40
- package/package.json +18 -18
- package/src/mcp/canvas-mcp.ts +8 -0
- package/src/mcp/resources/available-widgets-resource.ts +67 -0
- package/src/mcp/resources/document-structure-resource.ts +51 -36
- package/src/mcp/resources/editor-state-resource.ts +122 -0
- package/src/mcp/resources/general-context-resource.ts +99 -0
- package/src/mcp/resources/selected-element-resource.ts +217 -0
- package/src/mcp/resources/widgets-schema-resource.ts +71 -6
- package/src/mcp/tools/build-composition/prompt.ts +6 -0
- package/src/mcp/tools/build-composition/tool.ts +26 -0
- package/src/mcp/tools/configure-element/tool.ts +12 -0
- package/src/mcp/tools/get-element-config/tool.ts +13 -3
- package/src/mcp/utils/element-data-util.ts +46 -0
- package/src/mcp/utils/generate-available-tags.ts +0 -23
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.1.0-
|
|
4
|
+
"version": "4.1.0-803",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -37,25 +37,25 @@
|
|
|
37
37
|
"react-dom": "^18.3.1"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@elementor/editor": "4.1.0-
|
|
40
|
+
"@elementor/editor": "4.1.0-803",
|
|
41
41
|
"dompurify": "^3.2.6",
|
|
42
|
-
"@elementor/editor-controls": "4.1.0-
|
|
43
|
-
"@elementor/editor-documents": "4.1.0-
|
|
44
|
-
"@elementor/editor-elements": "4.1.0-
|
|
45
|
-
"@elementor/editor-interactions": "4.1.0-
|
|
46
|
-
"@elementor/editor-mcp": "4.1.0-
|
|
47
|
-
"@elementor/editor-notifications": "4.1.0-
|
|
48
|
-
"@elementor/editor-props": "4.1.0-
|
|
49
|
-
"@elementor/editor-responsive": "4.1.0-
|
|
50
|
-
"@elementor/editor-styles": "4.1.0-
|
|
51
|
-
"@elementor/editor-styles-repository": "4.1.0-
|
|
52
|
-
"@elementor/editor-ui": "4.1.0-
|
|
53
|
-
"@elementor/editor-v1-adapters": "4.1.0-
|
|
54
|
-
"@elementor/schema": "4.1.0-
|
|
55
|
-
"@elementor/twing": "4.1.0-
|
|
42
|
+
"@elementor/editor-controls": "4.1.0-803",
|
|
43
|
+
"@elementor/editor-documents": "4.1.0-803",
|
|
44
|
+
"@elementor/editor-elements": "4.1.0-803",
|
|
45
|
+
"@elementor/editor-interactions": "4.1.0-803",
|
|
46
|
+
"@elementor/editor-mcp": "4.1.0-803",
|
|
47
|
+
"@elementor/editor-notifications": "4.1.0-803",
|
|
48
|
+
"@elementor/editor-props": "4.1.0-803",
|
|
49
|
+
"@elementor/editor-responsive": "4.1.0-803",
|
|
50
|
+
"@elementor/editor-styles": "4.1.0-803",
|
|
51
|
+
"@elementor/editor-styles-repository": "4.1.0-803",
|
|
52
|
+
"@elementor/editor-ui": "4.1.0-803",
|
|
53
|
+
"@elementor/editor-v1-adapters": "4.1.0-803",
|
|
54
|
+
"@elementor/schema": "4.1.0-803",
|
|
55
|
+
"@elementor/twing": "4.1.0-803",
|
|
56
56
|
"@elementor/ui": "1.37.5",
|
|
57
|
-
"@elementor/utils": "4.1.0-
|
|
58
|
-
"@elementor/wp-media": "4.1.0-
|
|
57
|
+
"@elementor/utils": "4.1.0-803",
|
|
58
|
+
"@elementor/wp-media": "4.1.0-803",
|
|
59
59
|
"@floating-ui/react": "^0.27.5",
|
|
60
60
|
"@wordpress/i18n": "^5.13.0"
|
|
61
61
|
},
|
package/src/mcp/canvas-mcp.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
2
2
|
|
|
3
|
+
import { initAvailableWidgetsResource } from './resources/available-widgets-resource';
|
|
3
4
|
import { initBreakpointsResource } from './resources/breakpoints-resource';
|
|
4
5
|
import { initDocumentStructureResource } from './resources/document-structure-resource';
|
|
6
|
+
import { initEditorStateResource } from './resources/editor-state-resource';
|
|
7
|
+
import { initGeneralContextResource } from './resources/general-context-resource';
|
|
8
|
+
import { initSelectedElementResource } from './resources/selected-element-resource';
|
|
5
9
|
import { initWidgetsSchemaResource } from './resources/widgets-schema-resource';
|
|
6
10
|
import { initBuildCompositionsTool } from './tools/build-composition/tool';
|
|
7
11
|
import { initConfigureElementTool } from './tools/configure-element/tool';
|
|
@@ -18,7 +22,11 @@ export const initCanvasMcp = ( reg: MCPRegistryEntry ) => {
|
|
|
18
22
|
`
|
|
19
23
|
);
|
|
20
24
|
initWidgetsSchemaResource( reg );
|
|
25
|
+
initAvailableWidgetsResource( reg );
|
|
21
26
|
initDocumentStructureResource( reg );
|
|
27
|
+
initSelectedElementResource( reg );
|
|
28
|
+
initEditorStateResource( reg );
|
|
29
|
+
initGeneralContextResource( reg );
|
|
22
30
|
initBuildCompositionsTool( reg );
|
|
23
31
|
initGetElementConfigTool( reg );
|
|
24
32
|
initConfigureElementTool( reg );
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
2
|
+
import { v1ReadyEvent } from '@elementor/editor-v1-adapters';
|
|
3
|
+
|
|
4
|
+
import { type AvailableWidget, getAvailableWidgets } from '../utils/element-data-util';
|
|
5
|
+
|
|
6
|
+
export const AVAILABLE_WIDGETS_URI = 'elementor://context/available-widgets';
|
|
7
|
+
export const AVAILABLE_WIDGETS_URI_V4 = 'elementor://context/available-widgets/v4';
|
|
8
|
+
|
|
9
|
+
export const initAvailableWidgetsResource = ( reg: MCPRegistryEntry ) => {
|
|
10
|
+
const { resource, sendResourceUpdated } = reg;
|
|
11
|
+
|
|
12
|
+
const buildContents = ( uri: string, filterFunction: ( x: AvailableWidget ) => boolean = () => true ) => {
|
|
13
|
+
const widgets = getAvailableWidgets().filter( filterFunction );
|
|
14
|
+
return {
|
|
15
|
+
contents: [
|
|
16
|
+
{
|
|
17
|
+
uri,
|
|
18
|
+
mimeType: 'application/json',
|
|
19
|
+
text: JSON.stringify( widgets, null, 2 ),
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const notifyResourcesUpdated = () => {
|
|
26
|
+
sendResourceUpdated( {
|
|
27
|
+
uri: AVAILABLE_WIDGETS_URI,
|
|
28
|
+
...buildContents( AVAILABLE_WIDGETS_URI ),
|
|
29
|
+
} );
|
|
30
|
+
sendResourceUpdated( {
|
|
31
|
+
uri: AVAILABLE_WIDGETS_URI_V4,
|
|
32
|
+
...buildContents( AVAILABLE_WIDGETS_URI_V4, ( w: AvailableWidget ) => w.version === 'v4' ),
|
|
33
|
+
} );
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
resource(
|
|
37
|
+
'available-widgets-v4',
|
|
38
|
+
AVAILABLE_WIDGETS_URI_V4,
|
|
39
|
+
{
|
|
40
|
+
description: 'All registered v4 version widgets',
|
|
41
|
+
},
|
|
42
|
+
async () => buildContents( AVAILABLE_WIDGETS_URI_V4, ( w ) => w.version === 'v4' )
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
resource(
|
|
46
|
+
'available-widgets',
|
|
47
|
+
AVAILABLE_WIDGETS_URI,
|
|
48
|
+
{
|
|
49
|
+
description: 'All registered widget types with v3/v4 version metadata and description.',
|
|
50
|
+
},
|
|
51
|
+
async () => buildContents( AVAILABLE_WIDGETS_URI )
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const eventName = v1ReadyEvent().name;
|
|
55
|
+
|
|
56
|
+
const onV1Ready = () => {
|
|
57
|
+
const widgets = getAvailableWidgets();
|
|
58
|
+
if ( widgets.length === 0 ) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
window.removeEventListener( eventName, onV1Ready );
|
|
62
|
+
notifyResourcesUpdated();
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
window.addEventListener( eventName, onV1Ready );
|
|
66
|
+
onV1Ready();
|
|
67
|
+
};
|
|
@@ -1,41 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ExtendedWindow as BaseExtendedWindow,
|
|
3
|
+
type V1Document,
|
|
4
|
+
type V1DocumentsManager,
|
|
5
|
+
} from '@elementor/editor-documents';
|
|
6
|
+
import {
|
|
7
|
+
getWidgetsCache,
|
|
8
|
+
type V1Element,
|
|
9
|
+
type V1ElementEditorSettingsProps,
|
|
10
|
+
type V1ElementModelProps,
|
|
11
|
+
} from '@elementor/editor-elements';
|
|
1
12
|
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
2
13
|
import { __privateListenTo as listenTo, commandEndEvent } from '@elementor/editor-v1-adapters';
|
|
3
14
|
|
|
4
|
-
type
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
config: {
|
|
10
|
-
type: string;
|
|
11
|
-
settings?: {
|
|
12
|
-
post_title?: string;
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
container: {
|
|
16
|
-
children?: ElementorContainer[];
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
};
|
|
15
|
+
type UnknownVersionElementInstanceData = V1Element & {
|
|
16
|
+
model: V1Element[ 'model' ] & {
|
|
17
|
+
attributes: V1ElementModelProps;
|
|
18
|
+
config?: { atomic?: boolean };
|
|
19
|
+
editor_settings?: V1ElementEditorSettingsProps;
|
|
20
20
|
};
|
|
21
|
+
children?: V1Element[];
|
|
21
22
|
};
|
|
22
23
|
|
|
23
|
-
type
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
widgetType?: string;
|
|
30
|
-
title?: string;
|
|
31
|
-
};
|
|
32
|
-
editor_settings?: {
|
|
33
|
-
title?: string;
|
|
34
|
-
};
|
|
24
|
+
type ContainerWithStructure = V1Document & {
|
|
25
|
+
config: V1Document[ 'config' ] & {
|
|
26
|
+
settings?: { post_title?: string };
|
|
27
|
+
};
|
|
28
|
+
container: V1Document[ 'container' ] & {
|
|
29
|
+
children?: UnknownVersionElementInstanceData[];
|
|
35
30
|
};
|
|
36
|
-
children?: ElementorContainer[];
|
|
37
31
|
};
|
|
38
32
|
|
|
33
|
+
interface ExtendedWindow extends BaseExtendedWindow {
|
|
34
|
+
elementor: Omit< BaseExtendedWindow[ 'elementor' ], 'documents' > & {
|
|
35
|
+
documents: Omit< V1DocumentsManager, 'getCurrent' > & {
|
|
36
|
+
getCurrent: () => ContainerWithStructure;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
39
41
|
export const DOCUMENT_STRUCTURE_URI = 'elementor://document/structure';
|
|
40
42
|
|
|
41
43
|
export const initDocumentStructureResource = ( reg: MCPRegistryEntry ) => {
|
|
@@ -62,6 +64,7 @@ export const initDocumentStructureResource = ( reg: MCPRegistryEntry ) => {
|
|
|
62
64
|
commandEndEvent( 'document/elements/copy' ),
|
|
63
65
|
commandEndEvent( 'document/elements/paste' ),
|
|
64
66
|
commandEndEvent( 'editor/documents/attach-preview' ),
|
|
67
|
+
commandEndEvent( 'editor/documents/switch' ),
|
|
65
68
|
],
|
|
66
69
|
updateDocumentStructure
|
|
67
70
|
);
|
|
@@ -89,7 +92,7 @@ export const initDocumentStructureResource = ( reg: MCPRegistryEntry ) => {
|
|
|
89
92
|
};
|
|
90
93
|
|
|
91
94
|
function getDocumentStructure() {
|
|
92
|
-
const extendedWindow = window as ExtendedWindow;
|
|
95
|
+
const extendedWindow = window as unknown as ExtendedWindow;
|
|
93
96
|
const document = extendedWindow.elementor?.documents?.getCurrent?.();
|
|
94
97
|
|
|
95
98
|
if ( ! document ) {
|
|
@@ -97,9 +100,7 @@ function getDocumentStructure() {
|
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
const containers = document.container?.children || [];
|
|
100
|
-
const elements = (
|
|
101
|
-
extractElementData( container )
|
|
102
|
-
);
|
|
103
|
+
const elements = containers.map( ( container ) => extractElementData( container ) );
|
|
103
104
|
|
|
104
105
|
return {
|
|
105
106
|
documentId: document.id,
|
|
@@ -109,7 +110,20 @@ function getDocumentStructure() {
|
|
|
109
110
|
};
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
function
|
|
113
|
+
function resolveElementVersion( element: UnknownVersionElementInstanceData ): 'v3' | 'v4' {
|
|
114
|
+
if ( element.model?.config?.atomic ) {
|
|
115
|
+
return 'v4';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const widgetType = element.model?.attributes?.widgetType;
|
|
119
|
+
if ( widgetType && getWidgetsCache()?.[ widgetType ]?.atomic_props_schema ) {
|
|
120
|
+
return 'v4';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return 'v3';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function extractElementData( element: UnknownVersionElementInstanceData ): Record< string, unknown > | null {
|
|
113
127
|
if ( ! element || ! element.model ) {
|
|
114
128
|
return null;
|
|
115
129
|
}
|
|
@@ -119,6 +133,7 @@ function extractElementData( element: ElementorContainer ): Record< string, unkn
|
|
|
119
133
|
id: model.id,
|
|
120
134
|
elType: model.elType,
|
|
121
135
|
widgetType: model.widgetType || undefined,
|
|
136
|
+
version: resolveElementVersion( element ),
|
|
122
137
|
};
|
|
123
138
|
|
|
124
139
|
const title = model.title || element.model?.editor_settings?.title;
|
|
@@ -129,8 +144,8 @@ function extractElementData( element: ElementorContainer ): Record< string, unkn
|
|
|
129
144
|
|
|
130
145
|
if ( element.children && element.children.length > 0 ) {
|
|
131
146
|
result.children = element.children
|
|
132
|
-
.map( ( child
|
|
133
|
-
.filter( ( child
|
|
147
|
+
.map( ( child ) => extractElementData( child as UnknownVersionElementInstanceData ) )
|
|
148
|
+
.filter( ( child ) => child !== null );
|
|
134
149
|
}
|
|
135
150
|
|
|
136
151
|
return result;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
2
|
+
import { __privateListenTo as listenTo, commandEndEvent } from '@elementor/editor-v1-adapters';
|
|
3
|
+
|
|
4
|
+
const CURRENTLY_VIEWED_SCREEN = 'The user is currently viewing the Elementor editor';
|
|
5
|
+
const PAGE_CONTENT_CHARACTER_LIMIT = 500;
|
|
6
|
+
const PREVIEW_TEXT_NODE_MIN_LENGTH = 2;
|
|
7
|
+
|
|
8
|
+
export const EDITOR_STATE_URI = 'elementor://context/editor-state';
|
|
9
|
+
|
|
10
|
+
type ElementorWindow = Window & {
|
|
11
|
+
elementor?: {
|
|
12
|
+
$previewContents?: Element[];
|
|
13
|
+
documents?: {
|
|
14
|
+
getCurrent?: () => {
|
|
15
|
+
config?: {
|
|
16
|
+
settings?: {
|
|
17
|
+
post_title?: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const initEditorStateResource = ( reg: MCPRegistryEntry ) => {
|
|
26
|
+
const { resource, sendResourceUpdated } = reg;
|
|
27
|
+
|
|
28
|
+
let lastSerializedState = '';
|
|
29
|
+
|
|
30
|
+
const buildState = () => ( {
|
|
31
|
+
currentlyViewedScreen: CURRENTLY_VIEWED_SCREEN,
|
|
32
|
+
pageContent: getPageContentFromPreview(),
|
|
33
|
+
pageTitle: getPageTitle(),
|
|
34
|
+
} );
|
|
35
|
+
|
|
36
|
+
const notifyIfChanged = () => {
|
|
37
|
+
const serialized = JSON.stringify( buildState() );
|
|
38
|
+
if ( serialized === lastSerializedState ) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
lastSerializedState = serialized;
|
|
42
|
+
sendResourceUpdated( { uri: EDITOR_STATE_URI } );
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
listenTo(
|
|
46
|
+
[ commandEndEvent( 'editor/documents/switch' ), commandEndEvent( 'editor/documents/attach-preview' ) ],
|
|
47
|
+
notifyIfChanged
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
lastSerializedState = JSON.stringify( buildState() );
|
|
51
|
+
|
|
52
|
+
resource(
|
|
53
|
+
'editor-state',
|
|
54
|
+
EDITOR_STATE_URI,
|
|
55
|
+
{
|
|
56
|
+
description: 'Editor page title, preview text snapshot, and viewed screen label.',
|
|
57
|
+
},
|
|
58
|
+
async () => {
|
|
59
|
+
return {
|
|
60
|
+
contents: [
|
|
61
|
+
{
|
|
62
|
+
uri: EDITOR_STATE_URI,
|
|
63
|
+
text: JSON.stringify( buildState(), null, 2 ),
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
function getPageContentFromPreview(): string | null {
|
|
72
|
+
try {
|
|
73
|
+
const root = ( window as ElementorWindow ).elementor?.$previewContents?.[ 0 ];
|
|
74
|
+
if ( ! root ) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const content: string[] = [];
|
|
78
|
+
const clone = root.cloneNode( true ) as HTMLElement;
|
|
79
|
+
clone.querySelectorAll( '.elementor-editor-element-settings, #elementor-add-new-section' ).forEach( ( el ) => {
|
|
80
|
+
el.remove();
|
|
81
|
+
} );
|
|
82
|
+
const walk = ( node: Node, insideElementorElement = false ) => {
|
|
83
|
+
const isInside = ( node as Element ).classList?.contains( 'elementor-element' ) || insideElementorElement;
|
|
84
|
+
if ( node.nodeType === Node.TEXT_NODE && isInside ) {
|
|
85
|
+
const text = node.textContent?.trim().replace( /\s+/g, ' ' );
|
|
86
|
+
if ( text && text.length > PREVIEW_TEXT_NODE_MIN_LENGTH ) {
|
|
87
|
+
content.push( text );
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
node.childNodes.forEach( ( child ) => {
|
|
91
|
+
walk( child, isInside );
|
|
92
|
+
} );
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
walk( clone );
|
|
96
|
+
const text = content.join( ' ' );
|
|
97
|
+
if ( text.length > PAGE_CONTENT_CHARACTER_LIMIT ) {
|
|
98
|
+
return text.slice( 0, PAGE_CONTENT_CHARACTER_LIMIT ) + '...';
|
|
99
|
+
}
|
|
100
|
+
return text;
|
|
101
|
+
} catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function getPageTitle(): string {
|
|
107
|
+
try {
|
|
108
|
+
const extendedWindow = window as ElementorWindow;
|
|
109
|
+
const currentDocument = extendedWindow.elementor?.documents?.getCurrent?.();
|
|
110
|
+
const postTitle = currentDocument?.config?.settings?.post_title;
|
|
111
|
+
if ( postTitle ) {
|
|
112
|
+
return postTitle;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let title = document.title || 'Page';
|
|
116
|
+
title = title.split( /\s*[‹»|–—-]\s*/ )[ 0 ];
|
|
117
|
+
const trimmed = title.trim();
|
|
118
|
+
return trimmed || 'Page';
|
|
119
|
+
} catch {
|
|
120
|
+
return 'Page';
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
2
|
+
import { __privateListenTo as listenTo, commandEndEvent } from '@elementor/editor-v1-adapters';
|
|
3
|
+
|
|
4
|
+
type ExtendedWindow = Window & {
|
|
5
|
+
angieConfig?: {
|
|
6
|
+
plugins?: Record< string, unknown >;
|
|
7
|
+
};
|
|
8
|
+
elementor?: {
|
|
9
|
+
documents?: {
|
|
10
|
+
getCurrent?: () => {
|
|
11
|
+
config?: {
|
|
12
|
+
settings?: {
|
|
13
|
+
post_title?: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const GENERAL_CONTEXT_URI = 'elementor://context/general';
|
|
22
|
+
|
|
23
|
+
export const initGeneralContextResource = ( reg: MCPRegistryEntry ) => {
|
|
24
|
+
const { resource, sendResourceUpdated } = reg;
|
|
25
|
+
|
|
26
|
+
let lastSerializedPayload: string | null = null;
|
|
27
|
+
|
|
28
|
+
const getPageTitle = (): string | null => {
|
|
29
|
+
const extendedWindow = window as ExtendedWindow;
|
|
30
|
+
const title = extendedWindow.elementor?.documents?.getCurrent?.()?.config?.settings?.post_title;
|
|
31
|
+
if ( ! title?.trim() ) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return title;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const buildPayload = () => {
|
|
38
|
+
const extendedWindow = window as ExtendedWindow;
|
|
39
|
+
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
40
|
+
const postParam = new URLSearchParams( location.search ).get( 'post' );
|
|
41
|
+
const parsedPostId = postParam ? Number( postParam ) : null;
|
|
42
|
+
const postId = parsedPostId !== null && Number.isFinite( parsedPostId ) ? parsedPostId : null;
|
|
43
|
+
const pageTitle = getPageTitle();
|
|
44
|
+
const urlObject = new URL( window.location.href );
|
|
45
|
+
const pageUrl = urlObject.pathname + urlObject.search;
|
|
46
|
+
const pageName = pageTitle || 'Elementor Editor';
|
|
47
|
+
const plugins = extendedWindow.angieConfig?.plugins;
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
timezone,
|
|
51
|
+
postId,
|
|
52
|
+
currentPage: {
|
|
53
|
+
pageName,
|
|
54
|
+
pageTitle,
|
|
55
|
+
pageUrl,
|
|
56
|
+
},
|
|
57
|
+
...( plugins && { plugins } ),
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const pushUpdateIfChanged = () => {
|
|
62
|
+
const serialized = JSON.stringify( buildPayload() );
|
|
63
|
+
if ( serialized === lastSerializedPayload ) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
lastSerializedPayload = serialized;
|
|
67
|
+
sendResourceUpdated( { uri: GENERAL_CONTEXT_URI } );
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
resource(
|
|
71
|
+
'general-context',
|
|
72
|
+
GENERAL_CONTEXT_URI,
|
|
73
|
+
{
|
|
74
|
+
description: 'General context: timezone, post id, and current page.',
|
|
75
|
+
},
|
|
76
|
+
async () => {
|
|
77
|
+
return {
|
|
78
|
+
contents: [
|
|
79
|
+
{
|
|
80
|
+
uri: GENERAL_CONTEXT_URI,
|
|
81
|
+
mimeType: 'application/json',
|
|
82
|
+
text: JSON.stringify( buildPayload(), null, 2 ),
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
listenTo(
|
|
90
|
+
[
|
|
91
|
+
commandEndEvent( 'editor/documents/switch' ),
|
|
92
|
+
commandEndEvent( 'editor/documents/attach-preview' ),
|
|
93
|
+
commandEndEvent( 'document/elements/settings' ),
|
|
94
|
+
],
|
|
95
|
+
pushUpdateIfChanged
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
pushUpdateIfChanged();
|
|
99
|
+
};
|