@dotcms/angular 0.0.1-beta.3 → 0.0.1-beta.31

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.
Files changed (161) hide show
  1. package/dotcms-angular.d.ts.map +1 -1
  2. package/esm2022/dotcms-angular.mjs +2 -2
  3. package/esm2022/lib/deprecated/components/dot-editable-text/dot-editable-text.component.mjs +229 -0
  4. package/esm2022/lib/deprecated/components/dot-editable-text/utils.mjs +43 -0
  5. package/esm2022/lib/deprecated/components/no-component/no-component.component.mjs +32 -0
  6. package/esm2022/lib/deprecated/deprecated-api.mjs +11 -0
  7. package/esm2022/lib/{layout → deprecated/layout}/column/column.component.mjs +1 -1
  8. package/esm2022/lib/deprecated/layout/container/container.component.mjs +126 -0
  9. package/esm2022/lib/deprecated/layout/contentlet/contentlet.component.mjs +120 -0
  10. package/esm2022/lib/deprecated/layout/dotcms-layout/dotcms-layout.component.mjs +106 -0
  11. package/esm2022/lib/{layout → deprecated/layout}/row/row.component.mjs +1 -1
  12. package/esm2022/lib/deprecated/models/dotcms.model.mjs +3 -0
  13. package/esm2022/lib/deprecated/models/index.mjs +3 -0
  14. package/esm2022/lib/deprecated/services/dotcms-context/page-context.service.mjs +79 -0
  15. package/esm2022/lib/deprecated/utils/image_loader.mjs +74 -0
  16. package/esm2022/lib/deprecated/utils/index.mjs +84 -0
  17. package/esm2022/next/components/dotcms-block-editor-renderer/blocks/code.component.mjs +49 -0
  18. package/esm2022/next/components/dotcms-block-editor-renderer/blocks/dot-contentlet.component.mjs +125 -0
  19. package/esm2022/next/components/dotcms-block-editor-renderer/blocks/image.component.mjs +25 -0
  20. package/esm2022/next/components/dotcms-block-editor-renderer/blocks/list.component.mjs +66 -0
  21. package/esm2022/next/components/dotcms-block-editor-renderer/blocks/table.component.mjs +97 -0
  22. package/esm2022/next/components/dotcms-block-editor-renderer/blocks/text.component.mjs +231 -0
  23. package/esm2022/next/components/dotcms-block-editor-renderer/blocks/unknown.component.mjs +65 -0
  24. package/esm2022/next/components/dotcms-block-editor-renderer/blocks/video.component.mjs +48 -0
  25. package/esm2022/next/components/dotcms-block-editor-renderer/dotcms-block-editor-renderer.component.mjs +50 -0
  26. package/esm2022/next/components/dotcms-block-editor-renderer/item/dotcms-block-editor-item.component.mjs +45 -0
  27. package/esm2022/next/components/dotcms-editable-text/dotcms-editable-text.component.mjs +246 -0
  28. package/esm2022/next/components/dotcms-editable-text/utils.mjs +20 -0
  29. package/esm2022/next/components/dotcms-layout-body/components/column/column.component.mjs +45 -0
  30. package/esm2022/next/components/dotcms-layout-body/components/container/components/container-not-found/container-not-found.component.mjs +52 -0
  31. package/esm2022/next/components/dotcms-layout-body/components/container/components/empty-container/empty-container.component.mjs +43 -0
  32. package/esm2022/next/components/dotcms-layout-body/components/container/container.component.mjs +99 -0
  33. package/esm2022/next/components/dotcms-layout-body/components/contentlet/contentlet.component.mjs +145 -0
  34. package/esm2022/next/components/dotcms-layout-body/components/fallback-component/fallback-component.component.mjs +47 -0
  35. package/esm2022/next/components/dotcms-layout-body/components/page-error-message/page-error-message.component.mjs +55 -0
  36. package/esm2022/next/components/dotcms-layout-body/components/row/row.component.mjs +46 -0
  37. package/esm2022/next/components/dotcms-layout-body/dotcms-layout-body.component.mjs +69 -0
  38. package/esm2022/next/directives/dotcms-show-when/dotcms-show-when.directive.mjs +49 -0
  39. package/esm2022/next/dotcms-angular-next.mjs +5 -0
  40. package/esm2022/next/models/index.mjs +3 -0
  41. package/esm2022/next/providers/dotcms-image-loader/dotcms-image_loader.mjs +74 -0
  42. package/esm2022/next/public_api.mjs +7 -0
  43. package/esm2022/next/services/dotcms-editable-page.service.mjs +93 -0
  44. package/esm2022/next/store/dotcms.store.mjs +61 -0
  45. package/esm2022/public_api.mjs +2 -0
  46. package/fesm2022/dotcms-angular-next.mjs +1855 -0
  47. package/fesm2022/dotcms-angular-next.mjs.map +1 -0
  48. package/fesm2022/dotcms-angular.mjs +103 -10
  49. package/fesm2022/dotcms-angular.mjs.map +1 -1
  50. package/index.d.ts +6 -5
  51. package/lib/{components → deprecated/components}/dot-editable-text/dot-editable-text.component.d.ts +10 -6
  52. package/lib/deprecated/components/dot-editable-text/dot-editable-text.component.d.ts.map +1 -0
  53. package/lib/deprecated/components/dot-editable-text/utils.d.ts.map +1 -0
  54. package/lib/deprecated/components/no-component/no-component.component.d.ts.map +1 -0
  55. package/lib/deprecated/deprecated-api.d.ts +11 -0
  56. package/lib/deprecated/deprecated-api.d.ts.map +1 -0
  57. package/lib/deprecated/layout/column/column.component.d.ts.map +1 -0
  58. package/lib/deprecated/layout/container/container.component.d.ts.map +1 -0
  59. package/lib/deprecated/layout/contentlet/contentlet.component.d.ts.map +1 -0
  60. package/lib/{layout → deprecated/layout}/dotcms-layout/dotcms-layout.component.d.ts +5 -0
  61. package/lib/deprecated/layout/dotcms-layout/dotcms-layout.component.d.ts.map +1 -0
  62. package/lib/deprecated/layout/row/row.component.d.ts.map +1 -0
  63. package/lib/deprecated/models/dotcms.model.d.ts.map +1 -0
  64. package/lib/deprecated/models/index.d.ts.map +1 -0
  65. package/lib/{services → deprecated/services}/dotcms-context/page-context.service.d.ts +4 -0
  66. package/lib/deprecated/services/dotcms-context/page-context.service.d.ts.map +1 -0
  67. package/lib/deprecated/utils/image_loader.d.ts +21 -0
  68. package/lib/deprecated/utils/image_loader.d.ts.map +1 -0
  69. package/lib/deprecated/utils/index.d.ts.map +1 -0
  70. package/next/components/dotcms-block-editor-renderer/blocks/code.component.d.ts +10 -0
  71. package/next/components/dotcms-block-editor-renderer/blocks/code.component.d.ts.map +1 -0
  72. package/next/components/dotcms-block-editor-renderer/blocks/dot-contentlet.component.d.ts +34 -0
  73. package/next/components/dotcms-block-editor-renderer/blocks/dot-contentlet.component.d.ts.map +1 -0
  74. package/next/components/dotcms-block-editor-renderer/blocks/image.component.d.ts +9 -0
  75. package/next/components/dotcms-block-editor-renderer/blocks/image.component.d.ts.map +1 -0
  76. package/next/components/dotcms-block-editor-renderer/blocks/list.component.d.ts +14 -0
  77. package/next/components/dotcms-block-editor-renderer/blocks/list.component.d.ts.map +1 -0
  78. package/next/components/dotcms-block-editor-renderer/blocks/table.component.d.ts +10 -0
  79. package/next/components/dotcms-block-editor-renderer/blocks/table.component.d.ts.map +1 -0
  80. package/next/components/dotcms-block-editor-renderer/blocks/text.component.d.ts +27 -0
  81. package/next/components/dotcms-block-editor-renderer/blocks/text.component.d.ts.map +1 -0
  82. package/next/components/dotcms-block-editor-renderer/blocks/unknown.component.d.ts +18 -0
  83. package/next/components/dotcms-block-editor-renderer/blocks/unknown.component.d.ts.map +1 -0
  84. package/next/components/dotcms-block-editor-renderer/blocks/video.component.d.ts +10 -0
  85. package/next/components/dotcms-block-editor-renderer/blocks/video.component.d.ts.map +1 -0
  86. package/next/components/dotcms-block-editor-renderer/dotcms-block-editor-renderer.component.d.ts +39 -0
  87. package/next/components/dotcms-block-editor-renderer/dotcms-block-editor-renderer.component.d.ts.map +1 -0
  88. package/next/components/dotcms-block-editor-renderer/item/dotcms-block-editor-item.component.d.ts +12 -0
  89. package/next/components/dotcms-block-editor-renderer/item/dotcms-block-editor-item.component.d.ts.map +1 -0
  90. package/next/components/dotcms-editable-text/dotcms-editable-text.component.d.ts +129 -0
  91. package/next/components/dotcms-editable-text/dotcms-editable-text.component.d.ts.map +1 -0
  92. package/next/components/dotcms-editable-text/utils.d.ts +7 -0
  93. package/next/components/dotcms-editable-text/utils.d.ts.map +1 -0
  94. package/next/components/dotcms-layout-body/components/column/column.component.d.ts +21 -0
  95. package/next/components/dotcms-layout-body/components/column/column.component.d.ts.map +1 -0
  96. package/next/components/dotcms-layout-body/components/container/components/container-not-found/container-not-found.component.d.ts +27 -0
  97. package/next/components/dotcms-layout-body/components/container/components/container-not-found/container-not-found.component.d.ts.map +1 -0
  98. package/next/components/dotcms-layout-body/components/container/components/empty-container/empty-container.component.d.ts +23 -0
  99. package/next/components/dotcms-layout-body/components/container/components/empty-container/empty-container.component.d.ts.map +1 -0
  100. package/next/components/dotcms-layout-body/components/container/container.component.d.ts +32 -0
  101. package/next/components/dotcms-layout-body/components/container/container.component.d.ts.map +1 -0
  102. package/next/components/dotcms-layout-body/components/contentlet/contentlet.component.d.ts +48 -0
  103. package/next/components/dotcms-layout-body/components/contentlet/contentlet.component.d.ts.map +1 -0
  104. package/next/components/dotcms-layout-body/components/fallback-component/fallback-component.component.d.ts +16 -0
  105. package/next/components/dotcms-layout-body/components/fallback-component/fallback-component.component.d.ts.map +1 -0
  106. package/next/components/dotcms-layout-body/components/page-error-message/page-error-message.component.d.ts +13 -0
  107. package/next/components/dotcms-layout-body/components/page-error-message/page-error-message.component.d.ts.map +1 -0
  108. package/next/components/dotcms-layout-body/components/row/row.component.d.ts +22 -0
  109. package/next/components/dotcms-layout-body/components/row/row.component.d.ts.map +1 -0
  110. package/next/components/dotcms-layout-body/dotcms-layout-body.component.d.ts +30 -0
  111. package/next/components/dotcms-layout-body/dotcms-layout-body.component.d.ts.map +1 -0
  112. package/next/directives/dotcms-show-when/dotcms-show-when.directive.d.ts +21 -0
  113. package/next/directives/dotcms-show-when/dotcms-show-when.directive.d.ts.map +1 -0
  114. package/next/dotcms-angular-next.d.ts.map +1 -0
  115. package/next/index.d.ts +6 -0
  116. package/next/models/index.d.ts +39 -0
  117. package/next/models/index.d.ts.map +1 -0
  118. package/next/providers/dotcms-image-loader/dotcms-image_loader.d.ts +21 -0
  119. package/next/providers/dotcms-image-loader/dotcms-image_loader.d.ts.map +1 -0
  120. package/next/public_api.d.ts +7 -0
  121. package/next/public_api.d.ts.map +1 -0
  122. package/next/services/dotcms-editable-page.service.d.ts +40 -0
  123. package/next/services/dotcms-editable-page.service.d.ts.map +1 -0
  124. package/next/store/dotcms.store.d.ts +36 -0
  125. package/next/store/dotcms.store.d.ts.map +1 -0
  126. package/package.json +9 -2
  127. package/public_api.d.ts +2 -0
  128. package/public_api.d.ts.map +1 -0
  129. package/esm2022/index.mjs +0 -5
  130. package/esm2022/lib/components/dot-editable-text/dot-editable-text.component.mjs +0 -225
  131. package/esm2022/lib/components/dot-editable-text/utils.mjs +0 -43
  132. package/esm2022/lib/components/no-component/no-component.component.mjs +0 -32
  133. package/esm2022/lib/layout/container/container.component.mjs +0 -126
  134. package/esm2022/lib/layout/contentlet/contentlet.component.mjs +0 -120
  135. package/esm2022/lib/layout/dotcms-layout/dotcms-layout.component.mjs +0 -100
  136. package/esm2022/lib/models/dotcms.model.mjs +0 -3
  137. package/esm2022/lib/models/index.mjs +0 -3
  138. package/esm2022/lib/services/dotcms-context/page-context.service.mjs +0 -75
  139. package/esm2022/lib/utils/index.mjs +0 -84
  140. package/index.d.ts.map +0 -1
  141. package/lib/components/dot-editable-text/dot-editable-text.component.d.ts.map +0 -1
  142. package/lib/components/dot-editable-text/utils.d.ts.map +0 -1
  143. package/lib/components/no-component/no-component.component.d.ts.map +0 -1
  144. package/lib/layout/column/column.component.d.ts.map +0 -1
  145. package/lib/layout/container/container.component.d.ts.map +0 -1
  146. package/lib/layout/contentlet/contentlet.component.d.ts.map +0 -1
  147. package/lib/layout/dotcms-layout/dotcms-layout.component.d.ts.map +0 -1
  148. package/lib/layout/row/row.component.d.ts.map +0 -1
  149. package/lib/models/dotcms.model.d.ts.map +0 -1
  150. package/lib/models/index.d.ts.map +0 -1
  151. package/lib/services/dotcms-context/page-context.service.d.ts.map +0 -1
  152. package/lib/utils/index.d.ts.map +0 -1
  153. /package/lib/{components → deprecated/components}/dot-editable-text/utils.d.ts +0 -0
  154. /package/lib/{components → deprecated/components}/no-component/no-component.component.d.ts +0 -0
  155. /package/lib/{layout → deprecated/layout}/column/column.component.d.ts +0 -0
  156. /package/lib/{layout → deprecated/layout}/container/container.component.d.ts +0 -0
  157. /package/lib/{layout → deprecated/layout}/contentlet/contentlet.component.d.ts +0 -0
  158. /package/lib/{layout → deprecated/layout}/row/row.component.d.ts +0 -0
  159. /package/lib/{models → deprecated/models}/dotcms.model.d.ts +0 -0
  160. /package/lib/{models → deprecated/models}/index.d.ts +0 -0
  161. /package/lib/{utils → deprecated/utils}/index.d.ts +0 -0
