@dotcms/uve 0.0.1-beta.24 → 0.0.1-beta.26
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 +10 -9
- package/index.esm.js +3 -2
- package/internal.cjs.js +99 -35
- package/internal.esm.js +75 -2
- package/package.json +4 -10
- package/{index.cjs2.js → public.cjs.js} +504 -577
- package/{index.esm2.js → public.esm.js} +506 -579
- package/src/internal/constants.d.ts +1 -1
- package/src/internal/events.d.ts +1 -1
- package/src/internal/index.d.ts +1 -0
- package/src/internal/tinymce.config.d.ts +45 -0
- package/src/internal.d.ts +0 -3
- package/src/lib/core/core.utils.d.ts +1 -1
- package/src/lib/dom/dom.utils.d.ts +6 -7
- package/src/lib/editor/internal.d.ts +3 -3
- package/src/lib/editor/public.d.ts +2 -3
- package/src/script/utils.d.ts +2 -2
- package/src/lib/types/block-editor-renderer/internal.d.ts +0 -46
- package/src/lib/types/block-editor-renderer/public.d.ts +0 -38
- package/src/lib/types/editor/internal.d.ts +0 -119
- package/src/lib/types/editor/public.d.ts +0 -273
- package/src/lib/types/events/internal.d.ts +0 -34
- package/src/lib/types/events/public.d.ts +0 -18
- package/src/lib/types/page/public.d.ts +0 -485
- package/src/types.d.ts +0 -4
- package/types.cjs.d.ts +0 -1
- package/types.cjs.default.js +0 -1
- package/types.cjs.js +0 -111
- package/types.cjs.mjs +0 -2
- package/types.esm.d.ts +0 -1
- package/types.esm.js +0 -111
|
@@ -1,40 +1,5 @@
|
|
|
1
|
-
import { UVEEventType,
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Actions received from the dotcms editor
|
|
5
|
-
*
|
|
6
|
-
* @export
|
|
7
|
-
* @enum {number}
|
|
8
|
-
*/
|
|
9
|
-
var __DOTCMS_UVE_EVENT__;
|
|
10
|
-
(function (__DOTCMS_UVE_EVENT__) {
|
|
11
|
-
/**
|
|
12
|
-
* Request to page to reload
|
|
13
|
-
*/
|
|
14
|
-
__DOTCMS_UVE_EVENT__["UVE_RELOAD_PAGE"] = "uve-reload-page";
|
|
15
|
-
/**
|
|
16
|
-
* Request the bounds for the elements
|
|
17
|
-
*/
|
|
18
|
-
__DOTCMS_UVE_EVENT__["UVE_REQUEST_BOUNDS"] = "uve-request-bounds";
|
|
19
|
-
/**
|
|
20
|
-
* Received pong from the editor
|
|
21
|
-
*/
|
|
22
|
-
__DOTCMS_UVE_EVENT__["UVE_EDITOR_PONG"] = "uve-editor-pong";
|
|
23
|
-
/**
|
|
24
|
-
* Received scroll event trigger from the editor
|
|
25
|
-
*/
|
|
26
|
-
__DOTCMS_UVE_EVENT__["UVE_SCROLL_INSIDE_IFRAME"] = "uve-scroll-inside-iframe";
|
|
27
|
-
/**
|
|
28
|
-
* TODO:
|
|
29
|
-
* Set the page data - This is used to catch the "changes" event.
|
|
30
|
-
* We must to re-check the name late.
|
|
31
|
-
*/
|
|
32
|
-
__DOTCMS_UVE_EVENT__["UVE_SET_PAGE_DATA"] = "uve-set-page-data";
|
|
33
|
-
/**
|
|
34
|
-
* Copy contentlet inline editing success
|
|
35
|
-
*/
|
|
36
|
-
__DOTCMS_UVE_EVENT__["UVE_COPY_CONTENTLET_INLINE_EDITING_SUCCESS"] = "uve-copy-contentlet-inline-editing-success";
|
|
37
|
-
})(__DOTCMS_UVE_EVENT__ || (__DOTCMS_UVE_EVENT__ = {}));
|
|
1
|
+
import { UVEEventType, UVE_MODE, DotCMSUVEAction } from '@dotcms/types';
|
|
2
|
+
import { __DOTCMS_UVE_EVENT__ } from '@dotcms/types/internal';
|
|
38
3
|
|
|
39
4
|
/**
|
|
40
5
|
* Calculates the bounding information for each page element within the given containers.
|
|
@@ -253,7 +218,7 @@ const getColumnPositionClasses = column => {
|
|
|
253
218
|
*
|
|
254
219
|
*
|
|
255
220
|
* Helper function that returns an object containing the dotCMS data attributes.
|
|
256
|
-
* @param {
|
|
221
|
+
* @param {DotCMSBasicContentlet} contentlet - The contentlet to get the attributes for
|
|
257
222
|
* @param {string} container - The container to get the attributes for
|
|
258
223
|
* @returns {DotContentletAttributes} The dotCMS data attributes
|
|
259
224
|
*/
|
|
@@ -265,7 +230,7 @@ function getDotContentletAttributes(contentlet, container) {
|
|
|
265
230
|
'data-dot-inode': contentlet?.inode,
|
|
266
231
|
'data-dot-type': contentlet?.contentType,
|
|
267
232
|
'data-dot-container': container,
|
|
268
|
-
'data-dot-on-number-of-pages': contentlet?.['onNumberOfPages']
|
|
233
|
+
'data-dot-on-number-of-pages': contentlet?.['onNumberOfPages'] || '1'
|
|
269
234
|
};
|
|
270
235
|
}
|
|
271
236
|
/**
|
|
@@ -317,7 +282,7 @@ const getContainersData = (dotCMSPageAsset, columContainer) => {
|
|
|
317
282
|
*
|
|
318
283
|
* @param {DotCMSPageAsset} dotCMSPageAsset - The page asset containing all containers data
|
|
319
284
|
* @param {DotCMSColumnContainer} columContainer - The container reference from the layout
|
|
320
|
-
* @returns {
|
|
285
|
+
* @returns {DotCMSBasicContentlet[]} Array of contentlets in the container
|
|
321
286
|
*
|
|
322
287
|
* @example
|
|
323
288
|
* const contentlets = getContentletsInContainer(pageAsset, containerRef);
|
|
@@ -370,274 +335,345 @@ function getDotContainerAttributes({
|
|
|
370
335
|
};
|
|
371
336
|
}
|
|
372
337
|
|
|
373
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
374
338
|
/**
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
* to
|
|
339
|
+
* Subscribes to content changes in the UVE editor
|
|
340
|
+
*
|
|
341
|
+
* @param {UVEEventHandler} callback - Function to be called when content changes are detected
|
|
342
|
+
* @returns {Object} Object containing unsubscribe function and event type
|
|
343
|
+
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
344
|
+
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
345
|
+
* @internal
|
|
378
346
|
*/
|
|
379
|
-
function
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
384
|
-
};
|
|
385
|
-
const scrollEndCallback = () => {
|
|
386
|
-
sendMessageToUVE({
|
|
387
|
-
action: DotCMSUVEAction.IFRAME_SCROLL_END
|
|
388
|
-
});
|
|
347
|
+
function onContentChanges(callback) {
|
|
348
|
+
const messageCallback = event => {
|
|
349
|
+
if (event.data.name === __DOTCMS_UVE_EVENT__.UVE_SET_PAGE_DATA) {
|
|
350
|
+
callback(event.data.payload);
|
|
351
|
+
}
|
|
389
352
|
};
|
|
390
|
-
window.addEventListener('
|
|
391
|
-
window.addEventListener('scrollend', scrollEndCallback);
|
|
353
|
+
window.addEventListener('message', messageCallback);
|
|
392
354
|
return {
|
|
393
|
-
|
|
394
|
-
window.removeEventListener('
|
|
395
|
-
|
|
396
|
-
|
|
355
|
+
unsubscribe: () => {
|
|
356
|
+
window.removeEventListener('message', messageCallback);
|
|
357
|
+
},
|
|
358
|
+
event: UVEEventType.CONTENT_CHANGES
|
|
397
359
|
};
|
|
398
360
|
}
|
|
399
361
|
/**
|
|
400
|
-
*
|
|
401
|
-
* This helps identify and style empty contentlets in the editor view.
|
|
362
|
+
* Subscribes to page reload events in the UVE editor
|
|
402
363
|
*
|
|
403
|
-
* @
|
|
404
|
-
*
|
|
405
|
-
*
|
|
406
|
-
*
|
|
364
|
+
* @param {UVEEventHandler} callback - Function to be called when page reload is triggered
|
|
365
|
+
* @returns {Object} Object containing unsubscribe function and event type
|
|
366
|
+
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
367
|
+
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
368
|
+
* @internal
|
|
407
369
|
*/
|
|
408
|
-
function
|
|
409
|
-
const
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
return;
|
|
370
|
+
function onPageReload(callback) {
|
|
371
|
+
const messageCallback = event => {
|
|
372
|
+
if (event.data.name === __DOTCMS_UVE_EVENT__.UVE_RELOAD_PAGE) {
|
|
373
|
+
callback();
|
|
413
374
|
}
|
|
414
|
-
|
|
415
|
-
|
|
375
|
+
};
|
|
376
|
+
window.addEventListener('message', messageCallback);
|
|
377
|
+
return {
|
|
378
|
+
unsubscribe: () => {
|
|
379
|
+
window.removeEventListener('message', messageCallback);
|
|
380
|
+
},
|
|
381
|
+
event: UVEEventType.PAGE_RELOAD
|
|
382
|
+
};
|
|
416
383
|
}
|
|
417
384
|
/**
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
* This function sets up subscriptions for:
|
|
421
|
-
* - Page reload events that refresh the window
|
|
422
|
-
* - Bounds request events to update editor boundaries
|
|
423
|
-
* - Iframe scroll events to handle smooth scrolling within bounds
|
|
424
|
-
* - Contentlet hover events to notify the editor
|
|
385
|
+
* Subscribes to request bounds events in the UVE editor
|
|
425
386
|
*
|
|
426
|
-
* @
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
387
|
+
* @param {UVEEventHandler} callback - Function to be called when bounds are requested
|
|
388
|
+
* @returns {Object} Object containing unsubscribe function and event type
|
|
389
|
+
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
390
|
+
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
391
|
+
* @internal
|
|
430
392
|
*/
|
|
431
|
-
function
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
});
|
|
438
|
-
const iframeScrollSubscription = createUVESubscription(UVEEventType.IFRAME_SCROLL, direction => {
|
|
439
|
-
if (window.scrollY === 0 && direction === 'up' || computeScrollIsInBottom() && direction === 'down') {
|
|
440
|
-
// If the iframe scroll is at the top or bottom, do not send anything.
|
|
441
|
-
// This avoids losing the scrollend event.
|
|
442
|
-
return;
|
|
393
|
+
function onRequestBounds(callback) {
|
|
394
|
+
const messageCallback = event => {
|
|
395
|
+
if (event.data.name === __DOTCMS_UVE_EVENT__.UVE_REQUEST_BOUNDS) {
|
|
396
|
+
const containers = Array.from(document.querySelectorAll('[data-dot-object="container"]'));
|
|
397
|
+
const positionData = getDotCMSPageBounds(containers);
|
|
398
|
+
callback(positionData);
|
|
443
399
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
left: 0,
|
|
447
|
-
top: scrollY,
|
|
448
|
-
behavior: 'smooth'
|
|
449
|
-
});
|
|
450
|
-
});
|
|
451
|
-
const contentletHoveredSubscription = createUVESubscription(UVEEventType.CONTENTLET_HOVERED, contentletHovered => {
|
|
452
|
-
sendMessageToUVE({
|
|
453
|
-
action: DotCMSUVEAction.SET_CONTENTLET,
|
|
454
|
-
payload: contentletHovered
|
|
455
|
-
});
|
|
456
|
-
});
|
|
400
|
+
};
|
|
401
|
+
window.addEventListener('message', messageCallback);
|
|
457
402
|
return {
|
|
458
|
-
|
|
403
|
+
unsubscribe: () => {
|
|
404
|
+
window.removeEventListener('message', messageCallback);
|
|
405
|
+
},
|
|
406
|
+
event: UVEEventType.REQUEST_BOUNDS
|
|
459
407
|
};
|
|
460
408
|
}
|
|
461
409
|
/**
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
* This function sends a message to the editor indicating that the client-side
|
|
465
|
-
* initialization is complete and it's ready to handle editor interactions.
|
|
410
|
+
* Subscribes to iframe scroll events in the UVE editor
|
|
466
411
|
*
|
|
467
|
-
* @
|
|
468
|
-
*
|
|
469
|
-
*
|
|
412
|
+
* @param {UVEEventHandler} callback - Function to be called when iframe scroll occurs
|
|
413
|
+
* @returns {Object} Object containing unsubscribe function and event type
|
|
414
|
+
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
415
|
+
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
416
|
+
* @internal
|
|
470
417
|
*/
|
|
471
|
-
function
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
418
|
+
function onIframeScroll(callback) {
|
|
419
|
+
const messageCallback = event => {
|
|
420
|
+
if (event.data.name === __DOTCMS_UVE_EVENT__.UVE_SCROLL_INSIDE_IFRAME) {
|
|
421
|
+
const direction = event.data.direction;
|
|
422
|
+
callback(direction);
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
window.addEventListener('message', messageCallback);
|
|
426
|
+
return {
|
|
427
|
+
unsubscribe: () => {
|
|
428
|
+
window.removeEventListener('message', messageCallback);
|
|
429
|
+
},
|
|
430
|
+
event: UVEEventType.IFRAME_SCROLL
|
|
431
|
+
};
|
|
476
432
|
}
|
|
477
433
|
/**
|
|
478
|
-
*
|
|
434
|
+
* Subscribes to contentlet hover events in the UVE editor
|
|
435
|
+
*
|
|
436
|
+
* @param {UVEEventHandler} callback - Function to be called when a contentlet is hovered
|
|
437
|
+
* @returns {Object} Object containing unsubscribe function and event type
|
|
438
|
+
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
439
|
+
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
440
|
+
* @internal
|
|
479
441
|
*/
|
|
480
|
-
function
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
442
|
+
function onContentletHovered(callback) {
|
|
443
|
+
const pointerMoveCallback = event => {
|
|
444
|
+
const foundElement = findDotCMSElement(event.target);
|
|
445
|
+
if (!foundElement) return;
|
|
446
|
+
const {
|
|
447
|
+
x,
|
|
448
|
+
y,
|
|
449
|
+
width,
|
|
450
|
+
height
|
|
451
|
+
} = foundElement.getBoundingClientRect();
|
|
452
|
+
const isContainer = foundElement.dataset?.['dotObject'] === 'container';
|
|
453
|
+
const contentletForEmptyContainer = {
|
|
454
|
+
identifier: 'TEMP_EMPTY_CONTENTLET',
|
|
455
|
+
title: 'TEMP_EMPTY_CONTENTLET',
|
|
456
|
+
contentType: 'TEMP_EMPTY_CONTENTLET_TYPE',
|
|
457
|
+
inode: 'TEMPY_EMPTY_CONTENTLET_INODE',
|
|
458
|
+
widgetTitle: 'TEMP_EMPTY_CONTENTLET',
|
|
459
|
+
baseType: 'TEMP_EMPTY_CONTENTLET',
|
|
460
|
+
onNumberOfPages: 1
|
|
488
461
|
};
|
|
489
|
-
|
|
490
|
-
|
|
462
|
+
const contentlet = {
|
|
463
|
+
identifier: foundElement.dataset?.['dotIdentifier'],
|
|
464
|
+
title: foundElement.dataset?.['dotTitle'],
|
|
465
|
+
inode: foundElement.dataset?.['dotInode'],
|
|
466
|
+
contentType: foundElement.dataset?.['dotType'],
|
|
467
|
+
baseType: foundElement.dataset?.['dotBasetype'],
|
|
468
|
+
widgetTitle: foundElement.dataset?.['dotWidgetTitle'],
|
|
469
|
+
onNumberOfPages: foundElement.dataset?.['dotOnNumberOfPages']
|
|
470
|
+
};
|
|
471
|
+
const vtlFiles = findDotCMSVTLData(foundElement);
|
|
472
|
+
const contentletPayload = {
|
|
473
|
+
container:
|
|
474
|
+
// Here extract dot-container from contentlet if it is Headless
|
|
475
|
+
// or search in parent container if it is VTL
|
|
476
|
+
foundElement.dataset?.['dotContainer'] ? JSON.parse(foundElement.dataset?.['dotContainer']) : getClosestDotCMSContainerData(foundElement),
|
|
477
|
+
contentlet: isContainer ? contentletForEmptyContainer : contentlet,
|
|
478
|
+
vtlFiles
|
|
479
|
+
};
|
|
480
|
+
const contentletHoveredPayload = {
|
|
481
|
+
x,
|
|
482
|
+
y,
|
|
483
|
+
width,
|
|
484
|
+
height,
|
|
485
|
+
payload: contentletPayload
|
|
486
|
+
};
|
|
487
|
+
callback(contentletHoveredPayload);
|
|
488
|
+
};
|
|
489
|
+
document.addEventListener('pointermove', pointerMoveCallback);
|
|
491
490
|
return {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
}
|
|
491
|
+
unsubscribe: () => {
|
|
492
|
+
document.removeEventListener('pointermove', pointerMoveCallback);
|
|
493
|
+
},
|
|
494
|
+
event: UVEEventType.CONTENTLET_HOVERED
|
|
495
495
|
};
|
|
496
496
|
}
|
|
497
|
-
const listenBlockEditorClick = () => {
|
|
498
|
-
const editBlockEditorNodes = document.querySelectorAll('[data-block-editor-content]');
|
|
499
|
-
if (!editBlockEditorNodes.length) {
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
editBlockEditorNodes.forEach(node => {
|
|
503
|
-
const {
|
|
504
|
-
inode,
|
|
505
|
-
language = '1',
|
|
506
|
-
contentType,
|
|
507
|
-
fieldName,
|
|
508
|
-
blockEditorContent
|
|
509
|
-
} = node.dataset;
|
|
510
|
-
const content = JSON.parse(blockEditorContent || '');
|
|
511
|
-
if (!inode || !language || !contentType || !fieldName) {
|
|
512
|
-
console.error('Missing data attributes for block editor inline editing.');
|
|
513
|
-
console.warn('inode, language, contentType and fieldName are required.');
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
node.classList.add('dotcms__inline-edit-field');
|
|
517
|
-
node.addEventListener('click', () => {
|
|
518
|
-
initInlineEditing('BLOCK_EDITOR', {
|
|
519
|
-
inode,
|
|
520
|
-
content,
|
|
521
|
-
language: parseInt(language),
|
|
522
|
-
fieldName,
|
|
523
|
-
contentType
|
|
524
|
-
});
|
|
525
|
-
});
|
|
526
|
-
});
|
|
527
|
-
};
|
|
528
497
|
|
|
529
498
|
/**
|
|
530
|
-
*
|
|
499
|
+
* Events that can be subscribed to in the UVE
|
|
531
500
|
*
|
|
532
|
-
* @
|
|
533
|
-
* @
|
|
534
|
-
* @param {DotCMSUVEMessage<T>} message
|
|
501
|
+
* @internal
|
|
502
|
+
* @type {Record<UVEEventType, UVEEventSubscriber>}
|
|
535
503
|
*/
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
504
|
+
const __UVE_EVENTS__ = {
|
|
505
|
+
[UVEEventType.CONTENT_CHANGES]: callback => {
|
|
506
|
+
return onContentChanges(callback);
|
|
507
|
+
},
|
|
508
|
+
[UVEEventType.PAGE_RELOAD]: callback => {
|
|
509
|
+
return onPageReload(callback);
|
|
510
|
+
},
|
|
511
|
+
[UVEEventType.REQUEST_BOUNDS]: callback => {
|
|
512
|
+
return onRequestBounds(callback);
|
|
513
|
+
},
|
|
514
|
+
[UVEEventType.IFRAME_SCROLL]: callback => {
|
|
515
|
+
return onIframeScroll(callback);
|
|
516
|
+
},
|
|
517
|
+
[UVEEventType.CONTENTLET_HOVERED]: callback => {
|
|
518
|
+
return onContentletHovered(callback);
|
|
519
|
+
}
|
|
520
|
+
};
|
|
539
521
|
/**
|
|
540
|
-
*
|
|
522
|
+
* Default UVE event
|
|
541
523
|
*
|
|
542
|
-
*
|
|
524
|
+
* @param {string} event - The event to subscribe to.
|
|
525
|
+
* @internal
|
|
526
|
+
*/
|
|
527
|
+
const __UVE_EVENT_ERROR_FALLBACK__ = event => {
|
|
528
|
+
return {
|
|
529
|
+
unsubscribe: () => {
|
|
530
|
+
/* do nothing */
|
|
531
|
+
},
|
|
532
|
+
event
|
|
533
|
+
};
|
|
534
|
+
};
|
|
535
|
+
/**
|
|
536
|
+
* Development mode
|
|
543
537
|
*
|
|
544
|
-
* @
|
|
545
|
-
* @template T
|
|
546
|
-
* @param {Contentlet<T>} contentlet - The contentlet to edit.
|
|
538
|
+
* @internal
|
|
547
539
|
*/
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
payload: contentlet
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
/*
|
|
555
|
-
* Reorders the menu based on the provided configuration.
|
|
540
|
+
const DEVELOPMENT_MODE = 'development';
|
|
541
|
+
/**
|
|
542
|
+
* Production mode
|
|
556
543
|
*
|
|
557
|
-
* @
|
|
558
|
-
|
|
559
|
-
|
|
544
|
+
* @internal
|
|
545
|
+
*/
|
|
546
|
+
const PRODUCTION_MODE = 'production';
|
|
547
|
+
/**
|
|
548
|
+
* End class
|
|
560
549
|
*
|
|
561
|
-
*
|
|
562
|
-
* start level and depth, and sends a message to the editor to perform the reorder action.
|
|
550
|
+
* @internal
|
|
563
551
|
*/
|
|
564
|
-
|
|
565
|
-
const {
|
|
566
|
-
startLevel = 1,
|
|
567
|
-
depth = 2
|
|
568
|
-
} = config || {};
|
|
569
|
-
sendMessageToUVE({
|
|
570
|
-
action: DotCMSUVEAction.REORDER_MENU,
|
|
571
|
-
payload: {
|
|
572
|
-
startLevel,
|
|
573
|
-
depth
|
|
574
|
-
}
|
|
575
|
-
});
|
|
576
|
-
}
|
|
552
|
+
const END_CLASS = 'col-end-';
|
|
577
553
|
/**
|
|
578
|
-
*
|
|
554
|
+
* Start class
|
|
555
|
+
*
|
|
556
|
+
* @internal
|
|
557
|
+
*/
|
|
558
|
+
const START_CLASS = 'col-start-';
|
|
559
|
+
/**
|
|
560
|
+
* Empty container style for React
|
|
561
|
+
*
|
|
562
|
+
* @internal
|
|
563
|
+
*/
|
|
564
|
+
const EMPTY_CONTAINER_STYLE_REACT = {
|
|
565
|
+
width: '100%',
|
|
566
|
+
backgroundColor: '#ECF0FD',
|
|
567
|
+
display: 'flex',
|
|
568
|
+
justifyContent: 'center',
|
|
569
|
+
alignItems: 'center',
|
|
570
|
+
color: '#030E32',
|
|
571
|
+
height: '10rem'
|
|
572
|
+
};
|
|
573
|
+
/**
|
|
574
|
+
* Empty container style for Angular
|
|
575
|
+
*
|
|
576
|
+
* @internal
|
|
577
|
+
*/
|
|
578
|
+
const EMPTY_CONTAINER_STYLE_ANGULAR = {
|
|
579
|
+
width: '100%',
|
|
580
|
+
'background-color': '#ECF0FD',
|
|
581
|
+
display: 'flex',
|
|
582
|
+
'justify-content': 'center',
|
|
583
|
+
'align-items': 'center',
|
|
584
|
+
color: '#030E32',
|
|
585
|
+
height: '10rem'
|
|
586
|
+
};
|
|
587
|
+
/**
|
|
588
|
+
* Custom no component
|
|
589
|
+
*
|
|
590
|
+
* @internal
|
|
591
|
+
*/
|
|
592
|
+
const CUSTOM_NO_COMPONENT = 'CustomNoComponent';
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Gets the current state of the Universal Visual Editor (UVE).
|
|
596
|
+
*
|
|
597
|
+
* This function checks if the code is running inside the DotCMS Universal Visual Editor
|
|
598
|
+
* and returns information about its current state, including the editor mode.
|
|
579
599
|
*
|
|
580
600
|
* @export
|
|
581
|
-
* @
|
|
582
|
-
*
|
|
583
|
-
* @return {*}
|
|
601
|
+
* @return {UVEState | undefined} Returns the UVE state object if running inside the editor,
|
|
602
|
+
* undefined otherwise.
|
|
584
603
|
*
|
|
585
|
-
*
|
|
586
|
-
*
|
|
587
|
-
*
|
|
588
|
-
*
|
|
589
|
-
*
|
|
604
|
+
* The state includes:
|
|
605
|
+
* - mode: The current editor mode (preview, edit, live)
|
|
606
|
+
* - languageId: The language ID of the current page setted on the UVE
|
|
607
|
+
* - persona: The persona of the current page setted on the UVE
|
|
608
|
+
* - variantName: The name of the current variant
|
|
609
|
+
* - experimentId: The ID of the current experiment
|
|
610
|
+
* - publishDate: The publish date of the current page setted on the UVE
|
|
611
|
+
*
|
|
612
|
+
* @note The absence of any of these properties means that the value is the default one.
|
|
613
|
+
*
|
|
614
|
+
* @example
|
|
615
|
+
* ```ts
|
|
616
|
+
* const editorState = getUVEState();
|
|
617
|
+
* if (editorState?.mode === 'edit') {
|
|
618
|
+
* // Enable editing features
|
|
619
|
+
* }
|
|
590
620
|
* ```
|
|
591
621
|
*/
|
|
592
|
-
function
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
622
|
+
function getUVEState() {
|
|
623
|
+
if (typeof window === 'undefined' || window.parent === window || !window.location) {
|
|
624
|
+
return undefined;
|
|
625
|
+
}
|
|
626
|
+
const url = new URL(window.location.href);
|
|
627
|
+
const possibleModes = Object.values(UVE_MODE);
|
|
628
|
+
let mode = url.searchParams.get('mode') ?? UVE_MODE.EDIT;
|
|
629
|
+
const languageId = url.searchParams.get('language_id');
|
|
630
|
+
const persona = url.searchParams.get('personaId');
|
|
631
|
+
const variantName = url.searchParams.get('variantName');
|
|
632
|
+
const experimentId = url.searchParams.get('experimentId');
|
|
633
|
+
const publishDate = url.searchParams.get('publishDate');
|
|
634
|
+
const dotCMSHost = url.searchParams.get('dotCMSHost');
|
|
635
|
+
if (!possibleModes.includes(mode)) {
|
|
636
|
+
mode = UVE_MODE.EDIT;
|
|
637
|
+
}
|
|
638
|
+
return {
|
|
639
|
+
mode,
|
|
640
|
+
languageId,
|
|
641
|
+
persona,
|
|
642
|
+
variantName,
|
|
643
|
+
experimentId,
|
|
644
|
+
publishDate,
|
|
645
|
+
dotCMSHost
|
|
646
|
+
};
|
|
600
647
|
}
|
|
601
648
|
/**
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
* This function sets up:
|
|
605
|
-
* - Scroll handling
|
|
606
|
-
* - Empty contentlet styling
|
|
607
|
-
* - Block editor inline event listening
|
|
608
|
-
* - Client ready state
|
|
609
|
-
* - UVE event subscriptions
|
|
649
|
+
* Creates a subscription to a UVE event.
|
|
610
650
|
*
|
|
611
|
-
* @
|
|
612
|
-
* @
|
|
651
|
+
* @param eventType - The type of event to subscribe to
|
|
652
|
+
* @param callback - The callback function that will be called when the event occurs
|
|
653
|
+
* @returns An event subscription that can be used to unsubscribe
|
|
613
654
|
*
|
|
614
655
|
* @example
|
|
615
|
-
* ```
|
|
616
|
-
*
|
|
656
|
+
* ```ts
|
|
657
|
+
* // Subscribe to page changes
|
|
658
|
+
* const subscription = createUVESubscription(UVEEventType.CONTENT_CHANGES, (changes) => {
|
|
659
|
+
* console.log('Content changes:', changes);
|
|
660
|
+
* });
|
|
617
661
|
*
|
|
618
|
-
* //
|
|
619
|
-
*
|
|
662
|
+
* // Later, unsubscribe when no longer needed
|
|
663
|
+
* subscription.unsubscribe();
|
|
620
664
|
* ```
|
|
621
665
|
*/
|
|
622
|
-
function
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
} = listenBlockEditorInlineEvent();
|
|
634
|
-
return {
|
|
635
|
-
destroyUVESubscriptions: () => {
|
|
636
|
-
subscriptions.forEach(subscription => subscription.unsubscribe());
|
|
637
|
-
destroyScrollHandler();
|
|
638
|
-
destroyListenBlockEditorInlineEvent();
|
|
639
|
-
}
|
|
640
|
-
};
|
|
666
|
+
function createUVESubscription(eventType, callback) {
|
|
667
|
+
if (!getUVEState()) {
|
|
668
|
+
console.warn('UVE Subscription: Not running inside UVE');
|
|
669
|
+
return __UVE_EVENT_ERROR_FALLBACK__(eventType);
|
|
670
|
+
}
|
|
671
|
+
const eventCallback = __UVE_EVENTS__[eventType];
|
|
672
|
+
if (!eventCallback) {
|
|
673
|
+
console.error(`UVE Subscription: Event ${eventType} not found`);
|
|
674
|
+
return __UVE_EVENT_ERROR_FALLBACK__(eventType);
|
|
675
|
+
}
|
|
676
|
+
return eventCallback(callback);
|
|
641
677
|
}
|
|
642
678
|
|
|
643
679
|
/**
|
|
@@ -739,383 +775,274 @@ const isValidBlocks = blocks => {
|
|
|
739
775
|
};
|
|
740
776
|
};
|
|
741
777
|
|
|
778
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
742
779
|
/**
|
|
743
|
-
*
|
|
744
|
-
*
|
|
745
|
-
*
|
|
746
|
-
* @enum {string}
|
|
780
|
+
* Sets up scroll event handlers for the window to notify the editor about scroll events.
|
|
781
|
+
* Adds listeners for both 'scroll' and 'scrollend' events, sending appropriate messages
|
|
782
|
+
* to the editor when these events occur.
|
|
747
783
|
*/
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
Blocks["HEADING"] = "heading";
|
|
754
|
-
/** Represents a text block */
|
|
755
|
-
Blocks["TEXT"] = "text";
|
|
756
|
-
/** Represents a bullet/unordered list block */
|
|
757
|
-
Blocks["BULLET_LIST"] = "bulletList";
|
|
758
|
-
/** Represents an ordered/numbered list block */
|
|
759
|
-
Blocks["ORDERED_LIST"] = "orderedList";
|
|
760
|
-
/** Represents a list item within a list block */
|
|
761
|
-
Blocks["LIST_ITEM"] = "listItem";
|
|
762
|
-
/** Represents a blockquote block */
|
|
763
|
-
Blocks["BLOCK_QUOTE"] = "blockquote";
|
|
764
|
-
/** Represents a code block */
|
|
765
|
-
Blocks["CODE_BLOCK"] = "codeBlock";
|
|
766
|
-
/** Represents a hard break (line break) */
|
|
767
|
-
Blocks["HARDBREAK"] = "hardBreak";
|
|
768
|
-
/** Represents a horizontal rule/divider */
|
|
769
|
-
Blocks["HORIZONTAL_RULE"] = "horizontalRule";
|
|
770
|
-
/** Represents a DotCMS image block */
|
|
771
|
-
Blocks["DOT_IMAGE"] = "dotImage";
|
|
772
|
-
/** Represents a DotCMS video block */
|
|
773
|
-
Blocks["DOT_VIDEO"] = "dotVideo";
|
|
774
|
-
/** Represents a table block */
|
|
775
|
-
Blocks["TABLE"] = "table";
|
|
776
|
-
/** Represents a DotCMS content block */
|
|
777
|
-
Blocks["DOT_CONTENT"] = "dotContent";
|
|
778
|
-
})(Blocks || (Blocks = {}));
|
|
779
|
-
|
|
780
|
-
/**
|
|
781
|
-
* Subscribes to content changes in the UVE editor
|
|
782
|
-
*
|
|
783
|
-
* @param {UVEEventHandler} callback - Function to be called when content changes are detected
|
|
784
|
-
* @returns {Object} Object containing unsubscribe function and event type
|
|
785
|
-
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
786
|
-
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
787
|
-
* @internal
|
|
788
|
-
*/
|
|
789
|
-
function onContentChanges(callback) {
|
|
790
|
-
const messageCallback = event => {
|
|
791
|
-
if (event.data.name === __DOTCMS_UVE_EVENT__.UVE_SET_PAGE_DATA) {
|
|
792
|
-
callback(event.data.payload);
|
|
793
|
-
}
|
|
784
|
+
function scrollHandler() {
|
|
785
|
+
const scrollCallback = () => {
|
|
786
|
+
sendMessageToUVE({
|
|
787
|
+
action: DotCMSUVEAction.IFRAME_SCROLL
|
|
788
|
+
});
|
|
794
789
|
};
|
|
795
|
-
|
|
790
|
+
const scrollEndCallback = () => {
|
|
791
|
+
sendMessageToUVE({
|
|
792
|
+
action: DotCMSUVEAction.IFRAME_SCROLL_END
|
|
793
|
+
});
|
|
794
|
+
};
|
|
795
|
+
window.addEventListener('scroll', scrollCallback);
|
|
796
|
+
window.addEventListener('scrollend', scrollEndCallback);
|
|
796
797
|
return {
|
|
797
|
-
|
|
798
|
-
window.removeEventListener('
|
|
799
|
-
|
|
800
|
-
|
|
798
|
+
destroyScrollHandler: () => {
|
|
799
|
+
window.removeEventListener('scroll', scrollCallback);
|
|
800
|
+
window.removeEventListener('scrollend', scrollEndCallback);
|
|
801
|
+
}
|
|
801
802
|
};
|
|
802
803
|
}
|
|
803
804
|
/**
|
|
804
|
-
*
|
|
805
|
+
* Adds 'empty-contentlet' class to contentlet elements that have no height.
|
|
806
|
+
* This helps identify and style empty contentlets in the editor view.
|
|
805
807
|
*
|
|
806
|
-
* @
|
|
807
|
-
*
|
|
808
|
-
*
|
|
809
|
-
*
|
|
810
|
-
* @internal
|
|
808
|
+
* @remarks
|
|
809
|
+
* The function queries all elements with data-dot-object="contentlet" attribute
|
|
810
|
+
* and checks their clientHeight. If an element has no height (clientHeight = 0),
|
|
811
|
+
* it adds the 'empty-contentlet' class to that element.
|
|
811
812
|
*/
|
|
812
|
-
function
|
|
813
|
-
const
|
|
814
|
-
|
|
815
|
-
|
|
813
|
+
function addClassToEmptyContentlets() {
|
|
814
|
+
const contentlets = document.querySelectorAll('[data-dot-object="contentlet"]');
|
|
815
|
+
contentlets.forEach(contentlet => {
|
|
816
|
+
if (contentlet.clientHeight) {
|
|
817
|
+
return;
|
|
816
818
|
}
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
return {
|
|
820
|
-
unsubscribe: () => {
|
|
821
|
-
window.removeEventListener('message', messageCallback);
|
|
822
|
-
},
|
|
823
|
-
event: UVEEventType.PAGE_RELOAD
|
|
824
|
-
};
|
|
819
|
+
contentlet.classList.add('empty-contentlet');
|
|
820
|
+
});
|
|
825
821
|
}
|
|
826
822
|
/**
|
|
827
|
-
*
|
|
823
|
+
* Registers event handlers for various UVE (Universal Visual Editor) events.
|
|
828
824
|
*
|
|
829
|
-
*
|
|
830
|
-
*
|
|
831
|
-
*
|
|
832
|
-
*
|
|
833
|
-
*
|
|
825
|
+
* This function sets up subscriptions for:
|
|
826
|
+
* - Page reload events that refresh the window
|
|
827
|
+
* - Bounds request events to update editor boundaries
|
|
828
|
+
* - Iframe scroll events to handle smooth scrolling within bounds
|
|
829
|
+
* - Contentlet hover events to notify the editor
|
|
830
|
+
*
|
|
831
|
+
* @remarks
|
|
832
|
+
* For scroll events, the function includes logic to prevent scrolling beyond
|
|
833
|
+
* the top or bottom boundaries of the iframe, which helps maintain proper
|
|
834
|
+
* scroll event handling.
|
|
834
835
|
*/
|
|
835
|
-
function
|
|
836
|
-
const
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
836
|
+
function registerUVEEvents() {
|
|
837
|
+
const pageReloadSubscription = createUVESubscription(UVEEventType.PAGE_RELOAD, () => {
|
|
838
|
+
window.location.reload();
|
|
839
|
+
});
|
|
840
|
+
const requestBoundsSubscription = createUVESubscription(UVEEventType.REQUEST_BOUNDS, bounds => {
|
|
841
|
+
setBounds(bounds);
|
|
842
|
+
});
|
|
843
|
+
const iframeScrollSubscription = createUVESubscription(UVEEventType.IFRAME_SCROLL, direction => {
|
|
844
|
+
if (window.scrollY === 0 && direction === 'up' || computeScrollIsInBottom() && direction === 'down') {
|
|
845
|
+
// If the iframe scroll is at the top or bottom, do not send anything.
|
|
846
|
+
// This avoids losing the scrollend event.
|
|
847
|
+
return;
|
|
841
848
|
}
|
|
842
|
-
|
|
843
|
-
|
|
849
|
+
const scrollY = direction === 'up' ? -120 : 120;
|
|
850
|
+
window.scrollBy({
|
|
851
|
+
left: 0,
|
|
852
|
+
top: scrollY,
|
|
853
|
+
behavior: 'smooth'
|
|
854
|
+
});
|
|
855
|
+
});
|
|
856
|
+
const contentletHoveredSubscription = createUVESubscription(UVEEventType.CONTENTLET_HOVERED, contentletHovered => {
|
|
857
|
+
sendMessageToUVE({
|
|
858
|
+
action: DotCMSUVEAction.SET_CONTENTLET,
|
|
859
|
+
payload: contentletHovered
|
|
860
|
+
});
|
|
861
|
+
});
|
|
844
862
|
return {
|
|
845
|
-
|
|
846
|
-
window.removeEventListener('message', messageCallback);
|
|
847
|
-
},
|
|
848
|
-
event: UVEEventType.REQUEST_BOUNDS
|
|
863
|
+
subscriptions: [pageReloadSubscription, requestBoundsSubscription, iframeScrollSubscription, contentletHoveredSubscription]
|
|
849
864
|
};
|
|
850
865
|
}
|
|
851
866
|
/**
|
|
852
|
-
*
|
|
867
|
+
* Notifies the editor that the UVE client is ready to receive messages.
|
|
853
868
|
*
|
|
854
|
-
*
|
|
855
|
-
*
|
|
856
|
-
*
|
|
857
|
-
* @
|
|
858
|
-
*
|
|
869
|
+
* This function sends a message to the editor indicating that the client-side
|
|
870
|
+
* initialization is complete and it's ready to handle editor interactions.
|
|
871
|
+
*
|
|
872
|
+
* @remarks
|
|
873
|
+
* This is typically called after all UVE event handlers and DOM listeners
|
|
874
|
+
* have been set up successfully.
|
|
859
875
|
*/
|
|
860
|
-
function
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
}
|
|
866
|
-
};
|
|
867
|
-
window.addEventListener('message', messageCallback);
|
|
868
|
-
return {
|
|
869
|
-
unsubscribe: () => {
|
|
870
|
-
window.removeEventListener('message', messageCallback);
|
|
871
|
-
},
|
|
872
|
-
event: UVEEventType.IFRAME_SCROLL
|
|
873
|
-
};
|
|
876
|
+
function setClientIsReady(config) {
|
|
877
|
+
sendMessageToUVE({
|
|
878
|
+
action: DotCMSUVEAction.CLIENT_READY,
|
|
879
|
+
payload: config
|
|
880
|
+
});
|
|
874
881
|
}
|
|
875
882
|
/**
|
|
876
|
-
*
|
|
877
|
-
*
|
|
878
|
-
* @param {UVEEventHandler} callback - Function to be called when a contentlet is hovered
|
|
879
|
-
* @returns {Object} Object containing unsubscribe function and event type
|
|
880
|
-
* @returns {Function} .unsubscribe - Function to remove the event listener
|
|
881
|
-
* @returns {UVEEventType} .event - The event type being subscribed to
|
|
882
|
-
* @internal
|
|
883
|
+
* Listen for block editor inline event.
|
|
883
884
|
*/
|
|
884
|
-
function
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
height
|
|
893
|
-
} = foundElement.getBoundingClientRect();
|
|
894
|
-
const isContainer = foundElement.dataset?.['dotObject'] === 'container';
|
|
895
|
-
const contentletForEmptyContainer = {
|
|
896
|
-
identifier: 'TEMP_EMPTY_CONTENTLET',
|
|
897
|
-
title: 'TEMP_EMPTY_CONTENTLET',
|
|
898
|
-
contentType: 'TEMP_EMPTY_CONTENTLET_TYPE',
|
|
899
|
-
inode: 'TEMPY_EMPTY_CONTENTLET_INODE',
|
|
900
|
-
widgetTitle: 'TEMP_EMPTY_CONTENTLET',
|
|
901
|
-
baseType: 'TEMP_EMPTY_CONTENTLET',
|
|
902
|
-
onNumberOfPages: 1
|
|
903
|
-
};
|
|
904
|
-
const contentlet = {
|
|
905
|
-
identifier: foundElement.dataset?.['dotIdentifier'],
|
|
906
|
-
title: foundElement.dataset?.['dotTitle'],
|
|
907
|
-
inode: foundElement.dataset?.['dotInode'],
|
|
908
|
-
contentType: foundElement.dataset?.['dotType'],
|
|
909
|
-
baseType: foundElement.dataset?.['dotBasetype'],
|
|
910
|
-
widgetTitle: foundElement.dataset?.['dotWidgetTitle'],
|
|
911
|
-
onNumberOfPages: foundElement.dataset?.['dotOnNumberOfPages']
|
|
912
|
-
};
|
|
913
|
-
const vtlFiles = findDotCMSVTLData(foundElement);
|
|
914
|
-
const contentletPayload = {
|
|
915
|
-
container:
|
|
916
|
-
// Here extract dot-container from contentlet if it is Headless
|
|
917
|
-
// or search in parent container if it is VTL
|
|
918
|
-
foundElement.dataset?.['dotContainer'] ? JSON.parse(foundElement.dataset?.['dotContainer']) : getClosestDotCMSContainerData(foundElement),
|
|
919
|
-
contentlet: isContainer ? contentletForEmptyContainer : contentlet,
|
|
920
|
-
vtlFiles
|
|
921
|
-
};
|
|
922
|
-
const contentletHoveredPayload = {
|
|
923
|
-
x,
|
|
924
|
-
y,
|
|
925
|
-
width,
|
|
926
|
-
height,
|
|
927
|
-
payload: contentletPayload
|
|
885
|
+
function listenBlockEditorInlineEvent() {
|
|
886
|
+
if (document.readyState === 'complete') {
|
|
887
|
+
// The page is fully loaded or interactive
|
|
888
|
+
listenBlockEditorClick();
|
|
889
|
+
return {
|
|
890
|
+
destroyListenBlockEditorInlineEvent: () => {
|
|
891
|
+
window.removeEventListener('load', () => listenBlockEditorClick());
|
|
892
|
+
}
|
|
928
893
|
};
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
document.addEventListener('pointermove', pointerMoveCallback);
|
|
894
|
+
}
|
|
895
|
+
window.addEventListener('load', () => listenBlockEditorClick());
|
|
932
896
|
return {
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
}
|
|
936
|
-
event: UVEEventType.CONTENTLET_HOVERED
|
|
897
|
+
destroyListenBlockEditorInlineEvent: () => {
|
|
898
|
+
window.removeEventListener('load', () => listenBlockEditorClick());
|
|
899
|
+
}
|
|
937
900
|
};
|
|
938
901
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
* @internal
|
|
944
|
-
* @type {Record<UVEEventType, UVEEventSubscriber>}
|
|
945
|
-
*/
|
|
946
|
-
const __UVE_EVENTS__ = {
|
|
947
|
-
[UVEEventType.CONTENT_CHANGES]: callback => {
|
|
948
|
-
return onContentChanges(callback);
|
|
949
|
-
},
|
|
950
|
-
[UVEEventType.PAGE_RELOAD]: callback => {
|
|
951
|
-
return onPageReload(callback);
|
|
952
|
-
},
|
|
953
|
-
[UVEEventType.REQUEST_BOUNDS]: callback => {
|
|
954
|
-
return onRequestBounds(callback);
|
|
955
|
-
},
|
|
956
|
-
[UVEEventType.IFRAME_SCROLL]: callback => {
|
|
957
|
-
return onIframeScroll(callback);
|
|
958
|
-
},
|
|
959
|
-
[UVEEventType.CONTENTLET_HOVERED]: callback => {
|
|
960
|
-
return onContentletHovered(callback);
|
|
902
|
+
const listenBlockEditorClick = () => {
|
|
903
|
+
const editBlockEditorNodes = document.querySelectorAll('[data-block-editor-content]');
|
|
904
|
+
if (!editBlockEditorNodes.length) {
|
|
905
|
+
return;
|
|
961
906
|
}
|
|
907
|
+
editBlockEditorNodes.forEach(node => {
|
|
908
|
+
const {
|
|
909
|
+
inode,
|
|
910
|
+
language = '1',
|
|
911
|
+
contentType,
|
|
912
|
+
fieldName,
|
|
913
|
+
blockEditorContent
|
|
914
|
+
} = node.dataset;
|
|
915
|
+
const content = JSON.parse(blockEditorContent || '');
|
|
916
|
+
if (!inode || !language || !contentType || !fieldName) {
|
|
917
|
+
console.error('Missing data attributes for block editor inline editing.');
|
|
918
|
+
console.warn('inode, language, contentType and fieldName are required.');
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
node.classList.add('dotcms__inline-edit-field');
|
|
922
|
+
node.addEventListener('click', () => {
|
|
923
|
+
initInlineEditing('BLOCK_EDITOR', {
|
|
924
|
+
inode,
|
|
925
|
+
content,
|
|
926
|
+
language: parseInt(language),
|
|
927
|
+
fieldName,
|
|
928
|
+
contentType
|
|
929
|
+
});
|
|
930
|
+
});
|
|
931
|
+
});
|
|
962
932
|
};
|
|
933
|
+
|
|
963
934
|
/**
|
|
964
|
-
*
|
|
965
|
-
*
|
|
966
|
-
* @param {string} event - The event to subscribe to.
|
|
967
|
-
* @internal
|
|
968
|
-
*/
|
|
969
|
-
const __UVE_EVENT_ERROR_FALLBACK__ = event => {
|
|
970
|
-
return {
|
|
971
|
-
unsubscribe: () => {
|
|
972
|
-
/* do nothing */
|
|
973
|
-
},
|
|
974
|
-
event
|
|
975
|
-
};
|
|
976
|
-
};
|
|
977
|
-
/**
|
|
978
|
-
* Development mode
|
|
979
|
-
*
|
|
980
|
-
* @internal
|
|
981
|
-
*/
|
|
982
|
-
const DEVELOPMENT_MODE = 'development';
|
|
983
|
-
/**
|
|
984
|
-
* Production mode
|
|
985
|
-
*
|
|
986
|
-
* @internal
|
|
987
|
-
*/
|
|
988
|
-
const PRODUCTION_MODE = 'production';
|
|
989
|
-
/**
|
|
990
|
-
* End class
|
|
935
|
+
* Post message to dotcms page editor
|
|
991
936
|
*
|
|
992
|
-
* @
|
|
937
|
+
* @export
|
|
938
|
+
* @template T
|
|
939
|
+
* @param {DotCMSUVEMessage<T>} message
|
|
993
940
|
*/
|
|
994
|
-
|
|
941
|
+
function sendMessageToUVE(message) {
|
|
942
|
+
window.parent.postMessage(message, '*');
|
|
943
|
+
}
|
|
995
944
|
/**
|
|
996
|
-
*
|
|
945
|
+
* You can use this function to edit a contentlet in the editor.
|
|
997
946
|
*
|
|
998
|
-
*
|
|
999
|
-
*/
|
|
1000
|
-
const START_CLASS = 'col-start-';
|
|
1001
|
-
/**
|
|
1002
|
-
* Empty container style for React
|
|
947
|
+
* Calling this function inside the editor, will prompt the UVE to open a dialog to edit the contentlet.
|
|
1003
948
|
*
|
|
1004
|
-
* @
|
|
949
|
+
* @export
|
|
950
|
+
* @template T
|
|
951
|
+
* @param {Contentlet<T>} contentlet - The contentlet to edit.
|
|
1005
952
|
*/
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
};
|
|
1015
|
-
/**
|
|
1016
|
-
* Empty container style for Angular
|
|
953
|
+
function editContentlet(contentlet) {
|
|
954
|
+
sendMessageToUVE({
|
|
955
|
+
action: DotCMSUVEAction.EDIT_CONTENTLET,
|
|
956
|
+
payload: contentlet
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
/*
|
|
960
|
+
* Reorders the menu based on the provided configuration.
|
|
1017
961
|
*
|
|
1018
|
-
* @
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
width: '100%',
|
|
1022
|
-
'background-color': '#ECF0FD',
|
|
1023
|
-
display: 'flex',
|
|
1024
|
-
'justify-content': 'center',
|
|
1025
|
-
'align-items': 'center',
|
|
1026
|
-
color: '#030E32',
|
|
1027
|
-
height: '10rem'
|
|
1028
|
-
};
|
|
1029
|
-
/**
|
|
1030
|
-
* Custom no component
|
|
962
|
+
* @param {ReorderMenuConfig} [config] - Optional configuration for reordering the menu.
|
|
963
|
+
* @param {number} [config.startLevel=1] - The starting level of the menu to reorder.
|
|
964
|
+
* @param {number} [config.depth=2] - The depth of the menu to reorder.
|
|
1031
965
|
*
|
|
1032
|
-
*
|
|
966
|
+
* This function constructs a URL for the reorder menu page with the specified
|
|
967
|
+
* start level and depth, and sends a message to the editor to perform the reorder action.
|
|
1033
968
|
*/
|
|
1034
|
-
|
|
1035
|
-
|
|
969
|
+
function reorderMenu(config) {
|
|
970
|
+
const {
|
|
971
|
+
startLevel = 1,
|
|
972
|
+
depth = 2
|
|
973
|
+
} = config || {};
|
|
974
|
+
sendMessageToUVE({
|
|
975
|
+
action: DotCMSUVEAction.REORDER_MENU,
|
|
976
|
+
payload: {
|
|
977
|
+
startLevel,
|
|
978
|
+
depth
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
}
|
|
1036
982
|
/**
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1039
|
-
* This function checks if the code is running inside the DotCMS Universal Visual Editor
|
|
1040
|
-
* and returns information about its current state, including the editor mode.
|
|
983
|
+
* Initializes the inline editing in the editor.
|
|
1041
984
|
*
|
|
1042
985
|
* @export
|
|
1043
|
-
* @
|
|
1044
|
-
*
|
|
1045
|
-
*
|
|
1046
|
-
* The state includes:
|
|
1047
|
-
* - mode: The current editor mode (preview, edit, live)
|
|
1048
|
-
* - languageId: The language ID of the current page setted on the UVE
|
|
1049
|
-
* - persona: The persona of the current page setted on the UVE
|
|
1050
|
-
* - variantName: The name of the current variant
|
|
1051
|
-
* - experimentId: The ID of the current experiment
|
|
1052
|
-
* - publishDate: The publish date of the current page setted on the UVE
|
|
1053
|
-
*
|
|
1054
|
-
* @note The absence of any of these properties means that the value is the default one.
|
|
986
|
+
* @param {INLINE_EDITING_EVENT_KEY} type
|
|
987
|
+
* @param {InlineEditEventData} eventData
|
|
988
|
+
* @return {*}
|
|
1055
989
|
*
|
|
1056
|
-
* @example
|
|
1057
|
-
* ```
|
|
1058
|
-
*
|
|
1059
|
-
*
|
|
1060
|
-
*
|
|
1061
|
-
* }
|
|
990
|
+
* * @example
|
|
991
|
+
* ```html
|
|
992
|
+
* <div onclick="initInlineEditing('BLOCK_EDITOR', { inode, languageId, contentType, fieldName, content })">
|
|
993
|
+
* ${My Content}
|
|
994
|
+
* </div>
|
|
1062
995
|
* ```
|
|
1063
996
|
*/
|
|
1064
|
-
function
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
const persona = url.searchParams.get('personaId');
|
|
1073
|
-
const variantName = url.searchParams.get('variantName');
|
|
1074
|
-
const experimentId = url.searchParams.get('experimentId');
|
|
1075
|
-
const publishDate = url.searchParams.get('publishDate');
|
|
1076
|
-
const dotCMSHost = url.searchParams.get('dotCMSHost');
|
|
1077
|
-
if (!possibleModes.includes(mode)) {
|
|
1078
|
-
mode = UVE_MODE.EDIT;
|
|
1079
|
-
}
|
|
1080
|
-
return {
|
|
1081
|
-
mode,
|
|
1082
|
-
languageId,
|
|
1083
|
-
persona,
|
|
1084
|
-
variantName,
|
|
1085
|
-
experimentId,
|
|
1086
|
-
publishDate,
|
|
1087
|
-
dotCMSHost
|
|
1088
|
-
};
|
|
997
|
+
function initInlineEditing(type, data) {
|
|
998
|
+
sendMessageToUVE({
|
|
999
|
+
action: DotCMSUVEAction.INIT_INLINE_EDITING,
|
|
1000
|
+
payload: {
|
|
1001
|
+
type,
|
|
1002
|
+
data
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1089
1005
|
}
|
|
1090
1006
|
/**
|
|
1091
|
-
*
|
|
1007
|
+
* Initializes the Universal Visual Editor (UVE) with required handlers and event listeners.
|
|
1092
1008
|
*
|
|
1093
|
-
*
|
|
1094
|
-
*
|
|
1095
|
-
*
|
|
1009
|
+
* This function sets up:
|
|
1010
|
+
* - Scroll handling
|
|
1011
|
+
* - Empty contentlet styling
|
|
1012
|
+
* - Block editor inline event listening
|
|
1013
|
+
* - Client ready state
|
|
1014
|
+
* - UVE event subscriptions
|
|
1015
|
+
*
|
|
1016
|
+
* @returns {Object} An object containing the cleanup function
|
|
1017
|
+
* @returns {Function} destroyUVESubscriptions - Function to clean up all UVE event subscriptions
|
|
1096
1018
|
*
|
|
1097
1019
|
* @example
|
|
1098
|
-
* ```
|
|
1099
|
-
*
|
|
1100
|
-
* const subscription = createUVESubscription(UVEEventType.CONTENT_CHANGES, (changes) => {
|
|
1101
|
-
* console.log('Content changes:', changes);
|
|
1102
|
-
* });
|
|
1020
|
+
* ```typescript
|
|
1021
|
+
* const { destroyUVESubscriptions } = initUVE();
|
|
1103
1022
|
*
|
|
1104
|
-
* //
|
|
1105
|
-
*
|
|
1023
|
+
* // When done with UVE
|
|
1024
|
+
* destroyUVESubscriptions();
|
|
1106
1025
|
* ```
|
|
1107
1026
|
*/
|
|
1108
|
-
function
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1027
|
+
function initUVE(config = {}) {
|
|
1028
|
+
addClassToEmptyContentlets();
|
|
1029
|
+
setClientIsReady(config);
|
|
1030
|
+
const {
|
|
1031
|
+
subscriptions
|
|
1032
|
+
} = registerUVEEvents();
|
|
1033
|
+
const {
|
|
1034
|
+
destroyScrollHandler
|
|
1035
|
+
} = scrollHandler();
|
|
1036
|
+
const {
|
|
1037
|
+
destroyListenBlockEditorInlineEvent
|
|
1038
|
+
} = listenBlockEditorInlineEvent();
|
|
1039
|
+
return {
|
|
1040
|
+
destroyUVESubscriptions: () => {
|
|
1041
|
+
subscriptions.forEach(subscription => subscription.unsubscribe());
|
|
1042
|
+
destroyScrollHandler();
|
|
1043
|
+
destroyListenBlockEditorInlineEvent();
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1119
1046
|
}
|
|
1120
1047
|
|
|
1121
|
-
export {
|
|
1048
|
+
export { CUSTOM_NO_COMPONENT as C, DEVELOPMENT_MODE as D, END_CLASS as E, PRODUCTION_MODE as P, START_CLASS as S, __UVE_EVENTS__ as _, initUVE as a, __UVE_EVENT_ERROR_FALLBACK__ as b, createUVESubscription as c, EMPTY_CONTAINER_STYLE_REACT as d, editContentlet as e, EMPTY_CONTAINER_STYLE_ANGULAR as f, getUVEState as g, getDotCMSPageBounds as h, initInlineEditing as i, getDotCMSContentletsBound as j, getDotCMSContainerData as k, getClosestDotCMSContainerData as l, findDotCMSElement as m, findDotCMSVTLData as n, computeScrollIsInBottom as o, combineClasses as p, getColumnPositionClasses as q, reorderMenu as r, sendMessageToUVE as s, getDotContentletAttributes as t, getContainersData as u, getContentletsInContainer as v, getDotContainerAttributes as w, setBounds as x, isValidBlocks as y };
|