@dotcms/uve 0.0.1-beta.10 → 0.0.1-beta.12
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/index.cjs.js +92 -11
- package/index.esm.js +89 -12
- package/internal.cjs.js +360 -16
- package/internal.esm.js +354 -17
- package/package.json +1 -1
- package/src/index.d.ts +2 -1
- package/src/internal/constants.d.ts +3 -3
- package/src/internal/events.d.ts +66 -0
- package/src/internal.d.ts +1 -0
- package/src/lib/{utils.d.ts → core/core.utils.d.ts} +11 -7
- package/src/lib/dom/dom.utils.d.ts +111 -0
- package/src/lib/editor/internal.d.ts +8 -0
- package/src/lib/editor/public.d.ts +38 -0
- package/src/lib/types/editor/internal.d.ts +75 -0
- package/src/lib/types/editor/public.d.ts +55 -12
- package/src/lib/types/events/internal.d.ts +3 -1
- package/src/script/sdk-editor.d.ts +6 -0
- package/src/script/utils.d.ts +4 -0
- package/types.cjs.js +27 -0
- package/types.esm.js +28 -1
package/index.cjs.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var types = require('./types.cjs.js');
|
|
4
3
|
var internal = require('./internal.cjs.js');
|
|
4
|
+
var types = require('./types.cjs.js');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Gets the current state of the Universal Visual Editor (UVE).
|
|
@@ -58,29 +58,110 @@ function getUVEState() {
|
|
|
58
58
|
/**
|
|
59
59
|
* Creates a subscription to a UVE event.
|
|
60
60
|
*
|
|
61
|
-
* @param
|
|
62
|
-
* @param
|
|
63
|
-
* @
|
|
61
|
+
* @param eventType - The type of event to subscribe to
|
|
62
|
+
* @param callback - The callback function that will be called when the event occurs
|
|
63
|
+
* @returns An event subscription that can be used to unsubscribe
|
|
64
64
|
*
|
|
65
65
|
* @example
|
|
66
66
|
* ```ts
|
|
67
|
-
*
|
|
68
|
-
*
|
|
67
|
+
* // Subscribe to page changes
|
|
68
|
+
* const subscription = createUVESubscription(UVEEventType.CONTENT_CHANGES, (changes) => {
|
|
69
|
+
* console.log('Content changes:', changes);
|
|
69
70
|
* });
|
|
71
|
+
*
|
|
72
|
+
* // Later, unsubscribe when no longer needed
|
|
73
|
+
* subscription.unsubscribe();
|
|
70
74
|
* ```
|
|
71
75
|
*/
|
|
72
|
-
function createUVESubscription(
|
|
76
|
+
function createUVESubscription(eventType, callback) {
|
|
73
77
|
if (!getUVEState()) {
|
|
74
78
|
console.warn('UVE Subscription: Not running inside UVE');
|
|
75
|
-
return internal.__UVE_EVENT_ERROR_FALLBACK__(
|
|
79
|
+
return internal.__UVE_EVENT_ERROR_FALLBACK__(eventType);
|
|
76
80
|
}
|
|
77
|
-
const eventCallback = internal.__UVE_EVENTS__[
|
|
81
|
+
const eventCallback = internal.__UVE_EVENTS__[eventType];
|
|
78
82
|
if (!eventCallback) {
|
|
79
|
-
console.error(`UVE Subscription: Event ${
|
|
80
|
-
return internal.__UVE_EVENT_ERROR_FALLBACK__(
|
|
83
|
+
console.error(`UVE Subscription: Event ${eventType} not found`);
|
|
84
|
+
return internal.__UVE_EVENT_ERROR_FALLBACK__(eventType);
|
|
81
85
|
}
|
|
82
86
|
return eventCallback(callback);
|
|
83
87
|
}
|
|
84
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Post message to dotcms page editor
|
|
91
|
+
*
|
|
92
|
+
* @export
|
|
93
|
+
* @template T
|
|
94
|
+
* @param {DotCMSUVEMessage<T>} message
|
|
95
|
+
*/
|
|
96
|
+
function sendMessageToEditor(message) {
|
|
97
|
+
window.parent.postMessage(message, '*');
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* You can use this function to edit a contentlet in the editor.
|
|
101
|
+
*
|
|
102
|
+
* Calling this function inside the editor, will prompt the UVE to open a dialog to edit the contentlet.
|
|
103
|
+
*
|
|
104
|
+
* @export
|
|
105
|
+
* @template T
|
|
106
|
+
* @param {Contentlet<T>} contentlet - The contentlet to edit.
|
|
107
|
+
*/
|
|
108
|
+
function editContentlet(contentlet) {
|
|
109
|
+
sendMessageToEditor({
|
|
110
|
+
action: types.DotCMSUVEAction.EDIT_CONTENTLET,
|
|
111
|
+
payload: contentlet
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/*
|
|
115
|
+
* Reorders the menu based on the provided configuration.
|
|
116
|
+
*
|
|
117
|
+
* @param {ReorderMenuConfig} [config] - Optional configuration for reordering the menu.
|
|
118
|
+
* @param {number} [config.startLevel=1] - The starting level of the menu to reorder.
|
|
119
|
+
* @param {number} [config.depth=2] - The depth of the menu to reorder.
|
|
120
|
+
*
|
|
121
|
+
* This function constructs a URL for the reorder menu page with the specified
|
|
122
|
+
* start level and depth, and sends a message to the editor to perform the reorder action.
|
|
123
|
+
*/
|
|
124
|
+
function reorderMenu(config) {
|
|
125
|
+
const {
|
|
126
|
+
startLevel = 1,
|
|
127
|
+
depth = 2
|
|
128
|
+
} = config || {};
|
|
129
|
+
sendMessageToEditor({
|
|
130
|
+
action: types.DotCMSUVEAction.REORDER_MENU,
|
|
131
|
+
payload: {
|
|
132
|
+
startLevel,
|
|
133
|
+
depth
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Initializes the inline editing in the editor.
|
|
139
|
+
*
|
|
140
|
+
* @export
|
|
141
|
+
* @param {INLINE_EDITING_EVENT_KEY} type
|
|
142
|
+
* @param {InlineEditEventData} eventData
|
|
143
|
+
* @return {*}
|
|
144
|
+
*
|
|
145
|
+
* * @example
|
|
146
|
+
* ```html
|
|
147
|
+
* <div onclick="initInlineEditing('BLOCK_EDITOR', { inode, languageId, contentType, fieldName, content })">
|
|
148
|
+
* ${My Content}
|
|
149
|
+
* </div>
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
function initInlineEditing(type, data) {
|
|
153
|
+
sendMessageToEditor({
|
|
154
|
+
action: types.DotCMSUVEAction.INIT_INLINE_EDITING,
|
|
155
|
+
payload: {
|
|
156
|
+
type,
|
|
157
|
+
data
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
85
162
|
exports.createUVESubscription = createUVESubscription;
|
|
163
|
+
exports.editContentlet = editContentlet;
|
|
86
164
|
exports.getUVEState = getUVEState;
|
|
165
|
+
exports.initInlineEditing = initInlineEditing;
|
|
166
|
+
exports.reorderMenu = reorderMenu;
|
|
167
|
+
exports.sendMessageToEditor = sendMessageToEditor;
|
package/index.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { UVE_MODE } from './types.esm.js';
|
|
2
1
|
import { __UVE_EVENT_ERROR_FALLBACK__, __UVE_EVENTS__ } from './internal.esm.js';
|
|
2
|
+
import { UVE_MODE, DotCMSUVEAction } from './types.esm.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Gets the current state of the Universal Visual Editor (UVE).
|
|
@@ -56,28 +56,105 @@ function getUVEState() {
|
|
|
56
56
|
/**
|
|
57
57
|
* Creates a subscription to a UVE event.
|
|
58
58
|
*
|
|
59
|
-
* @param
|
|
60
|
-
* @param
|
|
61
|
-
* @
|
|
59
|
+
* @param eventType - The type of event to subscribe to
|
|
60
|
+
* @param callback - The callback function that will be called when the event occurs
|
|
61
|
+
* @returns An event subscription that can be used to unsubscribe
|
|
62
62
|
*
|
|
63
63
|
* @example
|
|
64
64
|
* ```ts
|
|
65
|
-
*
|
|
66
|
-
*
|
|
65
|
+
* // Subscribe to page changes
|
|
66
|
+
* const subscription = createUVESubscription(UVEEventType.CONTENT_CHANGES, (changes) => {
|
|
67
|
+
* console.log('Content changes:', changes);
|
|
67
68
|
* });
|
|
69
|
+
*
|
|
70
|
+
* // Later, unsubscribe when no longer needed
|
|
71
|
+
* subscription.unsubscribe();
|
|
68
72
|
* ```
|
|
69
73
|
*/
|
|
70
|
-
function createUVESubscription(
|
|
74
|
+
function createUVESubscription(eventType, callback) {
|
|
71
75
|
if (!getUVEState()) {
|
|
72
76
|
console.warn('UVE Subscription: Not running inside UVE');
|
|
73
|
-
return __UVE_EVENT_ERROR_FALLBACK__(
|
|
77
|
+
return __UVE_EVENT_ERROR_FALLBACK__(eventType);
|
|
74
78
|
}
|
|
75
|
-
const eventCallback = __UVE_EVENTS__[
|
|
79
|
+
const eventCallback = __UVE_EVENTS__[eventType];
|
|
76
80
|
if (!eventCallback) {
|
|
77
|
-
console.error(`UVE Subscription: Event ${
|
|
78
|
-
return __UVE_EVENT_ERROR_FALLBACK__(
|
|
81
|
+
console.error(`UVE Subscription: Event ${eventType} not found`);
|
|
82
|
+
return __UVE_EVENT_ERROR_FALLBACK__(eventType);
|
|
79
83
|
}
|
|
80
84
|
return eventCallback(callback);
|
|
81
85
|
}
|
|
82
86
|
|
|
83
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Post message to dotcms page editor
|
|
89
|
+
*
|
|
90
|
+
* @export
|
|
91
|
+
* @template T
|
|
92
|
+
* @param {DotCMSUVEMessage<T>} message
|
|
93
|
+
*/
|
|
94
|
+
function sendMessageToEditor(message) {
|
|
95
|
+
window.parent.postMessage(message, '*');
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* You can use this function to edit a contentlet in the editor.
|
|
99
|
+
*
|
|
100
|
+
* Calling this function inside the editor, will prompt the UVE to open a dialog to edit the contentlet.
|
|
101
|
+
*
|
|
102
|
+
* @export
|
|
103
|
+
* @template T
|
|
104
|
+
* @param {Contentlet<T>} contentlet - The contentlet to edit.
|
|
105
|
+
*/
|
|
106
|
+
function editContentlet(contentlet) {
|
|
107
|
+
sendMessageToEditor({
|
|
108
|
+
action: DotCMSUVEAction.EDIT_CONTENTLET,
|
|
109
|
+
payload: contentlet
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/*
|
|
113
|
+
* Reorders the menu based on the provided configuration.
|
|
114
|
+
*
|
|
115
|
+
* @param {ReorderMenuConfig} [config] - Optional configuration for reordering the menu.
|
|
116
|
+
* @param {number} [config.startLevel=1] - The starting level of the menu to reorder.
|
|
117
|
+
* @param {number} [config.depth=2] - The depth of the menu to reorder.
|
|
118
|
+
*
|
|
119
|
+
* This function constructs a URL for the reorder menu page with the specified
|
|
120
|
+
* start level and depth, and sends a message to the editor to perform the reorder action.
|
|
121
|
+
*/
|
|
122
|
+
function reorderMenu(config) {
|
|
123
|
+
const {
|
|
124
|
+
startLevel = 1,
|
|
125
|
+
depth = 2
|
|
126
|
+
} = config || {};
|
|
127
|
+
sendMessageToEditor({
|
|
128
|
+
action: DotCMSUVEAction.REORDER_MENU,
|
|
129
|
+
payload: {
|
|
130
|
+
startLevel,
|
|
131
|
+
depth
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Initializes the inline editing in the editor.
|
|
137
|
+
*
|
|
138
|
+
* @export
|
|
139
|
+
* @param {INLINE_EDITING_EVENT_KEY} type
|
|
140
|
+
* @param {InlineEditEventData} eventData
|
|
141
|
+
* @return {*}
|
|
142
|
+
*
|
|
143
|
+
* * @example
|
|
144
|
+
* ```html
|
|
145
|
+
* <div onclick="initInlineEditing('BLOCK_EDITOR', { inode, languageId, contentType, fieldName, content })">
|
|
146
|
+
* ${My Content}
|
|
147
|
+
* </div>
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
function initInlineEditing(type, data) {
|
|
151
|
+
sendMessageToEditor({
|
|
152
|
+
action: DotCMSUVEAction.INIT_INLINE_EDITING,
|
|
153
|
+
payload: {
|
|
154
|
+
type,
|
|
155
|
+
data
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export { createUVESubscription, editContentlet, getUVEState, initInlineEditing, reorderMenu, sendMessageToEditor };
|
package/internal.cjs.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var types = require('./types.cjs.js');
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Actions received from the dotcms editor
|
|
5
7
|
*
|
|
@@ -25,7 +27,9 @@ exports.__DOTCMS_UVE_EVENT__ = void 0;
|
|
|
25
27
|
*/
|
|
26
28
|
__DOTCMS_UVE_EVENT__["UVE_SCROLL_INSIDE_IFRAME"] = "uve-scroll-inside-iframe";
|
|
27
29
|
/**
|
|
28
|
-
*
|
|
30
|
+
* TODO:
|
|
31
|
+
* Set the page data - This is used to catch the "changes" event.
|
|
32
|
+
* We must to re-check the name late.
|
|
29
33
|
*/
|
|
30
34
|
__DOTCMS_UVE_EVENT__["UVE_SET_PAGE_DATA"] = "uve-set-page-data";
|
|
31
35
|
/**
|
|
@@ -34,27 +38,360 @@ exports.__DOTCMS_UVE_EVENT__ = void 0;
|
|
|
34
38
|
__DOTCMS_UVE_EVENT__["UVE_COPY_CONTENTLET_INLINE_EDITING_SUCCESS"] = "uve-copy-contentlet-inline-editing-success";
|
|
35
39
|
})(exports.__DOTCMS_UVE_EVENT__ || (exports.__DOTCMS_UVE_EVENT__ = {}));
|
|
36
40
|
|
|
37
|
-
// TODO: WE NEED TO LOOK FOR ALL THE NOTIFY_CLIENT EVENTS AND ADD THEM TO THE UVE_EVENTS CONSTANT WHEN WE MIGRATE THE EDITOR TO THE NEW UVE LIBRARY
|
|
38
41
|
/**
|
|
39
|
-
*
|
|
42
|
+
* Calculates the bounding information for each page element within the given containers.
|
|
40
43
|
*
|
|
41
|
-
* @
|
|
42
|
-
* @
|
|
44
|
+
* @export
|
|
45
|
+
* @param {HTMLDivElement[]} containers - An array of HTMLDivElement representing the containers.
|
|
46
|
+
* @return {DotCMSContainerBound[]} An array of objects containing the bounding information for each page element.
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* const containers = document.querySelectorAll('.container');
|
|
50
|
+
* const bounds = getDotCMSPageBounds(containers);
|
|
51
|
+
* console.log(bounds);
|
|
52
|
+
* ```
|
|
43
53
|
*/
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
function getDotCMSPageBounds(containers) {
|
|
55
|
+
return containers.map(container => {
|
|
56
|
+
const containerRect = container.getBoundingClientRect();
|
|
57
|
+
const contentlets = Array.from(container.querySelectorAll('[data-dot-object="contentlet"]'));
|
|
58
|
+
return {
|
|
59
|
+
x: containerRect.x,
|
|
60
|
+
y: containerRect.y,
|
|
61
|
+
width: containerRect.width,
|
|
62
|
+
height: containerRect.height,
|
|
63
|
+
payload: JSON.stringify({
|
|
64
|
+
container: getDotCMSContainerData(container)
|
|
65
|
+
}),
|
|
66
|
+
contentlets: getDotCMSContentletsBound(containerRect, contentlets)
|
|
50
67
|
};
|
|
51
|
-
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Calculates the bounding information for each contentlet inside a container.
|
|
72
|
+
*
|
|
73
|
+
* @export
|
|
74
|
+
* @param {DOMRect} containerRect - The bounding rectangle of the container.
|
|
75
|
+
* @param {HTMLDivElement[]} contentlets - An array of HTMLDivElement representing the contentlets.
|
|
76
|
+
* @return {DotCMSContentletBound[]} An array of objects containing the bounding information for each contentlet.
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* const containerRect = container.getBoundingClientRect();
|
|
80
|
+
* const contentlets = container.querySelectorAll('.contentlet');
|
|
81
|
+
* const bounds = getDotCMSContentletsBound(containerRect, contentlets);
|
|
82
|
+
* console.log(bounds); // Element bounds within the container
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
function getDotCMSContentletsBound(containerRect, contentlets) {
|
|
86
|
+
return contentlets.map(contentlet => {
|
|
87
|
+
const contentletRect = contentlet.getBoundingClientRect();
|
|
52
88
|
return {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
89
|
+
x: 0,
|
|
90
|
+
y: contentletRect.y - containerRect.y,
|
|
91
|
+
width: contentletRect.width,
|
|
92
|
+
height: contentletRect.height,
|
|
93
|
+
payload: JSON.stringify({
|
|
94
|
+
container: contentlet.dataset?.['dotContainer'] ? JSON.parse(contentlet.dataset?.['dotContainer']) : getClosestDotCMSContainerData(contentlet),
|
|
95
|
+
contentlet: {
|
|
96
|
+
identifier: contentlet.dataset?.['dotIdentifier'],
|
|
97
|
+
title: contentlet.dataset?.['dotTitle'],
|
|
98
|
+
inode: contentlet.dataset?.['dotInode'],
|
|
99
|
+
contentType: contentlet.dataset?.['dotType']
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get container data from VTLS.
|
|
107
|
+
*
|
|
108
|
+
* @export
|
|
109
|
+
* @param {HTMLElement} container - The container element.
|
|
110
|
+
* @return {object} An object containing the container data.
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* const container = document.querySelector('.container');
|
|
114
|
+
* const data = getContainerData(container);
|
|
115
|
+
* console.log(data);
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
function getDotCMSContainerData(container) {
|
|
119
|
+
return {
|
|
120
|
+
acceptTypes: container.dataset?.['dotAcceptTypes'] || '',
|
|
121
|
+
identifier: container.dataset?.['dotIdentifier'] || '',
|
|
122
|
+
maxContentlets: container.dataset?.['maxContentlets'] || '',
|
|
123
|
+
uuid: container.dataset?.['dotUuid'] || ''
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get the closest container data from the contentlet.
|
|
128
|
+
*
|
|
129
|
+
* @export
|
|
130
|
+
* @param {Element} element - The contentlet element.
|
|
131
|
+
* @return {object | null} An object containing the closest container data or null if no container is found.
|
|
132
|
+
* @example
|
|
133
|
+
* ```ts
|
|
134
|
+
* const contentlet = document.querySelector('.contentlet');
|
|
135
|
+
* const data = getClosestDotCMSContainerData(contentlet);
|
|
136
|
+
* console.log(data);
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
function getClosestDotCMSContainerData(element) {
|
|
140
|
+
// Find the closest ancestor element with data-dot-object="container" attribute
|
|
141
|
+
const container = element.closest('[data-dot-object="container"]');
|
|
142
|
+
// If a container element is found
|
|
143
|
+
if (container) {
|
|
144
|
+
// Return the dataset of the container element
|
|
145
|
+
return getDotCMSContainerData(container);
|
|
146
|
+
} else {
|
|
147
|
+
// If no container element is found, return null
|
|
148
|
+
console.warn('No container found for the contentlet');
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Find the closest contentlet element based on HTMLElement.
|
|
154
|
+
*
|
|
155
|
+
* @export
|
|
156
|
+
* @param {HTMLElement | null} element - The starting element.
|
|
157
|
+
* @return {HTMLElement | null} The closest contentlet element or null if not found.
|
|
158
|
+
* @example
|
|
159
|
+
* const element = document.querySelector('.some-element');
|
|
160
|
+
* const contentlet = findDotCMSElement(element);
|
|
161
|
+
* console.log(contentlet);
|
|
162
|
+
*/
|
|
163
|
+
function findDotCMSElement(element) {
|
|
164
|
+
if (!element) return null;
|
|
165
|
+
if (element?.dataset?.['dotObject'] === 'contentlet' || element?.dataset?.['dotObject'] === 'container' && element.children.length === 0) {
|
|
166
|
+
return element;
|
|
167
|
+
}
|
|
168
|
+
return findDotCMSElement(element?.['parentElement']);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Find VTL data within a target element.
|
|
172
|
+
*
|
|
173
|
+
* @export
|
|
174
|
+
* @param {HTMLElement} target - The target element to search within.
|
|
175
|
+
* @return {Array<{ inode: string, name: string }> | null} An array of objects containing VTL data or null if none found.
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* const target = document.querySelector('.target-element');
|
|
179
|
+
* const vtlData = findDotCMSVTLData(target);
|
|
180
|
+
* console.log(vtlData);
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
function findDotCMSVTLData(target) {
|
|
184
|
+
const vltElements = target.querySelectorAll('[data-dot-object="vtl-file"]');
|
|
185
|
+
if (!vltElements.length) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
return Array.from(vltElements).map(vltElement => {
|
|
189
|
+
return {
|
|
190
|
+
inode: vltElement.dataset?.['dotInode'],
|
|
191
|
+
name: vltElement.dataset?.['dotUrl']
|
|
192
|
+
};
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Check if the scroll position is at the bottom of the page.
|
|
197
|
+
*
|
|
198
|
+
* @export
|
|
199
|
+
* @return {boolean} True if the scroll position is at the bottom, otherwise false.
|
|
200
|
+
* @example
|
|
201
|
+
* ```ts
|
|
202
|
+
* if (dotCMSScrollIsInBottom()) {
|
|
203
|
+
* console.log('Scrolled to the bottom');
|
|
204
|
+
* }
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
function computeScrollIsInBottom() {
|
|
208
|
+
const documentHeight = document.documentElement.scrollHeight;
|
|
209
|
+
const viewportHeight = window.innerHeight;
|
|
210
|
+
const scrollY = window.scrollY;
|
|
211
|
+
return scrollY + viewportHeight >= documentHeight;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Subscribes to content changes in the UVE editor
|
|
216
|
+
*
|
|
217
|
+
* @param {UVEEventHandler} callback - Function to be called when content changes are detected
|
|
218
|
+
* @returns {Object} Object containing unsubscribe function and event type
|
|
219
|
+
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
220
|
+
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
221
|
+
* @internal
|
|
222
|
+
*/
|
|
223
|
+
function onContentChanges(callback) {
|
|
224
|
+
const messageCallback = event => {
|
|
225
|
+
if (event.data.name === exports.__DOTCMS_UVE_EVENT__.UVE_SET_PAGE_DATA) {
|
|
226
|
+
callback(event.data.payload);
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
window.addEventListener('message', messageCallback);
|
|
230
|
+
return {
|
|
231
|
+
unsubscribe: () => {
|
|
232
|
+
window.removeEventListener('message', messageCallback);
|
|
233
|
+
},
|
|
234
|
+
event: types.UVEEventType.CONTENT_CHANGES
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Subscribes to page reload events in the UVE editor
|
|
239
|
+
*
|
|
240
|
+
* @param {UVEEventHandler} callback - Function to be called when page reload is triggered
|
|
241
|
+
* @returns {Object} Object containing unsubscribe function and event type
|
|
242
|
+
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
243
|
+
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
244
|
+
* @internal
|
|
245
|
+
*/
|
|
246
|
+
function onPageReload(callback) {
|
|
247
|
+
const messageCallback = event => {
|
|
248
|
+
if (event.data.name === exports.__DOTCMS_UVE_EVENT__.UVE_RELOAD_PAGE) {
|
|
249
|
+
callback();
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
window.addEventListener('message', messageCallback);
|
|
253
|
+
return {
|
|
254
|
+
unsubscribe: () => {
|
|
255
|
+
window.removeEventListener('message', messageCallback);
|
|
256
|
+
},
|
|
257
|
+
event: types.UVEEventType.PAGE_RELOAD
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Subscribes to request bounds events in the UVE editor
|
|
262
|
+
*
|
|
263
|
+
* @param {UVEEventHandler} callback - Function to be called when bounds are requested
|
|
264
|
+
* @returns {Object} Object containing unsubscribe function and event type
|
|
265
|
+
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
266
|
+
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
267
|
+
* @internal
|
|
268
|
+
*/
|
|
269
|
+
function onRequestBounds(callback) {
|
|
270
|
+
const messageCallback = event => {
|
|
271
|
+
if (event.data.name === exports.__DOTCMS_UVE_EVENT__.UVE_REQUEST_BOUNDS) {
|
|
272
|
+
const containers = Array.from(document.querySelectorAll('[data-dot-object="container"]'));
|
|
273
|
+
const positionData = getDotCMSPageBounds(containers);
|
|
274
|
+
callback(positionData);
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
window.addEventListener('message', messageCallback);
|
|
278
|
+
return {
|
|
279
|
+
unsubscribe: () => {
|
|
280
|
+
window.removeEventListener('message', messageCallback);
|
|
281
|
+
},
|
|
282
|
+
event: types.UVEEventType.REQUEST_BOUNDS
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Subscribes to iframe scroll events in the UVE editor
|
|
287
|
+
*
|
|
288
|
+
* @param {UVEEventHandler} callback - Function to be called when iframe scroll occurs
|
|
289
|
+
* @returns {Object} Object containing unsubscribe function and event type
|
|
290
|
+
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
291
|
+
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
292
|
+
* @internal
|
|
293
|
+
*/
|
|
294
|
+
function onIframeScroll(callback) {
|
|
295
|
+
const messageCallback = event => {
|
|
296
|
+
if (event.data.name === exports.__DOTCMS_UVE_EVENT__.UVE_SCROLL_INSIDE_IFRAME) {
|
|
297
|
+
const direction = event.data.direction;
|
|
298
|
+
callback(direction);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
window.addEventListener('message', messageCallback);
|
|
302
|
+
return {
|
|
303
|
+
unsubscribe: () => {
|
|
304
|
+
window.removeEventListener('message', messageCallback);
|
|
305
|
+
},
|
|
306
|
+
event: types.UVEEventType.IFRAME_SCROLL
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Subscribes to contentlet hover events in the UVE editor
|
|
311
|
+
*
|
|
312
|
+
* @param {UVEEventHandler} callback - Function to be called when a contentlet is hovered
|
|
313
|
+
* @returns {Object} Object containing unsubscribe function and event type
|
|
314
|
+
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
315
|
+
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
316
|
+
* @internal
|
|
317
|
+
*/
|
|
318
|
+
function onContentletHovered(callback) {
|
|
319
|
+
const pointerMoveCallback = event => {
|
|
320
|
+
const foundElement = findDotCMSElement(event.target);
|
|
321
|
+
if (!foundElement) return;
|
|
322
|
+
const {
|
|
323
|
+
x,
|
|
324
|
+
y,
|
|
325
|
+
width,
|
|
326
|
+
height
|
|
327
|
+
} = foundElement.getBoundingClientRect();
|
|
328
|
+
const isContainer = foundElement.dataset?.['dotObject'] === 'container';
|
|
329
|
+
const contentletForEmptyContainer = {
|
|
330
|
+
identifier: 'TEMP_EMPTY_CONTENTLET',
|
|
331
|
+
title: 'TEMP_EMPTY_CONTENTLET',
|
|
332
|
+
contentType: 'TEMP_EMPTY_CONTENTLET_TYPE',
|
|
333
|
+
inode: 'TEMPY_EMPTY_CONTENTLET_INODE',
|
|
334
|
+
widgetTitle: 'TEMP_EMPTY_CONTENTLET',
|
|
335
|
+
baseType: 'TEMP_EMPTY_CONTENTLET',
|
|
336
|
+
onNumberOfPages: 1
|
|
337
|
+
};
|
|
338
|
+
const contentlet = {
|
|
339
|
+
identifier: foundElement.dataset?.['dotIdentifier'],
|
|
340
|
+
title: foundElement.dataset?.['dotTitle'],
|
|
341
|
+
inode: foundElement.dataset?.['dotInode'],
|
|
342
|
+
contentType: foundElement.dataset?.['dotType'],
|
|
343
|
+
baseType: foundElement.dataset?.['dotBasetype'],
|
|
344
|
+
widgetTitle: foundElement.dataset?.['dotWidgetTitle'],
|
|
345
|
+
onNumberOfPages: foundElement.dataset?.['dotOnNumberOfPages']
|
|
57
346
|
};
|
|
347
|
+
const vtlFiles = findDotCMSVTLData(foundElement);
|
|
348
|
+
const contentletPayload = {
|
|
349
|
+
container:
|
|
350
|
+
// Here extract dot-container from contentlet if it is Headless
|
|
351
|
+
// or search in parent container if it is VTL
|
|
352
|
+
foundElement.dataset?.['dotContainer'] ? JSON.parse(foundElement.dataset?.['dotContainer']) : getClosestDotCMSContainerData(foundElement),
|
|
353
|
+
contentlet: isContainer ? contentletForEmptyContainer : contentlet,
|
|
354
|
+
vtlFiles
|
|
355
|
+
};
|
|
356
|
+
const contentletHoveredPayload = {
|
|
357
|
+
x,
|
|
358
|
+
y,
|
|
359
|
+
width,
|
|
360
|
+
height,
|
|
361
|
+
payload: contentletPayload
|
|
362
|
+
};
|
|
363
|
+
callback(contentletHoveredPayload);
|
|
364
|
+
};
|
|
365
|
+
document.addEventListener('pointermove', pointerMoveCallback);
|
|
366
|
+
return {
|
|
367
|
+
unsubscribe: () => {
|
|
368
|
+
document.removeEventListener('pointermove', pointerMoveCallback);
|
|
369
|
+
},
|
|
370
|
+
event: types.UVEEventType.CONTENTLET_HOVERED
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Events that can be subscribed to in the UVE
|
|
376
|
+
*
|
|
377
|
+
* @internal
|
|
378
|
+
* @type {Record<UVEEventType, UVEEventSubscriber>}
|
|
379
|
+
*/
|
|
380
|
+
const __UVE_EVENTS__ = {
|
|
381
|
+
[types.UVEEventType.CONTENT_CHANGES]: callback => {
|
|
382
|
+
return onContentChanges(callback);
|
|
383
|
+
},
|
|
384
|
+
[types.UVEEventType.PAGE_RELOAD]: callback => {
|
|
385
|
+
return onPageReload(callback);
|
|
386
|
+
},
|
|
387
|
+
[types.UVEEventType.REQUEST_BOUNDS]: callback => {
|
|
388
|
+
return onRequestBounds(callback);
|
|
389
|
+
},
|
|
390
|
+
[types.UVEEventType.IFRAME_SCROLL]: callback => {
|
|
391
|
+
return onIframeScroll(callback);
|
|
392
|
+
},
|
|
393
|
+
[types.UVEEventType.CONTENTLET_HOVERED]: callback => {
|
|
394
|
+
return onContentletHovered(callback);
|
|
58
395
|
}
|
|
59
396
|
};
|
|
60
397
|
/**
|
|
@@ -74,3 +411,10 @@ const __UVE_EVENT_ERROR_FALLBACK__ = event => {
|
|
|
74
411
|
|
|
75
412
|
exports.__UVE_EVENTS__ = __UVE_EVENTS__;
|
|
76
413
|
exports.__UVE_EVENT_ERROR_FALLBACK__ = __UVE_EVENT_ERROR_FALLBACK__;
|
|
414
|
+
exports.computeScrollIsInBottom = computeScrollIsInBottom;
|
|
415
|
+
exports.findDotCMSElement = findDotCMSElement;
|
|
416
|
+
exports.findDotCMSVTLData = findDotCMSVTLData;
|
|
417
|
+
exports.getClosestDotCMSContainerData = getClosestDotCMSContainerData;
|
|
418
|
+
exports.getDotCMSContainerData = getDotCMSContainerData;
|
|
419
|
+
exports.getDotCMSContentletsBound = getDotCMSContentletsBound;
|
|
420
|
+
exports.getDotCMSPageBounds = getDotCMSPageBounds;
|