@@ -0,0 +1,1855 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, ViewContainerRef, TemplateRef, Input, Directive, Renderer2, ElementRef, SecurityContext, HostListener, ViewChild, Component, ChangeDetectionStrategy, computed, signal, Injectable, HostBinding } from '@angular/core';
3
+ import { UVE_MODE, DotCMSUVEAction, UVEEventType } from '@dotcms/types';
4
+ import { getUVEState, sendMessageToUVE, initUVE, updateNavigation, createUVESubscription } from '@dotcms/uve';
5
+ import { IMAGE_LOADER, NgComponentOutlet, AsyncPipe, NgTemplateOutlet, NgStyle } from '@angular/common';
6
+ import { EditorComponent, TINYMCE_SCRIPT_SRC } from '@tinymce/tinymce-angular';
7
+ import { DomSanitizer } from '@angular/platform-browser';
8
+ import { __DOTCMS_UVE_EVENT__, BlockEditorDefaultBlocks } from '@dotcms/types/internal';
9
+ import { __DEFAULT_TINYMCE_CONFIG__, __BASE_TINYMCE_CONFIG_WITH_NO_DEFAULT__, __TINYMCE_PATH_ON_DOTCMS__, isValidBlocks, PRODUCTION_MODE, DEVELOPMENT_MODE, EMPTY_CONTAINER_STYLE_ANGULAR, getDotContentletAttributes, CUSTOM_NO_COMPONENT, getDotContainerAttributes, getContainersData, getContentletsInContainer, getColumnPositionClasses, combineClasses } from '@dotcms/uve/internal';
10
+ import { Subject, of } from 'rxjs';
11
+ import { finalize } from 'rxjs/operators';
12
+
13
+ /**
14
+ * Directive to show a template when the UVE is in a specific mode.
15
+ *
16
+ * @example
17
+ * <div *dotCMSShowWhen="UVE_MODE.EDIT">
18
+ * This will be shown when the UVE is in edit mode.
19
+ * </div>
20
+ *
21
+ * @export
22
+ * @class DotCMSShowWhenDirective
23
+ */
24
+ class DotCMSShowWhenDirective {
25
+ #when = UVE_MODE.EDIT;
26
+ #hasView = false;
27
+ set dotCMSShowWhen(value) {
28
+ this.#when = value;
29
+ this.updateViewContainer();
30
+ }
31
+ #viewContainerRef = inject(ViewContainerRef);
32
+ #templateRef = inject(TemplateRef);
33
+ updateViewContainer() {
34
+ const state = getUVEState();
35
+ const shouldShow = state?.mode === this.#when;
36
+ if (shouldShow && !this.#hasView) {
37
+ this.#viewContainerRef.createEmbeddedView(this.#templateRef);
38
+ this.#hasView = true;
39
+ }
40
+ else if (!shouldShow && this.#hasView) {
41
+ this.#viewContainerRef.clear();
42
+ this.#hasView = false;
43
+ }
44
+ }
45
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSShowWhenDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
46
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.3", type: DotCMSShowWhenDirective, isStandalone: true, selector: "[dotCMSShowWhen]", inputs: { dotCMSShowWhen: "dotCMSShowWhen" }, ngImport: i0 }); }
47
+ }
48
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSShowWhenDirective, decorators: [{
49
+ type: Directive,
50
+ args: [{
51
+ selector: '[dotCMSShowWhen]',
52
+ standalone: true
53
+ }]
54
+ }], propDecorators: { dotCMSShowWhen: [{
55
+ type: Input
56
+ }] } });
57
+
58
+ /**
59
+ * Validates if a given path is a valid URL string
60
+ *
61
+ * @param path - The path to validate
62
+ * @returns boolean indicating if the path is valid
63
+ */
64
+ function isValidPath(path) {
65
+ if (typeof path !== 'string' || path.trim() === '') {
66
+ return false;
67
+ }
68
+ try {
69
+ new URL(path);
70
+ return true;
71
+ }
72
+ catch {
73
+ return false;
74
+ }
75
+ }
76
+ /**
77
+ * Provides a DotCMS image loader configuration for the Angular Image directive
78
+ *
79
+ * @param path - The base URL path to the DotCMS instance, or empty to use current site
80
+ * @returns An array of providers for the IMAGE_LOADER token
81
+ * @throws Error if the provided path is invalid
82
+ * @example
83
+ * ```typescript
84
+ * // In your app.config.ts
85
+ * export const appConfig: ApplicationConfig = {
86
+ * providers: [
87
+ * provideDotCMSImageLoader('https://demo.dotcms.com')
88
+ * // Or use current site:
89
+ * // provideDotCMSImageLoader()
90
+ * ]
91
+ * };
92
+ * ```
93
+ */
94
+ function provideDotCMSImageLoader(path) {
95
+ // If path is provided, validate it
96
+ if (path && !isValidPath(path)) {
97
+ throw new Error(`Image loader has detected an invalid path (\`${path}\`). ` +
98
+ `To fix this, supply either the full URL to the dotCMS site, or leave it empty to use the current site.`);
99
+ }
100
+ return [
101
+ {
102
+ provide: IMAGE_LOADER,
103
+ useValue: (config) => createDotCMSURL(config, path)
104
+ }
105
+ ];
106
+ }
107
+ /**
108
+ * Creates a DotCMS-compatible URL for image loading
109
+ *
110
+ * @param config - The image loader configuration
111
+ * @param path - The base URL path to the DotCMS instance
112
+ * @returns A fully qualified URL for the image
113
+ * @internal
114
+ */
115
+ function createDotCMSURL(config, path) {
116
+ const { loaderParams, src, width } = config;
117
+ const params = loaderParams;
118
+ if (params?.isOutsideSRC) {
119
+ return src;
120
+ }
121
+ // Use empty string as fallback to support using current site
122
+ const dotcmsHost = path ? new URL(path).origin : '';
123
+ const imageSRC = src.includes('/dA/') ? src : `/dA/${src}`;
124
+ const languageId = params?.languageId ?? '1';
125
+ if (width) {
126
+ return `${dotcmsHost}${imageSRC}/${width}w?language_id=${languageId}`;
127
+ }
128
+ return `${dotcmsHost}${imageSRC}?language_id=${languageId}`;
129
+ }
130
+
131
+ const DEFAULT_TINYMCE_CONFIG = {
132
+ ...__DEFAULT_TINYMCE_CONFIG__,
133
+ license_key: 'gpl' // Using self-hosted license key
134
+ };
135
+ const TINYMCE_CONFIG = {
136
+ minimal: {
137
+ ...DEFAULT_TINYMCE_CONFIG,
138
+ ...__BASE_TINYMCE_CONFIG_WITH_NO_DEFAULT__.minimal
139
+ },
140
+ full: {
141
+ ...DEFAULT_TINYMCE_CONFIG,
142
+ ...__BASE_TINYMCE_CONFIG_WITH_NO_DEFAULT__.full
143
+ },
144
+ plain: {
145
+ ...DEFAULT_TINYMCE_CONFIG,
146
+ ...__BASE_TINYMCE_CONFIG_WITH_NO_DEFAULT__.plain
147
+ }
148
+ };
149
+
150
+ /**
151
+ * Dot editable text component.
152
+ * This component is responsible to render a text field that can be edited inline.
153
+ *
154
+ * @export
155
+ * @class DotCMSEditableTextComponent
156
+ * @implements {OnInit}
157
+ * @implements {OnChanges}
158
+ */
159
+ class DotCMSEditableTextComponent {
160
+ constructor() {
161
+ /**
162
+ * Represents the mode of the editor which can be `plain`, `minimal`, or `full`
163
+ *
164
+ * @type {DOT_EDITABLE_TEXT_MODE}
165
+ * @memberof DotCMSEditableTextComponent
166
+ */
167
+ this.mode = 'plain';
168
+ /**
169
+ * Represents the format of the editor which can be `text` or `html`
170
+ *
171
+ * @type {DOT_EDITABLE_TEXT_FORMAT}
172
+ * @memberof DotCMSEditableTextComponent
173
+ */
174
+ this.format = 'text';
175
+ /**
176
+ * Represents the field name of the `contentlet` that can be edited
177
+ *
178
+ * @memberof DotCMSEditableTextComponent
179
+ */
180
+ this.fieldName = '';
181
+ /**
182
+ * Represents the content of the `contentlet` that can be edited
183
+ *
184
+ * @protected
185
+ * @memberof DotCMSEditableTextComponent
186
+ */
187
+ this.content = '';
188
+ this.#NotDotCMSHostMessage = 'The `dotCMSHost` parameter is not defined. Check that the UVE is sending the correct parameters.';
189
+ this.#sanitizer = inject(DomSanitizer);
190
+ this.#renderer = inject(Renderer2);
191
+ this.#elementRef = inject(ElementRef);
192
+ }
193
+ #NotDotCMSHostMessage;
194
+ #sanitizer;
195
+ #renderer;
196
+ #elementRef;
197
+ /**
198
+ * The TinyMCE editor
199
+ *
200
+ * @readonly
201
+ * @memberof DotCMSEditableTextComponent
202
+ */
203
+ get editor() {
204
+ return this.editorComponent?.editor;
205
+ }
206
+ /**
207
+ * Represents if the component is inside the editor
208
+ *
209
+ * @protected
210
+ * @type {boolean}
211
+ * @memberof DotCMSEditableTextComponent
212
+ */
213
+ get isEditMode() {
214
+ const { mode, dotCMSHost } = getUVEState() || {};
215
+ return mode === UVE_MODE.EDIT && dotCMSHost;
216
+ }
217
+ /**
218
+ * Returns the number of pages the contentlet is on
219
+ *
220
+ * @readonly
221
+ * @memberof DotCMSEditableTextComponent
222
+ */
223
+ get onNumberOfPages() {
224
+ return this.contentlet['onNumberOfPages'] || 1;
225
+ }
226
+ /**
227
+ * Handle copy contentlet inline editing success event
228
+ *
229
+ * @param {MessageEvent} { data }
230
+ * @return {*}
231
+ * @memberof DotCMSEditableTextComponent
232
+ */
233
+ onMessage({ data }) {
234
+ const { name, payload } = data;
235
+ if (name !== __DOTCMS_UVE_EVENT__.UVE_COPY_CONTENTLET_INLINE_EDITING_SUCCESS) {
236
+ return;
237
+ }
238
+ const { oldInode, inode } = payload;
239
+ const currentInode = this.contentlet.inode;
240
+ if (currentInode === oldInode || currentInode === inode) {
241
+ this.editorComponent.editor.focus();
242
+ return;
243
+ }
244
+ }
245
+ ngOnInit() {
246
+ const { dotCMSHost } = getUVEState() || {};
247
+ if (!this.isEditMode) {
248
+ this.innerHTMLToElement();
249
+ if (!dotCMSHost) {
250
+ console.warn(this.#NotDotCMSHostMessage);
251
+ }
252
+ return;
253
+ }
254
+ this.init = {
255
+ ...TINYMCE_CONFIG[this.mode],
256
+ base_url: `${dotCMSHost}/ext/tinymcev7`
257
+ };
258
+ }
259
+ ngOnChanges() {
260
+ this.content = this.contentlet[this.fieldName] || '';
261
+ if (this.editor) {
262
+ this.editor.setContent(this.content, { format: this.format });
263
+ }
264
+ }
265
+ /**
266
+ * Handle mouse down event
267
+ *
268
+ * @param {EventObj<MouseEvent>} { event }
269
+ * @return {*}
270
+ * @memberof DotCMSEditableTextComponent
271
+ */
272
+ onMouseDown({ event }) {
273
+ if (Number(this.onNumberOfPages) <= 1 || this.editorComponent.editor.hasFocus()) {
274
+ return;
275
+ }
276
+ const { inode, languageId: language } = this.contentlet;
277
+ event.stopPropagation();
278
+ event.preventDefault();
279
+ try {
280
+ sendMessageToUVE({
281
+ action: DotCMSUVEAction.COPY_CONTENTLET_INLINE_EDITING,
282
+ payload: {
283
+ dataset: {
284
+ inode,
285
+ language,
286
+ fieldName: this.fieldName
287
+ }
288
+ }
289
+ });
290
+ }
291
+ catch (error) {
292
+ console.error('Failed to post message to editor:', error);
293
+ }
294
+ }
295
+ /**
296
+ * Handle focus out event
297
+ *
298
+ * @return {*}
299
+ * @memberof DotCMSEditableTextComponent
300
+ */
301
+ onFocusOut() {
302
+ const content = this.editor.getContent({ format: this.format });
303
+ if (!this.editor.isDirty() || !this.didContentChange(content)) {
304
+ return;
305
+ }
306
+ const { inode, languageId: langId } = this.contentlet;
307
+ try {
308
+ sendMessageToUVE({
309
+ action: DotCMSUVEAction.UPDATE_CONTENTLET_INLINE_EDITING,
310
+ payload: {
311
+ content,
312
+ dataset: {
313
+ inode,
314
+ langId,
315
+ fieldName: this.fieldName
316
+ }
317
+ }
318
+ });
319
+ }
320
+ catch (error) {
321
+ console.error('Failed to post message to editor:', error);
322
+ }
323
+ }
324
+ /**
325
+ * inner HTML to element
326
+ *
327
+ * @private
328
+ * @param {string} editedContent
329
+ * @return {*}
330
+ * @memberof DotCMSEditableTextComponent
331
+ */
332
+ innerHTMLToElement() {
333
+ const element = this.#elementRef.nativeElement;
334
+ const safeHtml = this.#sanitizer.bypassSecurityTrustHtml(this.content);
335
+ const content = this.#sanitizer.sanitize(SecurityContext.HTML, safeHtml) || '';
336
+ this.#renderer.setProperty(element, 'innerHTML', content);
337
+ }
338
+ /**
339
+ * Check if the content has changed
340
+ *
341
+ * @private
342
+ * @param {string} editedContent
343
+ * @return {*}
344
+ * @memberof DotCMSEditableTextComponent
345
+ */
346
+ didContentChange(editedContent) {
347
+ return this.content !== editedContent;
348
+ }
349
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSEditableTextComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
350
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: DotCMSEditableTextComponent, isStandalone: true, selector: "dotcms-editable-text", inputs: { mode: "mode", format: "format", contentlet: "contentlet", fieldName: "fieldName" }, host: { listeners: { "window:message": "onMessage($event)" } }, providers: [
351
+ {
352
+ provide: TINYMCE_SCRIPT_SRC,
353
+ useFactory: () => {
354
+ const { dotCMSHost } = getUVEState() || {};
355
+ return `${dotCMSHost || ''}${__TINYMCE_PATH_ON_DOTCMS__}`;
356
+ }
357
+ }
358
+ ], viewQueries: [{ propertyName: "editorComponent", first: true, predicate: EditorComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (isEditMode) {\n <editor\n #tinyEditor\n [init]=\"init\"\n [initialValue]=\"content\"\n (onMouseDown)=\"onMouseDown($event)\"\n (onFocusOut)=\"onFocusOut()\" />\n}\n", styles: [":host ::ng-deep .mce-content-body:not(.mce-edit-focus):hover{outline:2px solid #006ce7;border-radius:4px}\n"], dependencies: [{ kind: "component", type: EditorComponent, selector: "editor", inputs: ["cloudChannel", "apiKey", "init", "id", "initialValue", "outputFormat", "inline", "tagName", "plugins", "toolbar", "modelEvents", "allowedEvents", "ignoreEvents", "disabled"] }] }); }
359
+ }
360
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSEditableTextComponent, decorators: [{
361
+ type: Component,
362
+ args: [{ selector: 'dotcms-editable-text', standalone: true, imports: [EditorComponent], providers: [
363
+ {
364
+ provide: TINYMCE_SCRIPT_SRC,
365
+ useFactory: () => {
366
+ const { dotCMSHost } = getUVEState() || {};
367
+ return `${dotCMSHost || ''}${__TINYMCE_PATH_ON_DOTCMS__}`;
368
+ }
369
+ }
370
+ ], template: "@if (isEditMode) {\n <editor\n #tinyEditor\n [init]=\"init\"\n [initialValue]=\"content\"\n (onMouseDown)=\"onMouseDown($event)\"\n (onFocusOut)=\"onFocusOut()\" />\n}\n", styles: [":host ::ng-deep .mce-content-body:not(.mce-edit-focus):hover{outline:2px solid #006ce7;border-radius:4px}\n"] }]
371
+ }], propDecorators: { editorComponent: [{
372
+ type: ViewChild,
373
+ args: [EditorComponent]
374
+ }], mode: [{
375
+ type: Input
376
+ }], format: [{
377
+ type: Input
378
+ }], contentlet: [{
379
+ type: Input
380
+ }], fieldName: [{
381
+ type: Input
382
+ }], onMessage: [{
383
+ type: HostListener,
384
+ args: ['window:message', ['$event']]
385
+ }] } });
386
+
387
+ class DotCodeBlock {
388
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCodeBlock, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
389
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: DotCodeBlock, isStandalone: true, selector: "dotcms-block-editor-renderer-code-block", ngImport: i0, template: `
390
+ <pre>
391
+ <code>
392
+ <ng-content />
393
+ </code>
394
+ </pre>
395
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
396
+ }
397
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCodeBlock, decorators: [{
398
+ type: Component,
399
+ args: [{
400
+ selector: 'dotcms-block-editor-renderer-code-block',
401
+ standalone: true,
402
+ template: `
403
+ <pre>
404
+ <code>
405
+ <ng-content />
406
+ </code>
407
+ </pre>
408
+ `,
409
+ changeDetection: ChangeDetectionStrategy.OnPush
410
+ }]
411
+ }] });
412
+ class DotBlockQuote {
413
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotBlockQuote, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
414
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: DotBlockQuote, isStandalone: true, selector: "dotcms-block-editor-renderer-block-quote", ngImport: i0, template: `
415
+ <blockquote>
416
+ <ng-content />
417
+ </blockquote>
418
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
419
+ }
420
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotBlockQuote, decorators: [{
421
+ type: Component,
422
+ args: [{
423
+ selector: 'dotcms-block-editor-renderer-block-quote',
424
+ standalone: true,
425
+ template: `
426
+ <blockquote>
427
+ <ng-content />
428
+ </blockquote>
429
+ `,
430
+ changeDetection: ChangeDetectionStrategy.OnPush
431
+ }]
432
+ }] });
433
+
434
+ class NoComponentProvided {
435
+ constructor() {
436
+ this.style = {
437
+ backgroundColor: '#fffaf0',
438
+ color: '#333',
439
+ padding: '1rem',
440
+ borderRadius: '0.5rem',
441
+ marginBottom: '1rem',
442
+ marginTop: '1rem',
443
+ border: '1px solid #ed8936'
444
+ };
445
+ }
446
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: NoComponentProvided, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
447
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: NoComponentProvided, isStandalone: true, selector: "dotcms-no-component-provided", inputs: { contentType: "contentType" }, ngImport: i0, template: `
448
+ <div data-testid="no-component-provided" [style]="style">
449
+ <strong style="color: #c05621">Dev Warning</strong>
450
+ : No component or custom renderer provided for content type
451
+ <strong style="color: #c05621">{{ contentType || 'Unknown' }}</strong>
452
+ .
453
+ <br />
454
+ Please refer to the
455
+ <a
456
+ href="https://dev.dotcms.com/docs/block-editor"
457
+ target="_blank"
458
+ rel="noopener noreferrer"
459
+ style="color: #c05621">
460
+ Block Editor Custom Renderers Documentation
461
+ </a>
462
+ for guidance.
463
+ </div>
464
+ `, isInline: true }); }
465
+ }
466
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: NoComponentProvided, decorators: [{
467
+ type: Component,
468
+ args: [{
469
+ selector: 'dotcms-no-component-provided',
470
+ standalone: true,
471
+ template: `
472
+ <div data-testid="no-component-provided" [style]="style">
473
+ <strong style="color: #c05621">Dev Warning</strong>
474
+ : No component or custom renderer provided for content type
475
+ <strong style="color: #c05621">{{ contentType || 'Unknown' }}</strong>
476
+ .
477
+ <br />
478
+ Please refer to the
479
+ <a
480
+ href="https://dev.dotcms.com/docs/block-editor"
481
+ target="_blank"
482
+ rel="noopener noreferrer"
483
+ style="color: #c05621">
484
+ Block Editor Custom Renderers Documentation
485
+ </a>
486
+ for guidance.
487
+ </div>
488
+ `
489
+ }]
490
+ }], propDecorators: { contentType: [{
491
+ type: Input
492
+ }] } });
493
+ /**
494
+ * DotContent component that renders content based on content type
495
+ */
496
+ class DotContentletBlock {
497
+ constructor() {
498
+ this.$data = computed(() => this.attrs?.['data']);
499
+ this.DOT_CONTENT_NO_DATA_MESSAGE = '[DotCMSBlockEditorRenderer]: No data provided for Contentlet Block. Try to add a contentlet to the block editor. If the error persists, please contact the DotCMS support team.';
500
+ this.DOT_CONTENT_NO_MATCHING_COMPONENT_MESSAGE = (contentType) => `[DotCMSBlockEditorRenderer]: No matching component found for content type: ${contentType}. Provide a custom renderer for this content type to fix this error.`;
501
+ }
502
+ get isDevMode() {
503
+ return getUVEState()?.mode === UVE_MODE.EDIT;
504
+ }
505
+ ngOnInit() {
506
+ if (!this.$data()) {
507
+ console.error(this.DOT_CONTENT_NO_DATA_MESSAGE);
508
+ return;
509
+ }
510
+ const contentType = this.$data()?.contentType || '';
511
+ this.contentComponent = this.customRenderers?.[contentType];
512
+ if (!this.contentComponent) {
513
+ console.warn(this.DOT_CONTENT_NO_MATCHING_COMPONENT_MESSAGE(contentType));
514
+ }
515
+ }
516
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotContentletBlock, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
517
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: DotContentletBlock, isStandalone: true, selector: "dotcms-block-editor-renderer-contentlet", inputs: { customRenderers: "customRenderers", attrs: "attrs" }, ngImport: i0, template: `
518
+ @if (contentComponent) {
519
+ <ng-container
520
+ *ngComponentOutlet="
521
+ contentComponent | async;
522
+ inputs: { contentlet: $data() }
523
+ "></ng-container>
524
+ } @else if (isDevMode) {
525
+ <dotcms-no-component-provided [contentType]="$data()?.contentType" />
526
+ }
527
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "component", type: NoComponentProvided, selector: "dotcms-no-component-provided", inputs: ["contentType"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
528
+ }
529
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotContentletBlock, decorators: [{
530
+ type: Component,
531
+ args: [{
532
+ selector: 'dotcms-block-editor-renderer-contentlet',
533
+ standalone: true,
534
+ imports: [NgComponentOutlet, AsyncPipe, NoComponentProvided],
535
+ changeDetection: ChangeDetectionStrategy.OnPush,
536
+ template: `
537
+ @if (contentComponent) {
538
+ <ng-container
539
+ *ngComponentOutlet="
540
+ contentComponent | async;
541
+ inputs: { contentlet: $data() }
542
+ "></ng-container>
543
+ } @else if (isDevMode) {
544
+ <dotcms-no-component-provided [contentType]="$data()?.contentType" />
545
+ }
546
+ `
547
+ }]
548
+ }], propDecorators: { customRenderers: [{
549
+ type: Input
550
+ }], attrs: [{
551
+ type: Input
552
+ }] } });
553
+
554
+ class DotImageBlock {
555
+ constructor() {
556
+ this.$srcURL = computed(() => this.attrs?.['src']);
557
+ }
558
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotImageBlock, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
559
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: DotImageBlock, isStandalone: true, selector: "dotcms-block-editor-renderer-image", inputs: { attrs: "attrs" }, ngImport: i0, template: `
560
+ <img [alt]="attrs?.['alt']" [src]="$srcURL()" />
561
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
562
+ }
563
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotImageBlock, decorators: [{
564
+ type: Component,
565
+ args: [{
566
+ selector: 'dotcms-block-editor-renderer-image',
567
+ standalone: true,
568
+ template: `
569
+ <img [alt]="attrs?.['alt']" [src]="$srcURL()" />
570
+ `,
571
+ changeDetection: ChangeDetectionStrategy.OnPush
572
+ }]
573
+ }], propDecorators: { attrs: [{
574
+ type: Input
575
+ }] } });
576
+
577
+ class DotBulletList {
578
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotBulletList, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
579
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: DotBulletList, isStandalone: true, selector: "dotcms-block-editor-renderer-bullet-list", ngImport: i0, template: `
580
+ <ul>
581
+ <ng-content />
582
+ </ul>
583
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
584
+ }
585
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotBulletList, decorators: [{
586
+ type: Component,
587
+ args: [{
588
+ selector: 'dotcms-block-editor-renderer-bullet-list',
589
+ standalone: true,
590
+ changeDetection: ChangeDetectionStrategy.OnPush,
591
+ template: `
592
+ <ul>
593
+ <ng-content />
594
+ </ul>
595
+ `
596
+ }]
597
+ }] });
598
+ class DotOrdererList {
599
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotOrdererList, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
600
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: DotOrdererList, isStandalone: true, selector: "dotcms-block-editor-renderer-ordered-list", ngImport: i0, template: `
601
+ <ol>
602
+ <ng-content />
603
+ </ol>
604
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
605
+ }
606
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotOrdererList, decorators: [{
607
+ type: Component,
608
+ args: [{
609
+ selector: 'dotcms-block-editor-renderer-ordered-list',
610
+ standalone: true,
611
+ changeDetection: ChangeDetectionStrategy.OnPush,
612
+ template: `
613
+ <ol>
614
+ <ng-content />
615
+ </ol>
616
+ `
617
+ }]
618
+ }] });
619
+ class DotListItem {
620
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotListItem, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
621
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: DotListItem, isStandalone: true, selector: "dotcms-block-editor-renderer-list-item", ngImport: i0, template: `
622
+ <li>
623
+ <ng-content />
624
+ </li>
625
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
626
+ }
627
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotListItem, decorators: [{
628
+ type: Component,
629
+ args: [{
630
+ selector: 'dotcms-block-editor-renderer-list-item',
631
+ standalone: true,
632
+ changeDetection: ChangeDetectionStrategy.OnPush,
633
+ template: `
634
+ <li>
635
+ <ng-content />
636
+ </li>
637
+ `
638
+ }]
639
+ }] });
640
+
641
+ class DotTableBlock {
642
+ constructor() {
643
+ this.blockEditorItem = DotCMSBlockEditorItemComponent;
644
+ }
645
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotTableBlock, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
646
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: DotTableBlock, isStandalone: true, selector: "dotcms-block-editor-renderer-table", inputs: { content: "content" }, ngImport: i0, template: `
647
+ <table>
648
+ <thead>
649
+ @for (rowNode of content?.slice(0, 1); track rowNode.type) {
650
+ <tr>
651
+ @for (cellNode of rowNode.content; track cellNode.type) {
652
+ <th
653
+ [attr.colspan]="cellNode.attrs?.['colspan'] || 1"
654
+ [attr.rowspan]="cellNode.attrs?.['rowspan'] || 1">
655
+ <ng-container
656
+ *ngComponentOutlet="
657
+ blockEditorItem;
658
+ inputs: { content: cellNode.content }
659
+ "></ng-container>
660
+ </th>
661
+ }
662
+ </tr>
663
+ }
664
+ </thead>
665
+ <tbody>
666
+ @for (rowNode of content?.slice(1); track rowNode.type) {
667
+ <tr>
668
+ @for (cellNode of rowNode.content; track cellNode.type) {
669
+ <td
670
+ [attr.colspan]="cellNode.attrs?.['colspan'] || 1"
671
+ [attr.rowspan]="cellNode.attrs?.['rowspan'] || 1">
672
+ <ng-container
673
+ *ngComponentOutlet="
674
+ blockEditorItem;
675
+ inputs: { content: cellNode.content }
676
+ "></ng-container>
677
+ </td>
678
+ }
679
+ </tr>
680
+ }
681
+ </tbody>
682
+ </table>
683
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }] }); }
684
+ }
685
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotTableBlock, decorators: [{
686
+ type: Component,
687
+ args: [{
688
+ selector: 'dotcms-block-editor-renderer-table',
689
+ standalone: true,
690
+ imports: [NgComponentOutlet],
691
+ template: `
692
+ <table>
693
+ <thead>
694
+ @for (rowNode of content?.slice(0, 1); track rowNode.type) {
695
+ <tr>
696
+ @for (cellNode of rowNode.content; track cellNode.type) {
697
+ <th
698
+ [attr.colspan]="cellNode.attrs?.['colspan'] || 1"
699
+ [attr.rowspan]="cellNode.attrs?.['rowspan'] || 1">
700
+ <ng-container
701
+ *ngComponentOutlet="
702
+ blockEditorItem;
703
+ inputs: { content: cellNode.content }
704
+ "></ng-container>
705
+ </th>
706
+ }
707
+ </tr>
708
+ }
709
+ </thead>
710
+ <tbody>
711
+ @for (rowNode of content?.slice(1); track rowNode.type) {
712
+ <tr>
713
+ @for (cellNode of rowNode.content; track cellNode.type) {
714
+ <td
715
+ [attr.colspan]="cellNode.attrs?.['colspan'] || 1"
716
+ [attr.rowspan]="cellNode.attrs?.['rowspan'] || 1">
717
+ <ng-container
718
+ *ngComponentOutlet="
719
+ blockEditorItem;
720
+ inputs: { content: cellNode.content }
721
+ "></ng-container>
722
+ </td>
723
+ }
724
+ </tr>
725
+ }
726
+ </tbody>
727
+ </table>
728
+ `
729
+ }]
730
+ }], propDecorators: { content: [{
731
+ type: Input
732
+ }] } });
733
+
734
+ class DotParagraphBlock {
735
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotParagraphBlock, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
736
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: DotParagraphBlock, isStandalone: true, selector: "dotcms-block-editor-renderer-paragraph", ngImport: i0, template: `
737
+ <p>
738
+ <ng-content />
739
+ </p>
740
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
741
+ }
742
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotParagraphBlock, decorators: [{
743
+ type: Component,
744
+ args: [{
745
+ selector: 'dotcms-block-editor-renderer-paragraph',
746
+ standalone: true,
747
+ changeDetection: ChangeDetectionStrategy.OnPush,
748
+ template: `
749
+ <p>
750
+ <ng-content />
751
+ </p>
752
+ `
753
+ }]
754
+ }] });
755
+ class DotHeadingBlock {
756
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotHeadingBlock, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
757
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: DotHeadingBlock, isStandalone: true, selector: "dotcms-block-editor-renderer-heading", inputs: { level: "level" }, ngImport: i0, template: `
758
+ @switch (level) {
759
+ @case ('1') {
760
+ <h1>
761
+ <ng-content />
762
+ </h1>
763
+ }
764
+ @case ('2') {
765
+ <h2>
766
+ <ng-content />
767
+ </h2>
768
+ }
769
+ @case ('3') {
770
+ <h3>
771
+ <ng-content />
772
+ </h3>
773
+ }
774
+ @case ('4') {
775
+ <h4>
776
+ <ng-content />
777
+ </h4>
778
+ }
779
+ @case ('5') {
780
+ <h5>
781
+ <ng-content />
782
+ </h5>
783
+ }
784
+ @case ('6') {
785
+ <h6>
786
+ <ng-content />
787
+ </h6>
788
+ }
789
+ @default {
790
+ <h1>
791
+ <ng-content />
792
+ </h1>
793
+ }
794
+ }
795
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
796
+ }
797
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotHeadingBlock, decorators: [{
798
+ type: Component,
799
+ args: [{
800
+ selector: 'dotcms-block-editor-renderer-heading',
801
+ standalone: true,
802
+ changeDetection: ChangeDetectionStrategy.OnPush,
803
+ template: `
804
+ @switch (level) {
805
+ @case ('1') {
806
+ <h1>
807
+ <ng-content />
808
+ </h1>
809
+ }
810
+ @case ('2') {
811
+ <h2>
812
+ <ng-content />
813
+ </h2>
814
+ }
815
+ @case ('3') {
816
+ <h3>
817
+ <ng-content />
818
+ </h3>
819
+ }
820
+ @case ('4') {
821
+ <h4>
822
+ <ng-content />
823
+ </h4>
824
+ }
825
+ @case ('5') {
826
+ <h5>
827
+ <ng-content />
828
+ </h5>
829
+ }
830
+ @case ('6') {
831
+ <h6>
832
+ <ng-content />
833
+ </h6>
834
+ }
835
+ @default {
836
+ <h1>
837
+ <ng-content />
838
+ </h1>
839
+ }
840
+ }
841
+ `
842
+ }]
843
+ }], propDecorators: { level: [{
844
+ type: Input
845
+ }] } });
846
+ class DotTextBlock {
847
+ constructor() {
848
+ this.marks = [];
849
+ this.text = '';
850
+ this.$remainingMarks = computed(() => this.marks?.slice(1));
851
+ this.$currentAttrs = computed(() => {
852
+ const attrs = { ...(this.marks?.[0]?.attrs || {}) };
853
+ if (attrs['class']) {
854
+ attrs['className'] = attrs['class'];
855
+ delete attrs['class'];
856
+ }
857
+ return attrs;
858
+ });
859
+ }
860
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotTextBlock, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
861
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: DotTextBlock, isStandalone: true, selector: "dotcms-block-editor-renderer-text", inputs: { marks: "marks", text: "text" }, ngImport: i0, template: `
862
+ @switch (marks?.[0]?.type) {
863
+ @case ('link') {
864
+ <a
865
+ [attr.href]="$currentAttrs()['href'] || ''"
866
+ [attr.target]="$currentAttrs()['target'] || ''">
867
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
868
+ </a>
869
+ }
870
+ @case ('bold') {
871
+ <strong>
872
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
873
+ </strong>
874
+ }
875
+ @case ('underline') {
876
+ <u>
877
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
878
+ </u>
879
+ }
880
+ @case ('italic') {
881
+ <em>
882
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
883
+ </em>
884
+ }
885
+ @case ('strike') {
886
+ <s>
887
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
888
+ </s>
889
+ }
890
+ @case ('superscript') {
891
+ <sup>
892
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
893
+ </sup>
894
+ }
895
+ @case ('subscript') {
896
+ <sub>
897
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
898
+ </sub>
899
+ }
900
+ @default {
901
+ {{ text }}
902
+ }
903
+ }
904
+ `, isInline: true, dependencies: [{ kind: "component", type: DotTextBlock, selector: "dotcms-block-editor-renderer-text", inputs: ["marks", "text"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
905
+ }
906
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotTextBlock, decorators: [{
907
+ type: Component,
908
+ args: [{
909
+ selector: 'dotcms-block-editor-renderer-text',
910
+ standalone: true,
911
+ changeDetection: ChangeDetectionStrategy.OnPush,
912
+ template: `
913
+ @switch (marks?.[0]?.type) {
914
+ @case ('link') {
915
+ <a
916
+ [attr.href]="$currentAttrs()['href'] || ''"
917
+ [attr.target]="$currentAttrs()['target'] || ''">
918
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
919
+ </a>
920
+ }
921
+ @case ('bold') {
922
+ <strong>
923
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
924
+ </strong>
925
+ }
926
+ @case ('underline') {
927
+ <u>
928
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
929
+ </u>
930
+ }
931
+ @case ('italic') {
932
+ <em>
933
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
934
+ </em>
935
+ }
936
+ @case ('strike') {
937
+ <s>
938
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
939
+ </s>
940
+ }
941
+ @case ('superscript') {
942
+ <sup>
943
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
944
+ </sup>
945
+ }
946
+ @case ('subscript') {
947
+ <sub>
948
+ <dotcms-block-editor-renderer-text [marks]="$remainingMarks()" [text]="text" />
949
+ </sub>
950
+ }
951
+ @default {
952
+ {{ text }}
953
+ }
954
+ }
955
+ `
956
+ }]
957
+ }], propDecorators: { marks: [{
958
+ type: Input
959
+ }], text: [{
960
+ type: Input
961
+ }] } });
962
+
963
+ class DotUnknownBlockComponent {
964
+ constructor() {
965
+ this.style = {
966
+ backgroundColor: '#fff5f5',
967
+ color: '#333',
968
+ padding: '1rem',
969
+ borderRadius: '0.5rem',
970
+ marginBottom: '1rem',
971
+ marginTop: '1rem',
972
+ border: '1px solid #fc8181'
973
+ };
974
+ }
975
+ get isEditMode() {
976
+ return getUVEState()?.mode === UVE_MODE.EDIT;
977
+ }
978
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotUnknownBlockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
979
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: DotUnknownBlockComponent, isStandalone: true, selector: "dotcms-block-editor-renderer-unknown", inputs: { node: "node" }, ngImport: i0, template: `
980
+ @if (isEditMode) {
981
+ <div [style]="style" data-testid="unknown-block-type">
982
+ <strong style="color: #c53030">Warning:</strong>
983
+ The block type
984
+ <strong>{{ node.type }}</strong>
985
+ is not recognized. Please check your
986
+ <a
987
+ href="https://dev.dotcms.com/docs/block-editor"
988
+ target="_blank"
989
+ rel="noopener noreferrer">
990
+ configuration
991
+ </a>
992
+ or contact support for assistance.
993
+ </div>
994
+ }
995
+ `, isInline: true }); }
996
+ }
997
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotUnknownBlockComponent, decorators: [{
998
+ type: Component,
999
+ args: [{
1000
+ selector: 'dotcms-block-editor-renderer-unknown',
1001
+ standalone: true,
1002
+ template: `
1003
+ @if (isEditMode) {
1004
+ <div [style]="style" data-testid="unknown-block-type">
1005
+ <strong style="color: #c53030">Warning:</strong>
1006
+ The block type
1007
+ <strong>{{ node.type }}</strong>
1008
+ is not recognized. Please check your
1009
+ <a
1010
+ href="https://dev.dotcms.com/docs/block-editor"
1011
+ target="_blank"
1012
+ rel="noopener noreferrer">
1013
+ configuration
1014
+ </a>
1015
+ or contact support for assistance.
1016
+ </div>
1017
+ }
1018
+ `
1019
+ }]
1020
+ }], propDecorators: { node: [{
1021
+ type: Input
1022
+ }] } });
1023
+
1024
+ class DotVideoBlock {
1025
+ constructor() {
1026
+ this.$srcURL = computed(() => this.attrs?.['src']);
1027
+ this.$posterURL = computed(() => this.attrs?.['data']?.['thumbnail']);
1028
+ }
1029
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotVideoBlock, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1030
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: DotVideoBlock, isStandalone: true, selector: "dotcms-block-editor-renderer-video", inputs: { attrs: "attrs" }, ngImport: i0, template: `
1031
+ <video
1032
+ [controls]="true"
1033
+ preload="metadata"
1034
+ [poster]="this.$posterURL()"
1035
+ [width]="attrs?.['width']"
1036
+ [height]="attrs?.['height']">
1037
+ <track default kind="captions" srclang="en" />
1038
+ <source [src]="this.$srcURL()" [type]="attrs?.['mimeType']" />
1039
+ Your browser does not support the
1040
+ <code>video</code>
1041
+ element.
1042
+ </video>
1043
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1044
+ }
1045
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotVideoBlock, decorators: [{
1046
+ type: Component,
1047
+ args: [{
1048
+ selector: 'dotcms-block-editor-renderer-video',
1049
+ standalone: true,
1050
+ changeDetection: ChangeDetectionStrategy.OnPush,
1051
+ template: `
1052
+ <video
1053
+ [controls]="true"
1054
+ preload="metadata"
1055
+ [poster]="this.$posterURL()"
1056
+ [width]="attrs?.['width']"
1057
+ [height]="attrs?.['height']">
1058
+ <track default kind="captions" srclang="en" />
1059
+ <source [src]="this.$srcURL()" [type]="attrs?.['mimeType']" />
1060
+ Your browser does not support the
1061
+ <code>video</code>
1062
+ element.
1063
+ </video>
1064
+ `
1065
+ }]
1066
+ }], propDecorators: { attrs: [{
1067
+ type: Input
1068
+ }] } });
1069
+
1070
+ class DotCMSBlockEditorItemComponent {
1071
+ constructor() {
1072
+ this.BLOCKS = BlockEditorDefaultBlocks;
1073
+ }
1074
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSBlockEditorItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1075
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: DotCMSBlockEditorItemComponent, isStandalone: true, selector: "dotcms-block-editor-renderer-block", inputs: { content: "content", customRenderers: "customRenderers" }, ngImport: i0, template: "@for (node of content; track node) {\n @if (customRenderers?.[node.type]) {\n <ng-container\n *ngTemplateOutlet=\"\n customRender;\n context: { customRender: customRenderers?.[node.type], node: node }\n \"></ng-container>\n } @else {\n @switch (node.type) {\n @case (BLOCKS.PARAGRAPH) {\n <dotcms-block-editor-renderer-paragraph [style]=\"node.attrs\">\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-paragraph>\n }\n\n @case (BLOCKS.TEXT) {\n <dotcms-block-editor-renderer-text [marks]=\"node.marks\" [text]=\"node.text || ''\" />\n }\n\n @case (BLOCKS.HEADING) {\n <dotcms-block-editor-renderer-heading\n [style]=\"node.attrs || {}\"\n [level]=\"node.attrs?.['level'] || '1'\">\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-heading>\n }\n\n @case (BLOCKS.BULLET_LIST) {\n <dotcms-block-editor-renderer-bullet-list>\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-bullet-list>\n }\n\n @case (BLOCKS.ORDERED_LIST) {\n <dotcms-block-editor-renderer-ordered-list>\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-ordered-list>\n }\n\n @case (BLOCKS.LIST_ITEM) {\n <dotcms-block-editor-renderer-list-item>\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-list-item>\n }\n\n @case (BLOCKS.BLOCK_QUOTE) {\n <dotcms-block-editor-renderer-block-quote>\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-block-quote>\n }\n\n @case (BLOCKS.CODE_BLOCK) {\n <dotcms-block-editor-renderer-code-block>\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-code-block>\n }\n\n @case (BLOCKS.HARDBREAK) {\n <br />\n }\n\n @case (BLOCKS.HORIZONTAL_RULE) {\n <hr />\n }\n\n @case (BLOCKS.DOT_IMAGE) {\n <dotcms-block-editor-renderer-image [attrs]=\"node.attrs || {}\" />\n }\n\n @case (BLOCKS.DOT_VIDEO) {\n <dotcms-block-editor-renderer-video [attrs]=\"node.attrs || {}\" />\n }\n\n @case (BLOCKS.TABLE) {\n <dotcms-block-editor-renderer-table [content]=\"node.content\" />\n }\n\n @case (BLOCKS.DOT_CONTENT) {\n <dotcms-block-editor-renderer-contentlet\n [attrs]=\"node.attrs || {}\"\n [customRenderers]=\"customRenderers\" />\n }\n\n @default {\n <dotcms-block-editor-renderer-unknown [node]=\"node\" />\n }\n }\n }\n}\n\n<ng-template #customRender let-customRender=\"customRender\" let-node=\"node\">\n <ng-container\n *ngComponentOutlet=\"customRender | async; inputs: { content: node }\"></ng-container>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: DotCMSBlockEditorItemComponent, selector: "dotcms-block-editor-renderer-block", inputs: ["content", "customRenderers"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "component", type: DotParagraphBlock, selector: "dotcms-block-editor-renderer-paragraph" }, { kind: "component", type: DotTextBlock, selector: "dotcms-block-editor-renderer-text", inputs: ["marks", "text"] }, { kind: "component", type: DotHeadingBlock, selector: "dotcms-block-editor-renderer-heading", inputs: ["level"] }, { kind: "component", type: DotBulletList, selector: "dotcms-block-editor-renderer-bullet-list" }, { kind: "component", type: DotOrdererList, selector: "dotcms-block-editor-renderer-ordered-list" }, { kind: "component", type: DotListItem, selector: "dotcms-block-editor-renderer-list-item" }, { kind: "component", type: DotCodeBlock, selector: "dotcms-block-editor-renderer-code-block" }, { kind: "component", type: DotBlockQuote, selector: "dotcms-block-editor-renderer-block-quote" }, { kind: "component", type: DotImageBlock, selector: "dotcms-block-editor-renderer-image", inputs: ["attrs"] }, { kind: "component", type: DotVideoBlock, selector: "dotcms-block-editor-renderer-video", inputs: ["attrs"] }, { kind: "component", type: DotTableBlock, selector: "dotcms-block-editor-renderer-table", inputs: ["content"] }, { kind: "component", type: DotContentletBlock, selector: "dotcms-block-editor-renderer-contentlet", inputs: ["customRenderers", "attrs"] }, { kind: "component", type: DotUnknownBlockComponent, selector: "dotcms-block-editor-renderer-unknown", inputs: ["node"] }] }); }
1076
+ }
1077
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSBlockEditorItemComponent, decorators: [{
1078
+ type: Component,
1079
+ args: [{ selector: 'dotcms-block-editor-renderer-block', standalone: true, imports: [
1080
+ NgTemplateOutlet,
1081
+ NgComponentOutlet,
1082
+ AsyncPipe,
1083
+ DotParagraphBlock,
1084
+ DotTextBlock,
1085
+ DotHeadingBlock,
1086
+ DotBulletList,
1087
+ DotOrdererList,
1088
+ DotListItem,
1089
+ DotCodeBlock,
1090
+ DotBlockQuote,
1091
+ DotImageBlock,
1092
+ DotVideoBlock,
1093
+ DotTableBlock,
1094
+ DotContentletBlock,
1095
+ DotUnknownBlockComponent
1096
+ ], template: "@for (node of content; track node) {\n @if (customRenderers?.[node.type]) {\n <ng-container\n *ngTemplateOutlet=\"\n customRender;\n context: { customRender: customRenderers?.[node.type], node: node }\n \"></ng-container>\n } @else {\n @switch (node.type) {\n @case (BLOCKS.PARAGRAPH) {\n <dotcms-block-editor-renderer-paragraph [style]=\"node.attrs\">\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-paragraph>\n }\n\n @case (BLOCKS.TEXT) {\n <dotcms-block-editor-renderer-text [marks]=\"node.marks\" [text]=\"node.text || ''\" />\n }\n\n @case (BLOCKS.HEADING) {\n <dotcms-block-editor-renderer-heading\n [style]=\"node.attrs || {}\"\n [level]=\"node.attrs?.['level'] || '1'\">\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-heading>\n }\n\n @case (BLOCKS.BULLET_LIST) {\n <dotcms-block-editor-renderer-bullet-list>\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-bullet-list>\n }\n\n @case (BLOCKS.ORDERED_LIST) {\n <dotcms-block-editor-renderer-ordered-list>\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-ordered-list>\n }\n\n @case (BLOCKS.LIST_ITEM) {\n <dotcms-block-editor-renderer-list-item>\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-list-item>\n }\n\n @case (BLOCKS.BLOCK_QUOTE) {\n <dotcms-block-editor-renderer-block-quote>\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-block-quote>\n }\n\n @case (BLOCKS.CODE_BLOCK) {\n <dotcms-block-editor-renderer-code-block>\n <dotcms-block-editor-renderer-block\n [content]=\"node.content\"\n [customRenderers]=\"customRenderers\" />\n </dotcms-block-editor-renderer-code-block>\n }\n\n @case (BLOCKS.HARDBREAK) {\n <br />\n }\n\n @case (BLOCKS.HORIZONTAL_RULE) {\n <hr />\n }\n\n @case (BLOCKS.DOT_IMAGE) {\n <dotcms-block-editor-renderer-image [attrs]=\"node.attrs || {}\" />\n }\n\n @case (BLOCKS.DOT_VIDEO) {\n <dotcms-block-editor-renderer-video [attrs]=\"node.attrs || {}\" />\n }\n\n @case (BLOCKS.TABLE) {\n <dotcms-block-editor-renderer-table [content]=\"node.content\" />\n }\n\n @case (BLOCKS.DOT_CONTENT) {\n <dotcms-block-editor-renderer-contentlet\n [attrs]=\"node.attrs || {}\"\n [customRenderers]=\"customRenderers\" />\n }\n\n @default {\n <dotcms-block-editor-renderer-unknown [node]=\"node\" />\n }\n }\n }\n}\n\n<ng-template #customRender let-customRender=\"customRender\" let-node=\"node\">\n <ng-container\n *ngComponentOutlet=\"customRender | async; inputs: { content: node }\"></ng-container>\n</ng-template>\n" }]
1097
+ }], propDecorators: { content: [{
1098
+ type: Input
1099
+ }], customRenderers: [{
1100
+ type: Input
1101
+ }] } });
1102
+
1103
+ /**
1104
+ * A component that renders content from DotCMS's Block Editor field.
1105
+ *
1106
+ * This component provides an easy way to render Block Editor content in your Angular applications.
1107
+ * It handles the rendering of standard blocks and allows customization through custom renderers.
1108
+ *
1109
+ * For more information about Block Editor, see {@link https://dev.dotcms.com/docs/block-editor}
1110
+ *
1111
+ * @example
1112
+ * ```html
1113
+ * <dotcms-block-editor-renderer
1114
+ * [blocks]="myBlockEditorContent"
1115
+ * [customRenderers]="myCustomRenderers">
1116
+ * </dotcms-block-editor-renderer>
1117
+ * ```
1118
+ */
1119
+ class DotCMSBlockEditorRendererComponent {
1120
+ constructor() {
1121
+ this.$blockEditorState = signal({ error: null });
1122
+ this.$isInEditMode = signal(getUVEState()?.mode === UVE_MODE.EDIT);
1123
+ }
1124
+ ngOnInit() {
1125
+ const state = isValidBlocks(this.blocks);
1126
+ if (state.error) {
1127
+ console.error('Error in dotcms-block-editor-renderer: ', state.error);
1128
+ }
1129
+ this.$blockEditorState.set(isValidBlocks(this.blocks));
1130
+ }
1131
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSBlockEditorRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1132
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: DotCMSBlockEditorRendererComponent, isStandalone: true, selector: "dotcms-block-editor-renderer", inputs: { blocks: "blocks", customRenderers: "customRenderers", class: "class", style: "style" }, ngImport: i0, template: "@if ($blockEditorState().error && $isInEditMode()) {\n <div data-testid=\"invalid-blocks-message\">\n {{ $blockEditorState().error }}\n </div>\n} @else if (!$blockEditorState().error) {\n <div [class]=\"class\" [style]=\"style\">\n <dotcms-block-editor-renderer-block\n [content]=\"blocks.content\"\n [customRenderers]=\"customRenderers\" />\n </div>\n}\n", styles: [""], dependencies: [{ kind: "component", type: DotCMSBlockEditorItemComponent, selector: "dotcms-block-editor-renderer-block", inputs: ["content", "customRenderers"] }] }); }
1133
+ }
1134
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSBlockEditorRendererComponent, decorators: [{
1135
+ type: Component,
1136
+ args: [{ selector: 'dotcms-block-editor-renderer', standalone: true, imports: [DotCMSBlockEditorItemComponent], template: "@if ($blockEditorState().error && $isInEditMode()) {\n <div data-testid=\"invalid-blocks-message\">\n {{ $blockEditorState().error }}\n </div>\n} @else if (!$blockEditorState().error) {\n <div [class]=\"class\" [style]=\"style\">\n <dotcms-block-editor-renderer-block\n [content]=\"blocks.content\"\n [customRenderers]=\"customRenderers\" />\n </div>\n}\n" }]
1137
+ }], propDecorators: { blocks: [{
1138
+ type: Input
1139
+ }], customRenderers: [{
1140
+ type: Input
1141
+ }], class: [{
1142
+ type: Input
1143
+ }], style: [{
1144
+ type: Input
1145
+ }] } });
1146
+
1147
+ /**
1148
+ * @description This component is used to display a message when a page is missing the required `layout.body` property.
1149
+ * @internal
1150
+ * @class PageErrorMessageComponent
1151
+ */
1152
+ class PageErrorMessageComponent {
1153
+ ngOnInit() {
1154
+ console.warn('Missing required layout.body property in page');
1155
+ }
1156
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: PageErrorMessageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1157
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: PageErrorMessageComponent, isStandalone: true, selector: "dotcms-page-error-message", ngImport: i0, template: `
1158
+ <div
1159
+ data-testid="error-message"
1160
+ style="padding: 1rem; border: 1px solid #e0e0e0; border-radius: 4px;">
1161
+ <p style="margin: 0 0 0.5rem; color: #666;">
1162
+ The
1163
+ <code>page</code>
1164
+ is missing the required
1165
+ <code>layout.body</code>
1166
+ property.
1167
+ </p>
1168
+ <p style="margin: 0; color: #666;">
1169
+ Make sure the page asset is properly loaded and includes a layout configuration.
1170
+ </p>
1171
+ </div>
1172
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1173
+ }
1174
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: PageErrorMessageComponent, decorators: [{
1175
+ type: Component,
1176
+ args: [{
1177
+ selector: 'dotcms-page-error-message',
1178
+ standalone: true,
1179
+ imports: [],
1180
+ template: `
1181
+ <div
1182
+ data-testid="error-message"
1183
+ style="padding: 1rem; border: 1px solid #e0e0e0; border-radius: 4px;">
1184
+ <p style="margin: 0 0 0.5rem; color: #666;">
1185
+ The
1186
+ <code>page</code>
1187
+ is missing the required
1188
+ <code>layout.body</code>
1189
+ property.
1190
+ </p>
1191
+ <p style="margin: 0; color: #666;">
1192
+ Make sure the page asset is properly loaded and includes a layout configuration.
1193
+ </p>
1194
+ </div>
1195
+ `,
1196
+ changeDetection: ChangeDetectionStrategy.OnPush
1197
+ }]
1198
+ }] });
1199
+
1200
+ const EMPTY_DOTCMS_PAGE_STORE = {
1201
+ page: {},
1202
+ components: {},
1203
+ mode: PRODUCTION_MODE
1204
+ };
1205
+ /**
1206
+ * @description This service is responsible for managing the page context.
1207
+ * @internal
1208
+ * @author dotCMS
1209
+ * @export
1210
+ * @class DotCMSStore
1211
+ */
1212
+ class DotCMSStore {
1213
+ constructor() {
1214
+ this.$store = signal(EMPTY_DOTCMS_PAGE_STORE);
1215
+ /**
1216
+ * @description Get if the current context is in development mode
1217
+ * @readonly
1218
+ * @type {boolean}
1219
+ * @memberof DotCMSStore
1220
+ */
1221
+ this.$isDevMode = computed(() => {
1222
+ const uveState = getUVEState();
1223
+ if (uveState?.mode) {
1224
+ return uveState?.mode === UVE_MODE.EDIT;
1225
+ }
1226
+ return this.$store()?.mode === DEVELOPMENT_MODE;
1227
+ });
1228
+ }
1229
+ /**
1230
+ * @description Get the store
1231
+ * @readonly
1232
+ * @type {DotCMSPageStore}
1233
+ * @memberof DotCMSStore
1234
+ */
1235
+ get store() {
1236
+ return this.$store();
1237
+ }
1238
+ /**
1239
+ * @description Set the store
1240
+ * @param {DotCMSPageStore} value
1241
+ * @memberof DotCMSStore
1242
+ */
1243
+ setStore(store) {
1244
+ this.$store.set(store);
1245
+ }
1246
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1247
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSStore, providedIn: 'root' }); }
1248
+ }
1249
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSStore, decorators: [{
1250
+ type: Injectable,
1251
+ args: [{
1252
+ providedIn: 'root'
1253
+ }]
1254
+ }] });
1255
+
1256
+ /**
1257
+ * @description This component is used to display a message when a container is not found.
1258
+ * @export
1259
+ * @internal
1260
+ * @class ContainerNotFoundComponent
1261
+ * @implements {OnInit}
1262
+ */
1263
+ class ContainerNotFoundComponent {
1264
+ constructor() {
1265
+ this.identifier = 'unknown';
1266
+ this.#dotcmsContextService = inject(DotCMSStore);
1267
+ this.$isDevMode = this.#dotcmsContextService.$isDevMode;
1268
+ this.emptyContainerStyle = EMPTY_CONTAINER_STYLE_ANGULAR;
1269
+ }
1270
+ #dotcmsContextService;
1271
+ ngOnInit() {
1272
+ if (this.$isDevMode()) {
1273
+ console.error(`Container with identifier ${this.identifier} not found`);
1274
+ }
1275
+ }
1276
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ContainerNotFoundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1277
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: ContainerNotFoundComponent, isStandalone: true, selector: "dotcms-container-not-found", inputs: { identifier: "identifier" }, ngImport: i0, template: `
1278
+ @if ($isDevMode()) {
1279
+ <div [attr.data-testid]="'container-not-found'" [ngStyle]="emptyContainerStyle">
1280
+ This container with identifier {{ identifier }} was not found.
1281
+ </div>
1282
+ }
1283
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] }); }
1284
+ }
1285
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ContainerNotFoundComponent, decorators: [{
1286
+ type: Component,
1287
+ args: [{
1288
+ selector: 'dotcms-container-not-found',
1289
+ standalone: true,
1290
+ imports: [NgStyle],
1291
+ template: `
1292
+ @if ($isDevMode()) {
1293
+ <div [attr.data-testid]="'container-not-found'" [ngStyle]="emptyContainerStyle">
1294
+ This container with identifier {{ identifier }} was not found.
1295
+ </div>
1296
+ }
1297
+ `
1298
+ }]
1299
+ }], propDecorators: { identifier: [{
1300
+ type: Input
1301
+ }] } });
1302
+
1303
+ /**
1304
+ * @description This component is used to display a message when a container is empty.
1305
+ * @export
1306
+ * @internal
1307
+ * @class EmptyContainerComponent
1308
+ */
1309
+ class EmptyContainerComponent {
1310
+ constructor() {
1311
+ this.emptyContainerStyle = EMPTY_CONTAINER_STYLE_ANGULAR;
1312
+ this.#dotCMSStore = inject(DotCMSStore);
1313
+ this.$isDevMode = this.#dotCMSStore.$isDevMode;
1314
+ }
1315
+ #dotCMSStore;
1316
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: EmptyContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1317
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: EmptyContainerComponent, isStandalone: true, selector: "dotcms-empty-container", ngImport: i0, template: `
1318
+ @if ($isDevMode()) {
1319
+ <div [ngStyle]="emptyContainerStyle" data-testid="empty-container">
1320
+ <span data-testid="empty-container-message">This container is empty.</span>
1321
+ </div>
1322
+ }
1323
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] }); }
1324
+ }
1325
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: EmptyContainerComponent, decorators: [{
1326
+ type: Component,
1327
+ args: [{
1328
+ selector: 'dotcms-empty-container',
1329
+ standalone: true,
1330
+ imports: [NgStyle],
1331
+ template: `
1332
+ @if ($isDevMode()) {
1333
+ <div [ngStyle]="emptyContainerStyle" data-testid="empty-container">
1334
+ <span data-testid="empty-container-message">This container is empty.</span>
1335
+ </div>
1336
+ }
1337
+ `
1338
+ }]
1339
+ }] });
1340
+
1341
+ /**
1342
+ * @description Fallback component that renders when no custom component is found for a contentlet
1343
+ * @category Components
1344
+ * @internal
1345
+ * @class FallbackComponent
1346
+ */
1347
+ class FallbackComponent {
1348
+ constructor() {
1349
+ this.UserNoComponent = null;
1350
+ }
1351
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: FallbackComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1352
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: FallbackComponent, isStandalone: true, selector: "dotcms-fallback-component", inputs: { UserNoComponent: "UserNoComponent", contentlet: "contentlet" }, ngImport: i0, template: `
1353
+ @if (UserNoComponent) {
1354
+ <ng-container *ngComponentOutlet="UserNoComponent | async; inputs: { contentlet }" />
1355
+ } @else {
1356
+ <div data-testid="dotcms-fallback-component">
1357
+ <p>No component found for content type: {{ contentlet.contentType }}</p>
1358
+ </div>
1359
+ }
1360
+ `, isInline: true, dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1361
+ }
1362
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: FallbackComponent, decorators: [{
1363
+ type: Component,
1364
+ args: [{
1365
+ selector: 'dotcms-fallback-component',
1366
+ standalone: true,
1367
+ imports: [AsyncPipe, NgComponentOutlet],
1368
+ template: `
1369
+ @if (UserNoComponent) {
1370
+ <ng-container *ngComponentOutlet="UserNoComponent | async; inputs: { contentlet }" />
1371
+ } @else {
1372
+ <div data-testid="dotcms-fallback-component">
1373
+ <p>No component found for content type: {{ contentlet.contentType }}</p>
1374
+ </div>
1375
+ }
1376
+ `,
1377
+ changeDetection: ChangeDetectionStrategy.OnPush
1378
+ }]
1379
+ }], propDecorators: { UserNoComponent: [{
1380
+ type: Input
1381
+ }], contentlet: [{
1382
+ type: Input
1383
+ }] } });
1384
+
1385
+ /**
1386
+ * @description Contentlet component that renders DotCMS content with development mode support
1387
+ *
1388
+ * @component
1389
+ * @param {DotCMSContentlet} contentlet - The contentlet to be rendered
1390
+ * @param {string} container - The container identifier
1391
+ * @class ContentletComponent
1392
+ */
1393
+ class ContentletComponent {
1394
+ constructor() {
1395
+ this.dotObject = 'contentlet';
1396
+ this.#dotCMSStore = inject(DotCMSStore);
1397
+ this.$contentlet = signal(null);
1398
+ this.$UserComponent = signal(null);
1399
+ this.$UserNoComponent = signal(null);
1400
+ this.$isDevMode = this.#dotCMSStore.$isDevMode;
1401
+ this.$haveContent = signal(false);
1402
+ this.$style = computed(() => this.$isDevMode() && !this.$haveContent() ? { minHeight: '4rem' } : {});
1403
+ this.$dotAttributes = computed(() => {
1404
+ const contentlet = this.$contentlet();
1405
+ if (!contentlet || !this.$isDevMode())
1406
+ return {};
1407
+ return getDotContentletAttributes(contentlet, this.containerData.identifier);
1408
+ });
1409
+ this.identifier = null;
1410
+ this.basetype = null;
1411
+ this.title = null;
1412
+ this.inode = null;
1413
+ this.type = null;
1414
+ this.containerAttribute = null;
1415
+ this.onNumberOfPages = null;
1416
+ this.styleAttribute = null;
1417
+ }
1418
+ #dotCMSStore;
1419
+ ngOnChanges() {
1420
+ this.$contentlet.set(this.contentlet);
1421
+ this.setupComponents();
1422
+ this.identifier = this.$dotAttributes()['data-dot-identifier'];
1423
+ this.basetype = this.$dotAttributes()['data-dot-basetype'];
1424
+ this.title = this.$dotAttributes()['data-dot-title'];
1425
+ this.inode = this.$dotAttributes()['data-dot-inode'];
1426
+ this.type = this.$dotAttributes()['data-dot-type'];
1427
+ this.containerAttribute = JSON.stringify(this.containerData);
1428
+ this.onNumberOfPages = this.$dotAttributes()['data-dot-on-number-of-pages'];
1429
+ this.styleAttribute = this.$style();
1430
+ }
1431
+ ngAfterViewInit() {
1432
+ this.checkContent();
1433
+ }
1434
+ setupComponents() {
1435
+ const store = this.#dotCMSStore.store;
1436
+ if (!store)
1437
+ return;
1438
+ if (!store?.components)
1439
+ return;
1440
+ this.$UserComponent.set(store.components[this.contentlet?.contentType]);
1441
+ this.$UserNoComponent.set(store.components[CUSTOM_NO_COMPONENT]);
1442
+ }
1443
+ checkContent() {
1444
+ const element = this.contentletRef?.nativeElement;
1445
+ if (element) {
1446
+ const hasContent = element.getBoundingClientRect().height > 0;
1447
+ this.$haveContent.set(hasContent);
1448
+ }
1449
+ }
1450
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ContentletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1451
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: ContentletComponent, isStandalone: true, selector: "dotcms-contentlet", inputs: { contentlet: "contentlet", containerData: "containerData" }, host: { properties: { "attr.data-dot-object": "this.dotObject", "attr.data-dot-identifier": "this.identifier", "attr.data-dot-basetype": "this.basetype", "attr.data-dot-title": "this.title", "attr.data-dot-inode": "this.inode", "attr.data-dot-type": "this.type", "attr.data-dot-container": "this.containerAttribute", "attr.data-dot-on-number-of-pages": "this.onNumberOfPages", "style": "this.styleAttribute" } }, viewQueries: [{ propertyName: "contentletRef", first: true, predicate: ["contentletRef"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
1452
+ @if ($UserComponent()) {
1453
+ <ng-container
1454
+ *ngComponentOutlet="
1455
+ $UserComponent() | async;
1456
+ inputs: { contentlet: $contentlet() ?? contentlet }
1457
+ " />
1458
+ } @else if ($isDevMode()) {
1459
+ <dotcms-fallback-component
1460
+ [UserNoComponent]="$UserNoComponent()"
1461
+ [contentlet]="$contentlet() ?? contentlet" />
1462
+ }
1463
+ `, isInline: true, dependencies: [{ kind: "component", type: FallbackComponent, selector: "dotcms-fallback-component", inputs: ["UserNoComponent", "contentlet"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1464
+ }
1465
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ContentletComponent, decorators: [{
1466
+ type: Component,
1467
+ args: [{
1468
+ selector: 'dotcms-contentlet',
1469
+ standalone: true,
1470
+ imports: [FallbackComponent, AsyncPipe, NgComponentOutlet],
1471
+ template: `
1472
+ @if ($UserComponent()) {
1473
+ <ng-container
1474
+ *ngComponentOutlet="
1475
+ $UserComponent() | async;
1476
+ inputs: { contentlet: $contentlet() ?? contentlet }
1477
+ " />
1478
+ } @else if ($isDevMode()) {
1479
+ <dotcms-fallback-component
1480
+ [UserNoComponent]="$UserNoComponent()"
1481
+ [contentlet]="$contentlet() ?? contentlet" />
1482
+ }
1483
+ `,
1484
+ changeDetection: ChangeDetectionStrategy.OnPush
1485
+ }]
1486
+ }], propDecorators: { contentlet: [{
1487
+ type: Input,
1488
+ args: [{ required: true }]
1489
+ }], containerData: [{
1490
+ type: Input,
1491
+ args: [{ required: true }]
1492
+ }], contentletRef: [{
1493
+ type: ViewChild,
1494
+ args: ['contentletRef']
1495
+ }], dotObject: [{
1496
+ type: HostBinding,
1497
+ args: ['attr.data-dot-object']
1498
+ }], identifier: [{
1499
+ type: HostBinding,
1500
+ args: ['attr.data-dot-identifier']
1501
+ }], basetype: [{
1502
+ type: HostBinding,
1503
+ args: ['attr.data-dot-basetype']
1504
+ }], title: [{
1505
+ type: HostBinding,
1506
+ args: ['attr.data-dot-title']
1507
+ }], inode: [{
1508
+ type: HostBinding,
1509
+ args: ['attr.data-dot-inode']
1510
+ }], type: [{
1511
+ type: HostBinding,
1512
+ args: ['attr.data-dot-type']
1513
+ }], containerAttribute: [{
1514
+ type: HostBinding,
1515
+ args: ['attr.data-dot-container']
1516
+ }], onNumberOfPages: [{
1517
+ type: HostBinding,
1518
+ args: ['attr.data-dot-on-number-of-pages']
1519
+ }], styleAttribute: [{
1520
+ type: HostBinding,
1521
+ args: ['style']
1522
+ }] } });
1523
+
1524
+ /**
1525
+ * @description This component renders a container with all its content using the layout provided by dotCMS Page API.
1526
+ *
1527
+ * @see {@link https://www.dotcms.com/docs/latest/page-rest-api-layout-as-a-service-laas}
1528
+ * @category Components
1529
+ * @internal
1530
+ * @class ContainerComponent
1531
+ */
1532
+ class ContainerComponent {
1533
+ constructor() {
1534
+ this.#dotCMSStore = inject(DotCMSStore);
1535
+ this.$containerData = signal(null);
1536
+ this.$contentlets = signal([]);
1537
+ this.$isEmpty = computed(() => this.$contentlets().length === 0);
1538
+ this.$dotAttributes = computed(() => {
1539
+ const containerData = this.$containerData();
1540
+ if (!containerData || !this.#dotCMSStore.$isDevMode()) {
1541
+ return {};
1542
+ }
1543
+ return getDotContainerAttributes(containerData);
1544
+ });
1545
+ this.dotObject = 'container';
1546
+ this.acceptTypes = null;
1547
+ this.identifier = null;
1548
+ this.maxContentlets = null;
1549
+ this.uuid = null;
1550
+ }
1551
+ #dotCMSStore;
1552
+ ngOnChanges() {
1553
+ const { page } = this.#dotCMSStore.store ?? {};
1554
+ if (!page) {
1555
+ return;
1556
+ }
1557
+ this.$containerData.set(getContainersData(page, this.container));
1558
+ this.$contentlets.set(getContentletsInContainer(page, this.container));
1559
+ this.acceptTypes = this.$dotAttributes()['data-dot-accept-types'];
1560
+ this.identifier = this.$dotAttributes()['data-dot-identifier'];
1561
+ this.maxContentlets = this.$dotAttributes()['data-max-contentlets'];
1562
+ this.uuid = this.$dotAttributes()['data-dot-uuid'];
1563
+ }
1564
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1565
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: ContainerComponent, isStandalone: true, selector: "dotcms-container", inputs: { container: "container" }, host: { properties: { "attr.data-dot-object": "this.dotObject", "attr.data-dot-accept-types": "this.acceptTypes", "attr.data-dot-identifier": "this.identifier", "attr.data-max-contentlets": "this.maxContentlets", "attr.data-dot-uuid": "this.uuid" } }, usesOnChanges: true, ngImport: i0, template: `
1566
+ @if (!$containerData()) {
1567
+ <dotcms-container-not-found [identifier]="container.identifier" />
1568
+ } @else if ($isEmpty()) {
1569
+ <dotcms-empty-container />
1570
+ } @else {
1571
+ @for (contentlet of $contentlets(); track contentlet.identifier) {
1572
+ <dotcms-contentlet [contentlet]="contentlet" [containerData]="$containerData()!" />
1573
+ }
1574
+ }
1575
+ `, isInline: true, dependencies: [{ kind: "component", type: ContainerNotFoundComponent, selector: "dotcms-container-not-found", inputs: ["identifier"] }, { kind: "component", type: EmptyContainerComponent, selector: "dotcms-empty-container" }, { kind: "component", type: ContentletComponent, selector: "dotcms-contentlet", inputs: ["contentlet", "containerData"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1576
+ }
1577
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ContainerComponent, decorators: [{
1578
+ type: Component,
1579
+ args: [{
1580
+ selector: 'dotcms-container',
1581
+ standalone: true,
1582
+ imports: [ContainerNotFoundComponent, EmptyContainerComponent, ContentletComponent],
1583
+ template: `
1584
+ @if (!$containerData()) {
1585
+ <dotcms-container-not-found [identifier]="container.identifier" />
1586
+ } @else if ($isEmpty()) {
1587
+ <dotcms-empty-container />
1588
+ } @else {
1589
+ @for (contentlet of $contentlets(); track contentlet.identifier) {
1590
+ <dotcms-contentlet [contentlet]="contentlet" [containerData]="$containerData()!" />
1591
+ }
1592
+ }
1593
+ `,
1594
+ changeDetection: ChangeDetectionStrategy.OnPush
1595
+ }]
1596
+ }], propDecorators: { container: [{
1597
+ type: Input,
1598
+ args: [{ required: true }]
1599
+ }], dotObject: [{
1600
+ type: HostBinding,
1601
+ args: ['attr.data-dot-object']
1602
+ }], acceptTypes: [{
1603
+ type: HostBinding,
1604
+ args: ['attr.data-dot-accept-types']
1605
+ }], identifier: [{
1606
+ type: HostBinding,
1607
+ args: ['attr.data-dot-identifier']
1608
+ }], maxContentlets: [{
1609
+ type: HostBinding,
1610
+ args: ['attr.data-max-contentlets']
1611
+ }], uuid: [{
1612
+ type: HostBinding,
1613
+ args: ['attr.data-dot-uuid']
1614
+ }] } });
1615
+
1616
+ /**
1617
+ * This component renders a column with all its content using the layout provided by dotCMS Page API.
1618
+ *
1619
+ * @see {@link https://www.dotcms.com/docs/latest/page-rest-api-layout-as-a-service-laas}
1620
+ * @category Components
1621
+ * @internal
1622
+ */
1623
+ class ColumnComponent {
1624
+ constructor() {
1625
+ this.customClasses = '';
1626
+ }
1627
+ ngOnChanges() {
1628
+ const positionClasses = getColumnPositionClasses(this.column);
1629
+ this.customClasses = combineClasses([positionClasses.startClass, positionClasses.endClass]);
1630
+ }
1631
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ColumnComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1632
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: ColumnComponent, isStandalone: true, selector: "dotcms-column", inputs: { column: "column" }, host: { properties: { "class": "this.customClasses" } }, usesOnChanges: true, ngImport: i0, template: `
1633
+ <div [class]="column.styleClass" data-testid="dotcms-column">
1634
+ @for (container of column.containers; track $index) {
1635
+ <dotcms-container [container]="container" />
1636
+ }
1637
+ </div>
1638
+ `, isInline: true, styles: [":host.col-start-1{grid-column-start:1}:host.col-start-2{grid-column-start:2}:host.col-start-3{grid-column-start:3}:host.col-start-4{grid-column-start:4}:host.col-start-5{grid-column-start:5}:host.col-start-6{grid-column-start:6}:host.col-start-7{grid-column-start:7}:host.col-start-8{grid-column-start:8}:host.col-start-9{grid-column-start:9}:host.col-start-10{grid-column-start:10}:host.col-start-11{grid-column-start:11}:host.col-start-12{grid-column-start:12}:host.col-end-1{grid-column-end:1}:host.col-end-2{grid-column-end:2}:host.col-end-3{grid-column-end:3}:host.col-end-4{grid-column-end:4}:host.col-end-5{grid-column-end:5}:host.col-end-6{grid-column-end:6}:host.col-end-7{grid-column-end:7}:host.col-end-8{grid-column-end:8}:host.col-end-9{grid-column-end:9}:host.col-end-10{grid-column-end:10}:host.col-end-11{grid-column-end:11}:host.col-end-12{grid-column-end:12}:host.col-end-13{grid-column-end:13}\n"], dependencies: [{ kind: "component", type: ContainerComponent, selector: "dotcms-container", inputs: ["container"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1639
+ }
1640
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ColumnComponent, decorators: [{
1641
+ type: Component,
1642
+ args: [{ selector: 'dotcms-column', standalone: true, imports: [ContainerComponent], template: `
1643
+ <div [class]="column.styleClass" data-testid="dotcms-column">
1644
+ @for (container of column.containers; track $index) {
1645
+ <dotcms-container [container]="container" />
1646
+ }
1647
+ </div>
1648
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host.col-start-1{grid-column-start:1}:host.col-start-2{grid-column-start:2}:host.col-start-3{grid-column-start:3}:host.col-start-4{grid-column-start:4}:host.col-start-5{grid-column-start:5}:host.col-start-6{grid-column-start:6}:host.col-start-7{grid-column-start:7}:host.col-start-8{grid-column-start:8}:host.col-start-9{grid-column-start:9}:host.col-start-10{grid-column-start:10}:host.col-start-11{grid-column-start:11}:host.col-start-12{grid-column-start:12}:host.col-end-1{grid-column-end:1}:host.col-end-2{grid-column-end:2}:host.col-end-3{grid-column-end:3}:host.col-end-4{grid-column-end:4}:host.col-end-5{grid-column-end:5}:host.col-end-6{grid-column-end:6}:host.col-end-7{grid-column-end:7}:host.col-end-8{grid-column-end:8}:host.col-end-9{grid-column-end:9}:host.col-end-10{grid-column-end:10}:host.col-end-11{grid-column-end:11}:host.col-end-12{grid-column-end:12}:host.col-end-13{grid-column-end:13}\n"] }]
1649
+ }], propDecorators: { column: [{
1650
+ type: Input,
1651
+ args: [{ required: true }]
1652
+ }], customClasses: [{
1653
+ type: HostBinding,
1654
+ args: ['class']
1655
+ }] } });
1656
+
1657
+ /**
1658
+ * @description This component renders a row with all its content using the layout provided by dotCMS Page API.
1659
+ *
1660
+ * @see {@link https://www.dotcms.com/docs/latest/page-rest-api-layout-as-a-service-laas}
1661
+ * @category Components
1662
+ * @internal
1663
+ * @class RowComponent
1664
+ */
1665
+ class RowComponent {
1666
+ constructor() {
1667
+ this.customClasses = signal('');
1668
+ }
1669
+ ngOnChanges() {
1670
+ this.customClasses.set(combineClasses([this.row.styleClass || 'dot-row']));
1671
+ }
1672
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: RowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1673
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: RowComponent, isStandalone: true, selector: "dotcms-row", inputs: { row: "row" }, usesOnChanges: true, ngImport: i0, template: `
1674
+ <div class="dot-row-container">
1675
+ <div [class]="customClasses()" data-dot-object="row" data-testid="dotcms-row">
1676
+ @for (column of row.columns; track $index) {
1677
+ <dotcms-column [column]="column" />
1678
+ }
1679
+ </div>
1680
+ </div>
1681
+ `, isInline: true, styles: [".dot-row{display:grid;grid-template-columns:repeat(12,1fr);gap:1rem}\n"], dependencies: [{ kind: "component", type: ColumnComponent, selector: "dotcms-column", inputs: ["column"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1682
+ }
1683
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: RowComponent, decorators: [{
1684
+ type: Component,
1685
+ args: [{ selector: 'dotcms-row', standalone: true, imports: [ColumnComponent], template: `
1686
+ <div class="dot-row-container">
1687
+ <div [class]="customClasses()" data-dot-object="row" data-testid="dotcms-row">
1688
+ @for (column of row.columns; track $index) {
1689
+ <dotcms-column [column]="column" />
1690
+ }
1691
+ </div>
1692
+ </div>
1693
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".dot-row{display:grid;grid-template-columns:repeat(12,1fr);gap:1rem}\n"] }]
1694
+ }], propDecorators: { row: [{
1695
+ type: Input,
1696
+ args: [{ required: true }]
1697
+ }] } });
1698
+
1699
+ /**
1700
+ * @description This component is used to render the layout for a DotCMS page.
1701
+ * @param {DotCMSPageAsset} page - The page to render the layout for
1702
+ * @param {DotCMSPageComponent} components - The components to render the layout for
1703
+ * @param {DotCMSPageRendererMode} mode - The mode to render the layout for
1704
+ *
1705
+ * @example
1706
+ * <dotcms-layout-body [page]="page" [components]="components" [mode]="'development'" />
1707
+ *
1708
+ * @export
1709
+ * @implements {OnChanges}
1710
+ * @class DotCMSLayoutBodyComponent
1711
+ */
1712
+ class DotCMSLayoutBodyComponent {
1713
+ constructor() {
1714
+ this.components = {};
1715
+ this.mode = 'production';
1716
+ this.#dotCMSStore = inject(DotCMSStore);
1717
+ this.$isDevMode = this.#dotCMSStore.$isDevMode;
1718
+ this.$rows = signal([]);
1719
+ this.$isEmpty = signal(false);
1720
+ }
1721
+ #dotCMSStore;
1722
+ ngOnChanges() {
1723
+ this.#dotCMSStore.setStore({
1724
+ page: this.page,
1725
+ components: this.components,
1726
+ mode: this.mode
1727
+ });
1728
+ this.$isEmpty.set(!this.page?.layout?.body);
1729
+ this.$rows.set(this.page?.layout?.body?.rows ?? []);
1730
+ }
1731
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSLayoutBodyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1732
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: DotCMSLayoutBodyComponent, isStandalone: true, selector: "dotcms-layout-body", inputs: { page: "page", components: "components", mode: "mode" }, providers: [DotCMSStore], usesOnChanges: true, ngImport: i0, template: `
1733
+ @if ($isEmpty() && $isDevMode()) {
1734
+ <dotcms-page-error-message />
1735
+ } @else {
1736
+ @for (row of $rows(); track row.identifier) {
1737
+ <dotcms-row [row]="row" />
1738
+ }
1739
+ }
1740
+ `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: PageErrorMessageComponent, selector: "dotcms-page-error-message" }, { kind: "component", type: RowComponent, selector: "dotcms-row", inputs: ["row"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1741
+ }
1742
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSLayoutBodyComponent, decorators: [{
1743
+ type: Component,
1744
+ args: [{ selector: 'dotcms-layout-body', standalone: true, imports: [PageErrorMessageComponent, RowComponent], providers: [DotCMSStore], template: `
1745
+ @if ($isEmpty() && $isDevMode()) {
1746
+ <dotcms-page-error-message />
1747
+ } @else {
1748
+ @for (row of $rows(); track row.identifier) {
1749
+ <dotcms-row [row]="row" />
1750
+ }
1751
+ }
1752
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}\n"] }]
1753
+ }], propDecorators: { page: [{
1754
+ type: Input,
1755
+ args: [{ required: true }]
1756
+ }], components: [{
1757
+ type: Input,
1758
+ args: [{ required: true }]
1759
+ }], mode: [{
1760
+ type: Input
1761
+ }] } });
1762
+
1763
+ class DotCMSEditablePageService {
1764
+ /**
1765
+ * Subject that emits the current editable page asset or null.
1766
+ * Used internally to track changes to the page data.
1767
+ *
1768
+ * @private
1769
+ * @type {Subject<DotCMSPageResponse | null>}
1770
+ */
1771
+ #responseSubject = new Subject();
1772
+ /**
1773
+ * Observable stream of the page asset changes.
1774
+ * Exposes the pageAssetSubject as an Observable for subscribers.
1775
+ *
1776
+ * @private
1777
+ * @type {Observable<DotCMSPageResponse | null>}
1778
+ */
1779
+ #response$ = this.#responseSubject.asObservable();
1780
+ /**
1781
+ * Listens for changes to an editable page and returns an Observable that emits the updated page data.
1782
+ * This method initializes the UVE (Universal Visual Editor) and sets up subscriptions to track content changes.
1783
+ *
1784
+ * @example
1785
+ * ```ts
1786
+ * // Import the service
1787
+ * import { DotCMSEditablePageService } from '@dotcms/angular';
1788
+ *
1789
+ * // Inject the service
1790
+ * constructor(private editablePageService: DotCMSEditablePageService) {}
1791
+ *
1792
+ * // Get the page data from your API call
1793
+ * const page = await client.page.get('/');
1794
+ *
1795
+ * // Listen for changes
1796
+ * const subscription = this.editablePageService.listen(page).subscribe(updatedPage => {
1797
+ * if (updatedPage) {
1798
+ * // Handle updated page data
1799
+ * console.log('Page updated:', updatedPage);
1800
+ * }
1801
+ * });
1802
+ *
1803
+ * // When done listening, unsubscribe
1804
+ * subscription.unsubscribe();
1805
+ * ```
1806
+ *
1807
+ * @param response Optional initial page data
1808
+ * @returns Observable that emits the updated page data or null
1809
+ */
1810
+ listen(response) {
1811
+ if (!getUVEState()) {
1812
+ return of(response || null);
1813
+ }
1814
+ const pageURI = response?.pageAsset?.page?.pageURI;
1815
+ initUVE(response);
1816
+ // Update the navigation to the pageURI, when we have a pageURI
1817
+ // Sometimes the page is null due to permissions, so we don't want to update the navigation
1818
+ // And wait for the UVE to resolve the page
1819
+ if (pageURI) {
1820
+ updateNavigation(pageURI);
1821
+ }
1822
+ const unsubscribeUVEChanges = this.#listenUVEChanges();
1823
+ return this.#response$.pipe(finalize(() => {
1824
+ unsubscribeUVEChanges();
1825
+ }));
1826
+ }
1827
+ /**
1828
+ * Sets up a subscription to listen for UVE content changes and updates the page asset subject.
1829
+ * This is an internal method used by listenEditablePage() to handle UVE events.
1830
+ *
1831
+ * @returns {UVEUnsubscribeFunction} Function to unsubscribe from the UVE content changes
1832
+ * @private
1833
+ */
1834
+ #listenUVEChanges() {
1835
+ const { unsubscribe } = createUVESubscription(UVEEventType.CONTENT_CHANGES, (payload) => {
1836
+ this.#responseSubject.next(payload);
1837
+ });
1838
+ return unsubscribe;
1839
+ }
1840
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSEditablePageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1841
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSEditablePageService, providedIn: 'root' }); }
1842
+ }
1843
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotCMSEditablePageService, decorators: [{
1844
+ type: Injectable,
1845
+ args: [{
1846
+ providedIn: 'root'
1847
+ }]
1848
+ }] });
1849
+
1850
+ /**
1851
+ * Generated bundle index. Do not edit.
1852
+ */
1853
+
1854
+ export { DotCMSBlockEditorRendererComponent, DotCMSEditablePageService, DotCMSEditableTextComponent, DotCMSLayoutBodyComponent, DotCMSShowWhenDirective, provideDotCMSImageLoader };
1855
+ //# sourceMappingURL=dotcms-angular-next.mjs.map