@elementor/editor-global-classes 4.0.0-manual → 4.0.1
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 +196 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +185 -45
- package/dist/index.mjs.map +1 -1
- package/package.json +20 -20
- package/src/components/class-manager/class-item.tsx +10 -8
- package/src/components/class-manager/class-manager-panel.tsx +5 -1
- package/src/components/class-manager/start-sync-to-v3-modal.tsx +31 -5
- package/src/components/global-styles-import-listener.tsx +61 -0
- package/src/init.ts +11 -1
- package/src/mcp-integration/classes-resource.ts +2 -5
- package/src/mcp-integration/index.ts +13 -6
- package/src/save-global-classes.tsx +3 -0
- package/src/sync-with-document-save.ts +40 -11
- package/src/utils/tracking.ts +48 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/editor-global-classes",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "Elementor Team",
|
|
6
6
|
"homepage": "https://elementor.com/",
|
|
@@ -39,28 +39,28 @@
|
|
|
39
39
|
"dev": "tsup --config=../../tsup.dev.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@elementor/editor": "4.0.
|
|
43
|
-
"@elementor/editor-current-user": "4.0.
|
|
44
|
-
"@elementor/editor-documents": "4.0.
|
|
45
|
-
"@elementor/editor-editing-panel": "4.0.
|
|
46
|
-
"@elementor/editor-mcp": "4.0.
|
|
47
|
-
"@elementor/editor-panels": "4.0.
|
|
48
|
-
"@elementor/editor-props": "4.0.
|
|
49
|
-
"@elementor/editor-variables": "4.0.
|
|
50
|
-
"@elementor/editor-styles": "4.0.
|
|
51
|
-
"@elementor/editor-canvas": "4.0.
|
|
52
|
-
"@elementor/editor-styles-repository": "4.0.
|
|
53
|
-
"@elementor/editor-ui": "4.0.
|
|
54
|
-
"@elementor/editor-v1-adapters": "4.0.
|
|
55
|
-
"@elementor/http-client": "4.0.
|
|
42
|
+
"@elementor/editor": "4.0.1",
|
|
43
|
+
"@elementor/editor-current-user": "4.0.1",
|
|
44
|
+
"@elementor/editor-documents": "4.0.1",
|
|
45
|
+
"@elementor/editor-editing-panel": "4.0.1",
|
|
46
|
+
"@elementor/editor-mcp": "4.0.1",
|
|
47
|
+
"@elementor/editor-panels": "4.0.1",
|
|
48
|
+
"@elementor/editor-props": "4.0.1",
|
|
49
|
+
"@elementor/editor-variables": "4.0.1",
|
|
50
|
+
"@elementor/editor-styles": "4.0.1",
|
|
51
|
+
"@elementor/editor-canvas": "4.0.1",
|
|
52
|
+
"@elementor/editor-styles-repository": "4.0.1",
|
|
53
|
+
"@elementor/editor-ui": "4.0.1",
|
|
54
|
+
"@elementor/editor-v1-adapters": "4.0.1",
|
|
55
|
+
"@elementor/http-client": "4.0.1",
|
|
56
56
|
"@elementor/icons": "^1.68.0",
|
|
57
|
-
"@elementor/query": "4.0.
|
|
58
|
-
"@elementor/schema": "4.0.
|
|
59
|
-
"@elementor/store": "4.0.
|
|
57
|
+
"@elementor/query": "4.0.1",
|
|
58
|
+
"@elementor/schema": "4.0.1",
|
|
59
|
+
"@elementor/store": "4.0.1",
|
|
60
60
|
"@elementor/ui": "1.36.17",
|
|
61
|
-
"@elementor/utils": "4.0.
|
|
61
|
+
"@elementor/utils": "4.0.1",
|
|
62
62
|
"@wordpress/i18n": "^5.13.0",
|
|
63
|
-
"@elementor/events": "4.0.
|
|
63
|
+
"@elementor/events": "4.0.1"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"react": "^18.3.1",
|
|
@@ -2,8 +2,7 @@ import * as React from 'react';
|
|
|
2
2
|
import { useRef, useState } from 'react';
|
|
3
3
|
import { validateStyleLabel } from '@elementor/editor-styles-repository';
|
|
4
4
|
import { EditableField, EllipsisWithTooltip, MenuListItem, useEditable, WarningInfotip } from '@elementor/editor-ui';
|
|
5
|
-
import {
|
|
6
|
-
import { DotsVerticalIcon } from '@elementor/icons';
|
|
5
|
+
import { DotsVerticalIcon, RefreshIcon, RefreshOffIcon } from '@elementor/icons';
|
|
7
6
|
import {
|
|
8
7
|
bindMenu,
|
|
9
8
|
bindTrigger,
|
|
@@ -142,18 +141,21 @@ export const ClassItem = ( {
|
|
|
142
141
|
{ __( 'Rename', 'elementor' ) }
|
|
143
142
|
</Typography>
|
|
144
143
|
</MenuListItem>
|
|
145
|
-
{
|
|
144
|
+
{ onToggleSync && (
|
|
146
145
|
<MenuListItem
|
|
147
146
|
onClick={ () => {
|
|
148
147
|
popupState.close();
|
|
149
148
|
onToggleSync( id, ! syncToV3 );
|
|
150
149
|
} }
|
|
151
150
|
>
|
|
152
|
-
<
|
|
153
|
-
{ syncToV3
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
151
|
+
<Stack direction="row" alignItems="center" gap={ 1 }>
|
|
152
|
+
{ syncToV3 ? <RefreshOffIcon fontSize="tiny" /> : <RefreshIcon fontSize="tiny" /> }
|
|
153
|
+
<Typography variant="caption" sx={ { color: 'text.primary' } }>
|
|
154
|
+
{ syncToV3
|
|
155
|
+
? __( 'Stop syncing to Global Fonts', 'elementor' )
|
|
156
|
+
: __( 'Sync to Global Fonts', 'elementor' ) }
|
|
157
|
+
</Typography>
|
|
158
|
+
</Stack>
|
|
157
159
|
</MenuListItem>
|
|
158
160
|
) }
|
|
159
161
|
<MenuListItem
|
|
@@ -34,6 +34,7 @@ import { useDirtyState } from '../../hooks/use-dirty-state';
|
|
|
34
34
|
import { useFilters } from '../../hooks/use-filters';
|
|
35
35
|
import { saveGlobalClasses } from '../../save-global-classes';
|
|
36
36
|
import { slice } from '../../store';
|
|
37
|
+
import { trackGlobalClasses } from '../../utils/tracking';
|
|
37
38
|
import { ActiveFilters } from '../search-and-filter/components/filter/active-filters';
|
|
38
39
|
import { CssClassFilter } from '../search-and-filter/components/filter/css-class-filter';
|
|
39
40
|
import { ClassManagerSearch } from '../search-and-filter/components/search/class-manager-search';
|
|
@@ -113,6 +114,7 @@ export function ClassManagerPanel() {
|
|
|
113
114
|
},
|
|
114
115
|
} )
|
|
115
116
|
);
|
|
117
|
+
trackGlobalClasses( { event: 'classSyncToV3', classId, action: 'unsync' } );
|
|
116
118
|
setStopSyncConfirmation( null );
|
|
117
119
|
}, [] );
|
|
118
120
|
|
|
@@ -125,6 +127,7 @@ export function ClassManagerPanel() {
|
|
|
125
127
|
},
|
|
126
128
|
} )
|
|
127
129
|
);
|
|
130
|
+
trackGlobalClasses( { event: 'classSyncToV3', classId, action: 'sync' } );
|
|
128
131
|
setStartSyncConfirmation( null );
|
|
129
132
|
}, [] );
|
|
130
133
|
|
|
@@ -221,6 +224,7 @@ export function ClassManagerPanel() {
|
|
|
221
224
|
{ startSyncConfirmation && (
|
|
222
225
|
<StartSyncToV3Modal
|
|
223
226
|
externalOpen
|
|
227
|
+
classId={ startSyncConfirmation }
|
|
224
228
|
onExternalClose={ () => setStartSyncConfirmation( null ) }
|
|
225
229
|
onConfirm={ () => handleStartSync( startSyncConfirmation ) }
|
|
226
230
|
/>
|
|
@@ -338,7 +342,7 @@ const StopSyncConfirmationDialog = ( { open, onClose, onConfirm }: StopSyncConfi
|
|
|
338
342
|
</ConfirmationDialog.Title>
|
|
339
343
|
<ConfirmationDialog.Content>
|
|
340
344
|
<ConfirmationDialog.ContentText>
|
|
341
|
-
{ __( "You're about to stop syncing a typography class to
|
|
345
|
+
{ __( "You're about to stop syncing a typography class to Global Fonts.", 'elementor' ) }
|
|
342
346
|
</ConfirmationDialog.ContentText>
|
|
343
347
|
<ConfirmationDialog.ContentText sx={ { mt: 1 } }>
|
|
344
348
|
{ __(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { useState } from 'react';
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import {
|
|
4
4
|
Box,
|
|
5
5
|
Button,
|
|
@@ -12,22 +12,48 @@ import {
|
|
|
12
12
|
} from '@elementor/ui';
|
|
13
13
|
import { __ } from '@wordpress/i18n';
|
|
14
14
|
|
|
15
|
+
import { trackGlobalClasses } from '../../utils/tracking';
|
|
16
|
+
|
|
15
17
|
const IMAGE_URL = 'https://assets.elementor.com/packages/v1/images/class-manager-sync-modal.png';
|
|
16
18
|
|
|
17
19
|
type StartSyncToV3ModalProps = {
|
|
18
20
|
externalOpen?: boolean;
|
|
21
|
+
classId?: string;
|
|
19
22
|
onExternalClose?: () => void;
|
|
20
23
|
onConfirm?: () => void;
|
|
21
24
|
};
|
|
22
25
|
|
|
23
|
-
export const StartSyncToV3Modal = ( {
|
|
26
|
+
export const StartSyncToV3Modal = ( {
|
|
27
|
+
externalOpen,
|
|
28
|
+
classId,
|
|
29
|
+
onExternalClose,
|
|
30
|
+
onConfirm,
|
|
31
|
+
}: StartSyncToV3ModalProps = {} ) => {
|
|
24
32
|
const [ shouldShowAgain, setShouldShowAgain ] = useState( true );
|
|
33
|
+
const hasTrackedExposure = useRef( false );
|
|
34
|
+
|
|
35
|
+
useEffect( () => {
|
|
36
|
+
if ( externalOpen && classId && ! hasTrackedExposure.current ) {
|
|
37
|
+
hasTrackedExposure.current = true;
|
|
38
|
+
trackGlobalClasses( { event: 'classSyncToV3PopupShown', classId } );
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if ( ! externalOpen ) {
|
|
42
|
+
hasTrackedExposure.current = false;
|
|
43
|
+
}
|
|
44
|
+
}, [ externalOpen, classId ] );
|
|
25
45
|
|
|
26
46
|
const handleClose = () => {
|
|
47
|
+
if ( classId ) {
|
|
48
|
+
trackGlobalClasses( { event: 'classSyncToV3PopupClick', classId, action: 'cancel' } );
|
|
49
|
+
}
|
|
27
50
|
onExternalClose?.();
|
|
28
51
|
};
|
|
29
52
|
|
|
30
53
|
const handleConfirm = () => {
|
|
54
|
+
if ( classId ) {
|
|
55
|
+
trackGlobalClasses( { event: 'classSyncToV3PopupClick', classId, action: 'sync' } );
|
|
56
|
+
}
|
|
31
57
|
onConfirm?.();
|
|
32
58
|
onExternalClose?.();
|
|
33
59
|
};
|
|
@@ -37,10 +63,10 @@ export const StartSyncToV3Modal = ( { externalOpen, onExternalClose, onConfirm }
|
|
|
37
63
|
<DialogContent sx={ { p: 0 } }>
|
|
38
64
|
<Box component="img" src={ IMAGE_URL } alt="" sx={ { width: '100%', display: 'block' } } />
|
|
39
65
|
<Box sx={ { px: 3, pt: 4, pb: 1 } }>
|
|
40
|
-
<Typography variant="h6">{ __( 'Sync class to
|
|
66
|
+
<Typography variant="h6">{ __( 'Sync class to Global Fonts', 'elementor' ) }</Typography>
|
|
41
67
|
<Typography variant="body2" color="secondary" sx={ { mb: 2, pt: 1 } }>
|
|
42
68
|
{ __(
|
|
43
|
-
'Only typography settings supported in
|
|
69
|
+
'Only typography settings supported in Global Fonts will be applied, including: font family, responsive font sizes, weight, text transform, decoration, line height, letter spacing, and word spacing. Changes made in the class will automatically apply to Global Fonts.',
|
|
44
70
|
'elementor'
|
|
45
71
|
) }
|
|
46
72
|
</Typography>
|
|
@@ -67,7 +93,7 @@ export const StartSyncToV3Modal = ( { externalOpen, onExternalClose, onConfirm }
|
|
|
67
93
|
{ __( 'Cancel', 'elementor' ) }
|
|
68
94
|
</Button>
|
|
69
95
|
<Button onClick={ handleConfirm } variant="contained" size="small">
|
|
70
|
-
{ __( 'Sync to
|
|
96
|
+
{ __( 'Sync to Global Fonts', 'elementor' ) }
|
|
71
97
|
</Button>
|
|
72
98
|
</Box>
|
|
73
99
|
</DialogActions>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { __useDispatch as useDispatch } from '@elementor/store';
|
|
3
|
+
|
|
4
|
+
import { apiClient } from '../api';
|
|
5
|
+
import { slice } from '../store';
|
|
6
|
+
|
|
7
|
+
export function GlobalStylesImportListener() {
|
|
8
|
+
const dispatch = useDispatch();
|
|
9
|
+
|
|
10
|
+
useEffect( () => {
|
|
11
|
+
const handleGlobalStylesImported = ( event: CustomEvent ) => {
|
|
12
|
+
const importedClasses = event.detail?.global_classes;
|
|
13
|
+
|
|
14
|
+
if ( importedClasses?.items && importedClasses?.order ) {
|
|
15
|
+
dispatch(
|
|
16
|
+
slice.actions.load( {
|
|
17
|
+
preview: {
|
|
18
|
+
items: importedClasses.items,
|
|
19
|
+
order: importedClasses.order,
|
|
20
|
+
},
|
|
21
|
+
frontend: {
|
|
22
|
+
items: importedClasses.items,
|
|
23
|
+
order: importedClasses.order,
|
|
24
|
+
},
|
|
25
|
+
} )
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
Promise.all( [ apiClient.all( 'preview' ), apiClient.all( 'frontend' ) ] )
|
|
30
|
+
.then( ( [ previewRes, frontendRes ] ) => {
|
|
31
|
+
const { data: previewData } = previewRes;
|
|
32
|
+
const { data: frontendData } = frontendRes;
|
|
33
|
+
|
|
34
|
+
dispatch(
|
|
35
|
+
slice.actions.load( {
|
|
36
|
+
preview: {
|
|
37
|
+
items: previewData.data,
|
|
38
|
+
order: previewData.meta.order,
|
|
39
|
+
},
|
|
40
|
+
frontend: {
|
|
41
|
+
items: frontendData.data,
|
|
42
|
+
order: frontendData.meta.order,
|
|
43
|
+
},
|
|
44
|
+
} )
|
|
45
|
+
);
|
|
46
|
+
} )
|
|
47
|
+
.catch( () => {} );
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
window.addEventListener( 'elementor/global-styles/imported', handleGlobalStylesImported as EventListener );
|
|
51
|
+
|
|
52
|
+
return () => {
|
|
53
|
+
window.removeEventListener(
|
|
54
|
+
'elementor/global-styles/imported',
|
|
55
|
+
handleGlobalStylesImported as EventListener
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
}, [ dispatch ] );
|
|
59
|
+
|
|
60
|
+
return null;
|
|
61
|
+
}
|
package/src/init.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
injectIntoCssClassConvert,
|
|
5
5
|
registerStyleProviderToColors,
|
|
6
6
|
} from '@elementor/editor-editing-panel';
|
|
7
|
+
import { getMCPByDomain } from '@elementor/editor-mcp';
|
|
7
8
|
import { __registerPanel as registerPanel } from '@elementor/editor-panels';
|
|
8
9
|
import { stylesRepository } from '@elementor/editor-styles-repository';
|
|
9
10
|
import { __registerSlice as registerSlice } from '@elementor/store';
|
|
@@ -11,6 +12,7 @@ import { __registerSlice as registerSlice } from '@elementor/store';
|
|
|
11
12
|
import { ClassManagerButton } from './components/class-manager/class-manager-button';
|
|
12
13
|
import { panel } from './components/class-manager/class-manager-panel';
|
|
13
14
|
import { ConvertLocalClassToGlobalClass } from './components/convert-local-class-to-global-class';
|
|
15
|
+
import { GlobalStylesImportListener } from './components/global-styles-import-listener';
|
|
14
16
|
import { OpenPanelFromUrl } from './components/open-panel-from-url';
|
|
15
17
|
import { PopulateStore } from './components/populate-store';
|
|
16
18
|
import { GLOBAL_CLASSES_PROVIDER_KEY, globalClassesStylesProvider } from './global-classes-styles-provider';
|
|
@@ -35,6 +37,11 @@ export function init() {
|
|
|
35
37
|
component: SyncWithDocumentSave,
|
|
36
38
|
} );
|
|
37
39
|
|
|
40
|
+
injectIntoLogic( {
|
|
41
|
+
id: 'global-classes-import-listener',
|
|
42
|
+
component: GlobalStylesImportListener,
|
|
43
|
+
} );
|
|
44
|
+
|
|
38
45
|
injectIntoLogic( {
|
|
39
46
|
id: 'global-classes-prefetch-css-class-usage',
|
|
40
47
|
component: PrefetchCssClassUsage,
|
|
@@ -60,5 +67,8 @@ export function init() {
|
|
|
60
67
|
getThemeColor: ( theme ) => theme.palette.global.dark,
|
|
61
68
|
} );
|
|
62
69
|
|
|
63
|
-
initMcpIntegration(
|
|
70
|
+
initMcpIntegration(
|
|
71
|
+
getMCPByDomain( 'classes', { instructions: 'MCP server for management of Elementor global classes' } ),
|
|
72
|
+
getMCPByDomain( 'canvas' )
|
|
73
|
+
);
|
|
64
74
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
2
2
|
|
|
3
3
|
import { globalClassesStylesProvider } from '../global-classes-styles-provider';
|
|
4
4
|
|
|
@@ -12,10 +12,7 @@ const updateLocalStorageCache = () => {
|
|
|
12
12
|
localStorage.setItem( STORAGE_KEY, JSON.stringify( classes ) );
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
export const initClassesResource = () => {
|
|
16
|
-
const canvasMcpEntry = getMCPByDomain( 'canvas' );
|
|
17
|
-
const classesMcpEntry = getMCPByDomain( 'classes' );
|
|
18
|
-
|
|
15
|
+
export const initClassesResource = ( classesMcpEntry: MCPRegistryEntry, canvasMcpEntry: MCPRegistryEntry ) => {
|
|
19
16
|
[ canvasMcpEntry, classesMcpEntry ].forEach( ( entry ) => {
|
|
20
17
|
const { mcpServer, resource, waitForReady } = entry;
|
|
21
18
|
resource(
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type MCPRegistryEntry } from '@elementor/editor-mcp';
|
|
2
2
|
|
|
3
3
|
import { initClassesResource } from './classes-resource';
|
|
4
4
|
import initMcpApplyUnapplyGlobalClasses from './mcp-apply-unapply-global-classes';
|
|
5
5
|
import initMcpApplyGetGlobalClassUsages from './mcp-get-global-class-usages';
|
|
6
6
|
import { initManageGlobalClasses } from './mcp-manage-global-classes';
|
|
7
7
|
|
|
8
|
-
export const initMcpIntegration = () => {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
export const initMcpIntegration = ( reg: MCPRegistryEntry, canvasMcpEntry: MCPRegistryEntry ) => {
|
|
9
|
+
const { setMCPDescription } = reg;
|
|
10
|
+
setMCPDescription(
|
|
11
|
+
`Everything related to V4 ( Atomic ) global classes.
|
|
12
|
+
# Global classes
|
|
13
|
+
- Create/update/delete global classes
|
|
14
|
+
- Get list of global classes
|
|
15
|
+
- Get details of a global class
|
|
16
|
+
- Get details of a global class
|
|
17
|
+
`
|
|
18
|
+
);
|
|
12
19
|
initMcpApplyUnapplyGlobalClasses( reg );
|
|
13
20
|
initMcpApplyGetGlobalClassUsages( reg );
|
|
14
21
|
initManageGlobalClasses( reg );
|
|
15
|
-
initClassesResource();
|
|
22
|
+
initClassesResource( reg, canvasMcpEntry );
|
|
16
23
|
};
|
|
@@ -24,6 +24,9 @@ export async function saveGlobalClasses( { context, onApprove }: Options ) {
|
|
|
24
24
|
} );
|
|
25
25
|
|
|
26
26
|
dispatch( slice.actions.reset( { context } ) );
|
|
27
|
+
|
|
28
|
+
window.dispatchEvent( new CustomEvent( 'classes:updated', { detail: { context } } ) );
|
|
29
|
+
|
|
27
30
|
if ( response?.data?.data?.code === API_ERROR_CODES.DUPLICATED_LABEL ) {
|
|
28
31
|
dispatch( slice.actions.updateMultiple( response.data.data.modifiedLabels ) );
|
|
29
32
|
trackGlobalClasses( {
|
|
@@ -7,10 +7,13 @@ import { UPDATE_CLASS_CAPABILITY_KEY } from './capabilities';
|
|
|
7
7
|
import { saveGlobalClasses } from './save-global-classes';
|
|
8
8
|
import { selectIsDirty } from './store';
|
|
9
9
|
|
|
10
|
+
let pendingSave: Promise< void > | null = null;
|
|
11
|
+
|
|
10
12
|
export function syncWithDocumentSave( panelActions?: { open: () => void } ) {
|
|
11
13
|
const unsubscribe = syncDirtyState();
|
|
12
14
|
|
|
13
15
|
bindSaveAction( panelActions );
|
|
16
|
+
bindBeforeSaveTemplateAction();
|
|
14
17
|
|
|
15
18
|
return unsubscribe;
|
|
16
19
|
}
|
|
@@ -25,25 +28,51 @@ function syncDirtyState() {
|
|
|
25
28
|
} );
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
function triggerSave( panelActions?: { open: () => void }, context: 'preview' | 'frontend' = 'preview' ) {
|
|
32
|
+
const user = getCurrentUser();
|
|
33
|
+
const canEdit = user?.capabilities.includes( UPDATE_CLASS_CAPABILITY_KEY );
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
if ( ! canEdit ) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
33
38
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
if ( pendingSave ) {
|
|
40
|
+
return pendingSave;
|
|
41
|
+
}
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
const promise = saveGlobalClasses( {
|
|
44
|
+
context,
|
|
45
|
+
onApprove: panelActions?.open,
|
|
46
|
+
} );
|
|
47
|
+
|
|
48
|
+
pendingSave = promise;
|
|
49
|
+
promise.finally( () => {
|
|
50
|
+
pendingSave = null;
|
|
51
|
+
} );
|
|
52
|
+
|
|
53
|
+
return promise;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function bindSaveAction( panelActions?: { open: () => void } ) {
|
|
57
|
+
registerDataHook( 'dependency', 'document/save/save', ( args ) => {
|
|
58
|
+
triggerSave( panelActions, args.status === 'publish' ? 'frontend' : 'preview' );
|
|
42
59
|
|
|
43
60
|
return true;
|
|
44
61
|
} );
|
|
45
62
|
}
|
|
46
63
|
|
|
64
|
+
function bindBeforeSaveTemplateAction() {
|
|
65
|
+
window.addEventListener( 'elementor/global-styles/before-save', ( ( event: CustomEvent ) => {
|
|
66
|
+
if ( ! pendingSave && isDirty() ) {
|
|
67
|
+
triggerSave();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if ( pendingSave ) {
|
|
71
|
+
event.detail.promises.push( pendingSave );
|
|
72
|
+
}
|
|
73
|
+
} ) as EventListener );
|
|
74
|
+
}
|
|
75
|
+
|
|
47
76
|
function isDirty() {
|
|
48
77
|
return selectIsDirty( getState() );
|
|
49
78
|
}
|
package/src/utils/tracking.ts
CHANGED
|
@@ -72,6 +72,17 @@ type EventMap = {
|
|
|
72
72
|
type: string;
|
|
73
73
|
source: 'global' | 'local';
|
|
74
74
|
};
|
|
75
|
+
classSyncToV3PopupShown: {
|
|
76
|
+
classId: StyleDefinitionID;
|
|
77
|
+
};
|
|
78
|
+
classSyncToV3: {
|
|
79
|
+
classId: StyleDefinitionID;
|
|
80
|
+
action: 'sync' | 'unsync';
|
|
81
|
+
};
|
|
82
|
+
classSyncToV3PopupClick: {
|
|
83
|
+
classId: StyleDefinitionID;
|
|
84
|
+
action: 'sync' | 'cancel';
|
|
85
|
+
};
|
|
75
86
|
};
|
|
76
87
|
|
|
77
88
|
export type TrackingEvent = {
|
|
@@ -138,6 +149,43 @@ const getSanitizedData = async ( payload: TrackingEvent ): Promise< Record< stri
|
|
|
138
149
|
return { ...payload, classTitle: getCssClass( payload.classId ).label };
|
|
139
150
|
}
|
|
140
151
|
break;
|
|
152
|
+
case 'classSyncToV3PopupShown':
|
|
153
|
+
return {
|
|
154
|
+
...payload,
|
|
155
|
+
interaction_type: 'popup_shown',
|
|
156
|
+
target_type: 'popup',
|
|
157
|
+
target_name: 'sync_to_v3_popup',
|
|
158
|
+
interaction_result: 'popup_viewed',
|
|
159
|
+
target_location: 'widget_panel',
|
|
160
|
+
location_l1: 'class_manager',
|
|
161
|
+
};
|
|
162
|
+
case 'classSyncToV3': {
|
|
163
|
+
const classLabel = getCssClass( payload.classId ).label;
|
|
164
|
+
const isSync = payload.action === 'sync';
|
|
165
|
+
return {
|
|
166
|
+
...payload,
|
|
167
|
+
interaction_type: 'click',
|
|
168
|
+
target_type: classLabel,
|
|
169
|
+
target_name: isSync ? 'sync_to_v3' : 'unsync_to_v3',
|
|
170
|
+
interaction_result: isSync ? 'class_is_synced_to_V3' : 'class_is_unsynced_from_V3',
|
|
171
|
+
target_location: 'widget_panel',
|
|
172
|
+
location_l1: 'class_manager',
|
|
173
|
+
interaction_description: isSync
|
|
174
|
+
? `user_synced_${ classLabel }_to_v3`
|
|
175
|
+
: `user_unsync_${ classLabel }_from_v3`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
case 'classSyncToV3PopupClick': {
|
|
179
|
+
const isSyncAction = payload.action === 'sync';
|
|
180
|
+
return {
|
|
181
|
+
...payload,
|
|
182
|
+
interaction_type: 'click',
|
|
183
|
+
target_type: 'button',
|
|
184
|
+
target_name: isSyncAction ? 'sync_to_v3' : 'cancel',
|
|
185
|
+
interaction_result: isSyncAction ? 'class_is_synced' : 'cancel',
|
|
186
|
+
target_location: 'sync_to_v3_popup',
|
|
187
|
+
};
|
|
188
|
+
}
|
|
141
189
|
default:
|
|
142
190
|
return payload;
|
|
143
191
|
}
|