@dotcms/uve 0.0.1-beta.15 → 0.0.1-beta.17
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/constants.cjs.js +767 -0
- package/constants.esm.js +740 -0
- package/index.cjs.js +8 -81
- package/index.esm.js +4 -76
- package/internal.cjs.js +107 -623
- package/internal.esm.js +78 -603
- package/package.json +1 -1
- package/src/internal.d.ts +2 -0
- package/src/lib/editor/internal.d.ts +16 -1
- package/src/lib/types/block-editor-renderer/internal.d.ts +46 -0
- package/src/lib/types/block-editor-renderer/public.d.ts +38 -0
- package/src/types.d.ts +1 -0
package/internal.cjs.js
CHANGED
|
@@ -1,652 +1,136 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var constants = require('./constants.cjs.js');
|
|
3
4
|
var types = require('./types.cjs.js');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @
|
|
9
|
-
* @
|
|
10
|
-
*/
|
|
11
|
-
exports.__DOTCMS_UVE_EVENT__ = void 0;
|
|
12
|
-
(function (__DOTCMS_UVE_EVENT__) {
|
|
13
|
-
/**
|
|
14
|
-
* Request to page to reload
|
|
15
|
-
*/
|
|
16
|
-
__DOTCMS_UVE_EVENT__["UVE_RELOAD_PAGE"] = "uve-reload-page";
|
|
17
|
-
/**
|
|
18
|
-
* Request the bounds for the elements
|
|
19
|
-
*/
|
|
20
|
-
__DOTCMS_UVE_EVENT__["UVE_REQUEST_BOUNDS"] = "uve-request-bounds";
|
|
21
|
-
/**
|
|
22
|
-
* Received pong from the editor
|
|
23
|
-
*/
|
|
24
|
-
__DOTCMS_UVE_EVENT__["UVE_EDITOR_PONG"] = "uve-editor-pong";
|
|
25
|
-
/**
|
|
26
|
-
* Received scroll event trigger from the editor
|
|
27
|
-
*/
|
|
28
|
-
__DOTCMS_UVE_EVENT__["UVE_SCROLL_INSIDE_IFRAME"] = "uve-scroll-inside-iframe";
|
|
29
|
-
/**
|
|
30
|
-
* TODO:
|
|
31
|
-
* Set the page data - This is used to catch the "changes" event.
|
|
32
|
-
* We must to re-check the name late.
|
|
33
|
-
*/
|
|
34
|
-
__DOTCMS_UVE_EVENT__["UVE_SET_PAGE_DATA"] = "uve-set-page-data";
|
|
35
|
-
/**
|
|
36
|
-
* Copy contentlet inline editing success
|
|
37
|
-
*/
|
|
38
|
-
__DOTCMS_UVE_EVENT__["UVE_COPY_CONTENTLET_INLINE_EDITING_SUCCESS"] = "uve-copy-contentlet-inline-editing-success";
|
|
39
|
-
})(exports.__DOTCMS_UVE_EVENT__ || (exports.__DOTCMS_UVE_EVENT__ = {}));
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Calculates the bounding information for each page element within the given containers.
|
|
43
|
-
*
|
|
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
|
-
* ```
|
|
7
|
+
* Sets the bounds of the containers in the editor.
|
|
8
|
+
* Retrieves the containers from the DOM and sends their position data to the editor.
|
|
9
|
+
* @private
|
|
10
|
+
* @memberof DotCMSPageEditor
|
|
53
11
|
*/
|
|
54
|
-
function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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)
|
|
67
|
-
};
|
|
12
|
+
function setBounds(bounds) {
|
|
13
|
+
constants.sendMessageToUVE({
|
|
14
|
+
action: types.DotCMSUVEAction.SET_BOUNDS,
|
|
15
|
+
payload: bounds
|
|
68
16
|
});
|
|
69
17
|
}
|
|
70
18
|
/**
|
|
71
|
-
*
|
|
19
|
+
* Validates the structure of a Block Editor block.
|
|
20
|
+
*
|
|
21
|
+
* This function checks that:
|
|
22
|
+
* 1. The blocks parameter is a valid object
|
|
23
|
+
* 2. The block has a 'doc' type
|
|
24
|
+
* 3. The block has a valid content array that is not empty
|
|
72
25
|
*
|
|
73
|
-
* @
|
|
74
|
-
* @
|
|
75
|
-
* @
|
|
76
|
-
* @
|
|
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
|
-
* ```
|
|
26
|
+
* @param {Block} blocks - The blocks structure to validate
|
|
27
|
+
* @returns {BlockEditorState} Object containing validation state and any error message
|
|
28
|
+
* @property {boolean} BlockEditorState.isValid - Whether the blocks structure is valid
|
|
29
|
+
* @property {string | null} BlockEditorState.error - Error message if invalid, null if valid
|
|
84
30
|
*/
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const contentletRect = contentlet.getBoundingClientRect();
|
|
31
|
+
const isValidBlocks = blocks => {
|
|
32
|
+
if (!blocks) {
|
|
88
33
|
return {
|
|
89
|
-
|
|
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
|
-
})
|
|
34
|
+
error: `Error: Blocks object is not defined`
|
|
102
35
|
};
|
|
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
36
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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;
|
|
37
|
+
if (typeof blocks !== 'object') {
|
|
38
|
+
return {
|
|
39
|
+
error: `Error: Blocks must be an object, but received: ${typeof blocks}`
|
|
40
|
+
};
|
|
167
41
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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;
|
|
42
|
+
if (blocks.type !== 'doc') {
|
|
43
|
+
return {
|
|
44
|
+
error: `Error: Invalid block type. Expected 'doc' but received: '${blocks.type}'`
|
|
45
|
+
};
|
|
187
46
|
}
|
|
188
|
-
|
|
47
|
+
if (!blocks.content) {
|
|
189
48
|
return {
|
|
190
|
-
|
|
191
|
-
name: vltElement.dataset?.['dotUrl']
|
|
49
|
+
error: 'Error: Blocks content is missing'
|
|
192
50
|
};
|
|
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
|
-
*
|
|
216
|
-
* Combine classes into a single string.
|
|
217
|
-
*
|
|
218
|
-
* @param {string[]} classes
|
|
219
|
-
* @returns {string} Combined classes
|
|
220
|
-
*/
|
|
221
|
-
const combineClasses = classes => classes.filter(Boolean).join(' ');
|
|
222
|
-
/**
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
* Calculates and returns the CSS Grid positioning classes for a column based on its configuration.
|
|
226
|
-
* Uses a 12-column grid system where columns are positioned using grid-column-start and grid-column-end.
|
|
227
|
-
*
|
|
228
|
-
* @example
|
|
229
|
-
* ```typescript
|
|
230
|
-
* const classes = getColumnPositionClasses({
|
|
231
|
-
* leftOffset: 1, // Starts at the first column
|
|
232
|
-
* width: 6 // Spans 6 columns
|
|
233
|
-
* });
|
|
234
|
-
* // Returns: { startClass: 'col-start-1', endClass: 'col-end-7' }
|
|
235
|
-
* ```
|
|
236
|
-
*
|
|
237
|
-
* @param {DotPageAssetLayoutColumn} column - Column configuration object
|
|
238
|
-
* @param {number} column.leftOffset - Starting position (0-based) in the grid
|
|
239
|
-
* @param {number} column.width - Number of columns to span
|
|
240
|
-
* @returns {{ startClass: string, endClass: string }} Object containing CSS class names for grid positioning
|
|
241
|
-
*/
|
|
242
|
-
const getColumnPositionClasses = column => {
|
|
243
|
-
const {
|
|
244
|
-
leftOffset,
|
|
245
|
-
width
|
|
246
|
-
} = column;
|
|
247
|
-
const startClass = `${START_CLASS}${leftOffset}`;
|
|
248
|
-
const endClass = `${END_CLASS}${leftOffset + width}`;
|
|
249
|
-
return {
|
|
250
|
-
startClass,
|
|
251
|
-
endClass
|
|
252
|
-
};
|
|
253
|
-
};
|
|
254
|
-
/**
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
* Helper function that returns an object containing the dotCMS data attributes.
|
|
258
|
-
* @param {DotCMSContentlet} contentlet - The contentlet to get the attributes for
|
|
259
|
-
* @param {string} container - The container to get the attributes for
|
|
260
|
-
* @returns {DotContentletAttributes} The dotCMS data attributes
|
|
261
|
-
*/
|
|
262
|
-
function getDotContentletAttributes(contentlet, container) {
|
|
263
|
-
return {
|
|
264
|
-
'data-dot-identifier': contentlet?.identifier,
|
|
265
|
-
'data-dot-basetype': contentlet?.baseType,
|
|
266
|
-
'data-dot-title': contentlet?.['widgetTitle'] || contentlet?.title,
|
|
267
|
-
'data-dot-inode': contentlet?.inode,
|
|
268
|
-
'data-dot-type': contentlet?.contentType,
|
|
269
|
-
'data-dot-container': container,
|
|
270
|
-
'data-dot-on-number-of-pages': contentlet?.['onNumberOfPages']
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
* Retrieves container data from a DotCMS page asset using the container reference.
|
|
277
|
-
* This function processes the container information and returns a standardized format
|
|
278
|
-
* for container editing.
|
|
279
|
-
*
|
|
280
|
-
* @param {DotCMSPageAsset} dotCMSPageAsset - The page asset containing all containers data
|
|
281
|
-
* @param {DotCMSColumnContainer} columContainer - The container reference from the layout
|
|
282
|
-
* @throws {Error} When page asset is invalid or container is not found
|
|
283
|
-
* @returns {EditableContainerData} Formatted container data for editing
|
|
284
|
-
*
|
|
285
|
-
* @example
|
|
286
|
-
* const containerData = getContainersData(pageAsset, containerRef);
|
|
287
|
-
* // Returns: { uuid: '123', identifier: 'cont1', acceptTypes: 'type1,type2', maxContentlets: 5 }
|
|
288
|
-
*/
|
|
289
|
-
const getContainersData = (dotCMSPageAsset, columContainer) => {
|
|
290
|
-
const {
|
|
291
|
-
identifier,
|
|
292
|
-
uuid
|
|
293
|
-
} = columContainer;
|
|
294
|
-
const dotContainer = dotCMSPageAsset.containers[identifier];
|
|
295
|
-
if (!dotContainer) {
|
|
296
|
-
return null;
|
|
297
51
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
const acceptTypes = containerStructures?.map(structure => structure.contentTypeVar).join(',') ?? '';
|
|
303
|
-
const variantId = container?.parentPermissionable?.variantId;
|
|
304
|
-
const maxContentlets = container?.maxContentlets ?? 0;
|
|
305
|
-
const path = container?.path;
|
|
306
|
-
return {
|
|
307
|
-
uuid,
|
|
308
|
-
variantId,
|
|
309
|
-
acceptTypes,
|
|
310
|
-
maxContentlets,
|
|
311
|
-
identifier: path ?? identifier
|
|
312
|
-
};
|
|
313
|
-
};
|
|
314
|
-
/**
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
* Retrieves the contentlets (content items) associated with a specific container.
|
|
318
|
-
* Handles different UUID formats and provides warning for missing contentlets.
|
|
319
|
-
*
|
|
320
|
-
* @param {DotCMSPageAsset} dotCMSPageAsset - The page asset containing all containers data
|
|
321
|
-
* @param {DotCMSColumnContainer} columContainer - The container reference from the layout
|
|
322
|
-
* @returns {DotCMSContentlet[]} Array of contentlets in the container
|
|
323
|
-
*
|
|
324
|
-
* @example
|
|
325
|
-
* const contentlets = getContentletsInContainer(pageAsset, containerRef);
|
|
326
|
-
* // Returns: [{ identifier: 'cont1', ... }, { identifier: 'cont2', ... }]
|
|
327
|
-
*/
|
|
328
|
-
const getContentletsInContainer = (dotCMSPageAsset, columContainer) => {
|
|
329
|
-
const {
|
|
330
|
-
identifier,
|
|
331
|
-
uuid
|
|
332
|
-
} = columContainer;
|
|
333
|
-
const {
|
|
334
|
-
contentlets
|
|
335
|
-
} = dotCMSPageAsset.containers[identifier];
|
|
336
|
-
const contentletsInContainer = contentlets[`uuid-${uuid}`] || contentlets[`uuid-dotParser_${uuid}`] || [];
|
|
337
|
-
if (!contentletsInContainer) {
|
|
338
|
-
console.warn(`We couldn't find the contentlets for the container with the identifier ${identifier} and the uuid ${uuid} becareful by adding content to this container.\nWe recommend to change the container in the layout and add the content again.`);
|
|
52
|
+
if (!Array.isArray(blocks.content)) {
|
|
53
|
+
return {
|
|
54
|
+
error: `Error: Blocks content must be an array, but received: ${typeof blocks.content}`
|
|
55
|
+
};
|
|
339
56
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
* const attributes = getDotContainerAttributes({
|
|
353
|
-
* uuid: '123',
|
|
354
|
-
* identifier: 'cont1',
|
|
355
|
-
* acceptTypes: 'type1,type2',
|
|
356
|
-
* maxContentlets: 5
|
|
357
|
-
* });
|
|
358
|
-
* // Returns: { 'data-dot-object': 'container', 'data-dot-identifier': 'cont1', ... }
|
|
359
|
-
*/
|
|
360
|
-
function getDotContainerAttributes({
|
|
361
|
-
uuid,
|
|
362
|
-
identifier,
|
|
363
|
-
acceptTypes,
|
|
364
|
-
maxContentlets
|
|
365
|
-
}) {
|
|
366
|
-
return {
|
|
367
|
-
'data-dot-object': 'container',
|
|
368
|
-
'data-dot-accept-types': acceptTypes,
|
|
369
|
-
'data-dot-identifier': identifier,
|
|
370
|
-
'data-max-contentlets': maxContentlets.toString(),
|
|
371
|
-
'data-dot-uuid': uuid
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* Subscribes to content changes in the UVE editor
|
|
377
|
-
*
|
|
378
|
-
* @param {UVEEventHandler} callback - Function to be called when content changes are detected
|
|
379
|
-
* @returns {Object} Object containing unsubscribe function and event type
|
|
380
|
-
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
381
|
-
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
382
|
-
* @internal
|
|
383
|
-
*/
|
|
384
|
-
function onContentChanges(callback) {
|
|
385
|
-
const messageCallback = event => {
|
|
386
|
-
if (event.data.name === exports.__DOTCMS_UVE_EVENT__.UVE_SET_PAGE_DATA) {
|
|
387
|
-
callback(event.data.payload);
|
|
57
|
+
if (blocks.content.length === 0) {
|
|
58
|
+
return {
|
|
59
|
+
error: 'Error: Blocks content is empty. At least one block is required.'
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// Validate each block in the content array
|
|
63
|
+
for (let i = 0; i < blocks.content.length; i++) {
|
|
64
|
+
const block = blocks.content[i];
|
|
65
|
+
if (!block.type) {
|
|
66
|
+
return {
|
|
67
|
+
error: `Error: Block at index ${i} is missing required 'type' property`
|
|
68
|
+
};
|
|
388
69
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
window.removeEventListener('message', messageCallback);
|
|
394
|
-
},
|
|
395
|
-
event: types.UVEEventType.CONTENT_CHANGES
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Subscribes to page reload events in the UVE editor
|
|
400
|
-
*
|
|
401
|
-
* @param {UVEEventHandler} callback - Function to be called when page reload is triggered
|
|
402
|
-
* @returns {Object} Object containing unsubscribe function and event type
|
|
403
|
-
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
404
|
-
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
405
|
-
* @internal
|
|
406
|
-
*/
|
|
407
|
-
function onPageReload(callback) {
|
|
408
|
-
const messageCallback = event => {
|
|
409
|
-
if (event.data.name === exports.__DOTCMS_UVE_EVENT__.UVE_RELOAD_PAGE) {
|
|
410
|
-
callback();
|
|
70
|
+
if (typeof block.type !== 'string') {
|
|
71
|
+
return {
|
|
72
|
+
error: `Error: Block type at index ${i} must be a string, but received: ${typeof block.type}`
|
|
73
|
+
};
|
|
411
74
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
},
|
|
418
|
-
event: types.UVEEventType.PAGE_RELOAD
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
/**
|
|
422
|
-
* Subscribes to request bounds events in the UVE editor
|
|
423
|
-
*
|
|
424
|
-
* @param {UVEEventHandler} callback - Function to be called when bounds are requested
|
|
425
|
-
* @returns {Object} Object containing unsubscribe function and event type
|
|
426
|
-
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
427
|
-
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
428
|
-
* @internal
|
|
429
|
-
*/
|
|
430
|
-
function onRequestBounds(callback) {
|
|
431
|
-
const messageCallback = event => {
|
|
432
|
-
if (event.data.name === exports.__DOTCMS_UVE_EVENT__.UVE_REQUEST_BOUNDS) {
|
|
433
|
-
const containers = Array.from(document.querySelectorAll('[data-dot-object="container"]'));
|
|
434
|
-
const positionData = getDotCMSPageBounds(containers);
|
|
435
|
-
callback(positionData);
|
|
75
|
+
// Validate block attributes if present
|
|
76
|
+
if (block.attrs && typeof block.attrs !== 'object') {
|
|
77
|
+
return {
|
|
78
|
+
error: `Error: Block attributes at index ${i} must be an object, but received: ${typeof block.attrs}`
|
|
79
|
+
};
|
|
436
80
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
*/
|
|
455
|
-
function onIframeScroll(callback) {
|
|
456
|
-
const messageCallback = event => {
|
|
457
|
-
if (event.data.name === exports.__DOTCMS_UVE_EVENT__.UVE_SCROLL_INSIDE_IFRAME) {
|
|
458
|
-
const direction = event.data.direction;
|
|
459
|
-
callback(direction);
|
|
81
|
+
// Validate nested content if present
|
|
82
|
+
if (block.content) {
|
|
83
|
+
if (!Array.isArray(block.content)) {
|
|
84
|
+
return {
|
|
85
|
+
error: `Error: Block content at index ${i} must be an array, but received: ${typeof block.content}`
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// Recursively validate nested blocks
|
|
89
|
+
const nestedValidation = isValidBlocks({
|
|
90
|
+
type: 'doc',
|
|
91
|
+
content: block.content
|
|
92
|
+
});
|
|
93
|
+
if (nestedValidation.error) {
|
|
94
|
+
return {
|
|
95
|
+
error: `Error in nested block at index ${i}: ${nestedValidation.error}`
|
|
96
|
+
};
|
|
97
|
+
}
|
|
460
98
|
}
|
|
461
|
-
};
|
|
462
|
-
window.addEventListener('message', messageCallback);
|
|
463
|
-
return {
|
|
464
|
-
unsubscribe: () => {
|
|
465
|
-
window.removeEventListener('message', messageCallback);
|
|
466
|
-
},
|
|
467
|
-
event: types.UVEEventType.IFRAME_SCROLL
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* Subscribes to contentlet hover events in the UVE editor
|
|
472
|
-
*
|
|
473
|
-
* @param {UVEEventHandler} callback - Function to be called when a contentlet is hovered
|
|
474
|
-
* @returns {Object} Object containing unsubscribe function and event type
|
|
475
|
-
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
476
|
-
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
477
|
-
* @internal
|
|
478
|
-
*/
|
|
479
|
-
function onContentletHovered(callback) {
|
|
480
|
-
const pointerMoveCallback = event => {
|
|
481
|
-
const foundElement = findDotCMSElement(event.target);
|
|
482
|
-
if (!foundElement) return;
|
|
483
|
-
const {
|
|
484
|
-
x,
|
|
485
|
-
y,
|
|
486
|
-
width,
|
|
487
|
-
height
|
|
488
|
-
} = foundElement.getBoundingClientRect();
|
|
489
|
-
const isContainer = foundElement.dataset?.['dotObject'] === 'container';
|
|
490
|
-
const contentletForEmptyContainer = {
|
|
491
|
-
identifier: 'TEMP_EMPTY_CONTENTLET',
|
|
492
|
-
title: 'TEMP_EMPTY_CONTENTLET',
|
|
493
|
-
contentType: 'TEMP_EMPTY_CONTENTLET_TYPE',
|
|
494
|
-
inode: 'TEMPY_EMPTY_CONTENTLET_INODE',
|
|
495
|
-
widgetTitle: 'TEMP_EMPTY_CONTENTLET',
|
|
496
|
-
baseType: 'TEMP_EMPTY_CONTENTLET',
|
|
497
|
-
onNumberOfPages: 1
|
|
498
|
-
};
|
|
499
|
-
const contentlet = {
|
|
500
|
-
identifier: foundElement.dataset?.['dotIdentifier'],
|
|
501
|
-
title: foundElement.dataset?.['dotTitle'],
|
|
502
|
-
inode: foundElement.dataset?.['dotInode'],
|
|
503
|
-
contentType: foundElement.dataset?.['dotType'],
|
|
504
|
-
baseType: foundElement.dataset?.['dotBasetype'],
|
|
505
|
-
widgetTitle: foundElement.dataset?.['dotWidgetTitle'],
|
|
506
|
-
onNumberOfPages: foundElement.dataset?.['dotOnNumberOfPages']
|
|
507
|
-
};
|
|
508
|
-
const vtlFiles = findDotCMSVTLData(foundElement);
|
|
509
|
-
const contentletPayload = {
|
|
510
|
-
container:
|
|
511
|
-
// Here extract dot-container from contentlet if it is Headless
|
|
512
|
-
// or search in parent container if it is VTL
|
|
513
|
-
foundElement.dataset?.['dotContainer'] ? JSON.parse(foundElement.dataset?.['dotContainer']) : getClosestDotCMSContainerData(foundElement),
|
|
514
|
-
contentlet: isContainer ? contentletForEmptyContainer : contentlet,
|
|
515
|
-
vtlFiles
|
|
516
|
-
};
|
|
517
|
-
const contentletHoveredPayload = {
|
|
518
|
-
x,
|
|
519
|
-
y,
|
|
520
|
-
width,
|
|
521
|
-
height,
|
|
522
|
-
payload: contentletPayload
|
|
523
|
-
};
|
|
524
|
-
callback(contentletHoveredPayload);
|
|
525
|
-
};
|
|
526
|
-
document.addEventListener('pointermove', pointerMoveCallback);
|
|
527
|
-
return {
|
|
528
|
-
unsubscribe: () => {
|
|
529
|
-
document.removeEventListener('pointermove', pointerMoveCallback);
|
|
530
|
-
},
|
|
531
|
-
event: types.UVEEventType.CONTENTLET_HOVERED
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
/**
|
|
536
|
-
* Events that can be subscribed to in the UVE
|
|
537
|
-
*
|
|
538
|
-
* @internal
|
|
539
|
-
* @type {Record<UVEEventType, UVEEventSubscriber>}
|
|
540
|
-
*/
|
|
541
|
-
const __UVE_EVENTS__ = {
|
|
542
|
-
[types.UVEEventType.CONTENT_CHANGES]: callback => {
|
|
543
|
-
return onContentChanges(callback);
|
|
544
|
-
},
|
|
545
|
-
[types.UVEEventType.PAGE_RELOAD]: callback => {
|
|
546
|
-
return onPageReload(callback);
|
|
547
|
-
},
|
|
548
|
-
[types.UVEEventType.REQUEST_BOUNDS]: callback => {
|
|
549
|
-
return onRequestBounds(callback);
|
|
550
|
-
},
|
|
551
|
-
[types.UVEEventType.IFRAME_SCROLL]: callback => {
|
|
552
|
-
return onIframeScroll(callback);
|
|
553
|
-
},
|
|
554
|
-
[types.UVEEventType.CONTENTLET_HOVERED]: callback => {
|
|
555
|
-
return onContentletHovered(callback);
|
|
556
99
|
}
|
|
557
|
-
};
|
|
558
|
-
/**
|
|
559
|
-
* Default UVE event
|
|
560
|
-
*
|
|
561
|
-
* @param {string} event - The event to subscribe to.
|
|
562
|
-
* @internal
|
|
563
|
-
*/
|
|
564
|
-
const __UVE_EVENT_ERROR_FALLBACK__ = event => {
|
|
565
100
|
return {
|
|
566
|
-
|
|
567
|
-
/* do nothing */
|
|
568
|
-
},
|
|
569
|
-
event
|
|
101
|
+
error: null
|
|
570
102
|
};
|
|
571
103
|
};
|
|
572
|
-
/**
|
|
573
|
-
* Development mode
|
|
574
|
-
*
|
|
575
|
-
* @internal
|
|
576
|
-
*/
|
|
577
|
-
const DEVELOPMENT_MODE = 'development';
|
|
578
|
-
/**
|
|
579
|
-
* Production mode
|
|
580
|
-
*
|
|
581
|
-
* @internal
|
|
582
|
-
*/
|
|
583
|
-
const PRODUCTION_MODE = 'production';
|
|
584
|
-
/**
|
|
585
|
-
* End class
|
|
586
|
-
*
|
|
587
|
-
* @internal
|
|
588
|
-
*/
|
|
589
|
-
const END_CLASS = 'col-end-';
|
|
590
|
-
/**
|
|
591
|
-
* Start class
|
|
592
|
-
*
|
|
593
|
-
* @internal
|
|
594
|
-
*/
|
|
595
|
-
const START_CLASS = 'col-start-';
|
|
596
|
-
/**
|
|
597
|
-
* Empty container style for React
|
|
598
|
-
*
|
|
599
|
-
* @internal
|
|
600
|
-
*/
|
|
601
|
-
const EMPTY_CONTAINER_STYLE_REACT = {
|
|
602
|
-
width: '100%',
|
|
603
|
-
backgroundColor: '#ECF0FD',
|
|
604
|
-
display: 'flex',
|
|
605
|
-
justifyContent: 'center',
|
|
606
|
-
alignItems: 'center',
|
|
607
|
-
color: '#030E32',
|
|
608
|
-
height: '10rem'
|
|
609
|
-
};
|
|
610
|
-
/**
|
|
611
|
-
* Empty container style for Angular
|
|
612
|
-
*
|
|
613
|
-
* @internal
|
|
614
|
-
*/
|
|
615
|
-
const EMPTY_CONTAINER_STYLE_ANGULAR = {
|
|
616
|
-
width: '100%',
|
|
617
|
-
'background-color': '#ECF0FD',
|
|
618
|
-
display: 'flex',
|
|
619
|
-
'justify-content': 'center',
|
|
620
|
-
'align-items': 'center',
|
|
621
|
-
color: '#030E32',
|
|
622
|
-
height: '10rem'
|
|
623
|
-
};
|
|
624
|
-
/**
|
|
625
|
-
* Custom no component
|
|
626
|
-
*
|
|
627
|
-
* @internal
|
|
628
|
-
*/
|
|
629
|
-
const CUSTOM_NO_COMPONENT = 'CustomNoComponent';
|
|
630
104
|
|
|
631
|
-
exports
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
exports.
|
|
636
|
-
exports.
|
|
637
|
-
exports.
|
|
638
|
-
exports.
|
|
639
|
-
exports.
|
|
640
|
-
exports.
|
|
641
|
-
exports.
|
|
642
|
-
exports
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
exports.
|
|
647
|
-
exports.
|
|
648
|
-
exports.
|
|
649
|
-
exports.
|
|
650
|
-
exports.
|
|
651
|
-
exports.
|
|
652
|
-
exports.
|
|
105
|
+
Object.defineProperty(exports, "Blocks", {
|
|
106
|
+
enumerable: true,
|
|
107
|
+
get: function () { return constants.Blocks; }
|
|
108
|
+
});
|
|
109
|
+
exports.CUSTOM_NO_COMPONENT = constants.CUSTOM_NO_COMPONENT;
|
|
110
|
+
exports.DEVELOPMENT_MODE = constants.DEVELOPMENT_MODE;
|
|
111
|
+
exports.EMPTY_CONTAINER_STYLE_ANGULAR = constants.EMPTY_CONTAINER_STYLE_ANGULAR;
|
|
112
|
+
exports.EMPTY_CONTAINER_STYLE_REACT = constants.EMPTY_CONTAINER_STYLE_REACT;
|
|
113
|
+
exports.END_CLASS = constants.END_CLASS;
|
|
114
|
+
exports.PRODUCTION_MODE = constants.PRODUCTION_MODE;
|
|
115
|
+
exports.START_CLASS = constants.START_CLASS;
|
|
116
|
+
Object.defineProperty(exports, "__DOTCMS_UVE_EVENT__", {
|
|
117
|
+
enumerable: true,
|
|
118
|
+
get: function () { return constants.__DOTCMS_UVE_EVENT__; }
|
|
119
|
+
});
|
|
120
|
+
exports.__UVE_EVENTS__ = constants.__UVE_EVENTS__;
|
|
121
|
+
exports.__UVE_EVENT_ERROR_FALLBACK__ = constants.__UVE_EVENT_ERROR_FALLBACK__;
|
|
122
|
+
exports.combineClasses = constants.combineClasses;
|
|
123
|
+
exports.computeScrollIsInBottom = constants.computeScrollIsInBottom;
|
|
124
|
+
exports.findDotCMSElement = constants.findDotCMSElement;
|
|
125
|
+
exports.findDotCMSVTLData = constants.findDotCMSVTLData;
|
|
126
|
+
exports.getClosestDotCMSContainerData = constants.getClosestDotCMSContainerData;
|
|
127
|
+
exports.getColumnPositionClasses = constants.getColumnPositionClasses;
|
|
128
|
+
exports.getContainersData = constants.getContainersData;
|
|
129
|
+
exports.getContentletsInContainer = constants.getContentletsInContainer;
|
|
130
|
+
exports.getDotCMSContainerData = constants.getDotCMSContainerData;
|
|
131
|
+
exports.getDotCMSContentletsBound = constants.getDotCMSContentletsBound;
|
|
132
|
+
exports.getDotCMSPageBounds = constants.getDotCMSPageBounds;
|
|
133
|
+
exports.getDotContainerAttributes = constants.getDotContainerAttributes;
|
|
134
|
+
exports.getDotContentletAttributes = constants.getDotContentletAttributes;
|
|
135
|
+
exports.isValidBlocks = isValidBlocks;
|
|
136
|
+
exports.setBounds = setBounds;
|