@dotcms/angular 0.0.1-alpha.40 → 0.0.1-alpha.41

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 (79) hide show
  1. package/README.md +10 -10
  2. package/dotcms-angular.d.ts.map +1 -0
  3. package/esm2022/dotcms-angular.mjs +5 -0
  4. package/esm2022/index.mjs +5 -0
  5. package/esm2022/lib/components/dot-editable-text/dot-editable-text.component.mjs +225 -0
  6. package/esm2022/lib/components/dot-editable-text/utils.mjs +43 -0
  7. package/esm2022/lib/components/no-component/no-component.component.mjs +32 -0
  8. package/esm2022/lib/layout/column/column.component.mjs +45 -0
  9. package/esm2022/lib/layout/container/container.component.mjs +126 -0
  10. package/esm2022/lib/layout/contentlet/contentlet.component.mjs +120 -0
  11. package/esm2022/lib/layout/dotcms-layout/dotcms-layout.component.mjs +100 -0
  12. package/esm2022/lib/layout/row/row.component.mjs +29 -0
  13. package/esm2022/lib/models/dotcms.model.mjs +3 -0
  14. package/esm2022/lib/models/index.mjs +3 -0
  15. package/esm2022/lib/services/dotcms-context/page-context.service.mjs +75 -0
  16. package/esm2022/lib/utils/index.mjs +79 -0
  17. package/fesm2022/dotcms-angular.mjs +858 -0
  18. package/fesm2022/dotcms-angular.mjs.map +1 -0
  19. package/{src/index.ts → index.d.ts} +1 -0
  20. package/index.d.ts.map +1 -0
  21. package/lib/components/dot-editable-text/dot-editable-text.component.d.ts +129 -0
  22. package/lib/components/dot-editable-text/dot-editable-text.component.d.ts.map +1 -0
  23. package/lib/components/dot-editable-text/utils.d.ts +7 -0
  24. package/lib/components/dot-editable-text/utils.d.ts.map +1 -0
  25. package/lib/components/no-component/no-component.component.d.ts +22 -0
  26. package/lib/components/no-component/no-component.component.d.ts.map +1 -0
  27. package/lib/layout/column/column.component.d.ts +29 -0
  28. package/lib/layout/column/column.component.d.ts.map +1 -0
  29. package/lib/layout/container/container.component.d.ts +88 -0
  30. package/lib/layout/container/container.component.d.ts.map +1 -0
  31. package/{src/lib/layout/contentlet/contentlet.component.ts → lib/layout/contentlet/contentlet.component.d.ts} +17 -32
  32. package/lib/layout/contentlet/contentlet.component.d.ts.map +1 -0
  33. package/lib/layout/dotcms-layout/dotcms-layout.component.d.ts +67 -0
  34. package/lib/layout/dotcms-layout/dotcms-layout.component.d.ts.map +1 -0
  35. package/lib/layout/row/row.component.d.ts +20 -0
  36. package/lib/layout/row/row.component.d.ts.map +1 -0
  37. package/{src/lib/models/dotcms.model.ts → lib/models/dotcms.model.d.ts} +3 -21
  38. package/lib/models/dotcms.model.d.ts.map +1 -0
  39. package/{src/lib/models/index.ts → lib/models/index.d.ts} +1 -8
  40. package/lib/models/index.d.ts.map +1 -0
  41. package/{src/lib/services/dotcms-context/page-context.service.ts → lib/services/dotcms-context/page-context.service.d.ts} +12 -41
  42. package/lib/services/dotcms-context/page-context.service.d.ts.map +1 -0
  43. package/lib/utils/index.d.ts +63 -0
  44. package/lib/utils/index.d.ts.map +1 -0
  45. package/package.json +22 -5
  46. package/.eslintrc.json +0 -18
  47. package/jest.config.ts +0 -22
  48. package/ng-package.json +0 -7
  49. package/project.json +0 -33
  50. package/src/lib/components/dot-editable-text/dot-editable-text.component.css +0 -4
  51. package/src/lib/components/dot-editable-text/dot-editable-text.component.html +0 -8
  52. package/src/lib/components/dot-editable-text/dot-editable-text.component.spec.ts +0 -424
  53. package/src/lib/components/dot-editable-text/dot-editable-text.component.ts +0 -269
  54. package/src/lib/components/dot-editable-text/utils.ts +0 -51
  55. package/src/lib/components/no-component/no-component.component.css +0 -3
  56. package/src/lib/components/no-component/no-component.component.spec.ts +0 -24
  57. package/src/lib/components/no-component/no-component.component.ts +0 -31
  58. package/src/lib/layout/column/column.component.css +0 -99
  59. package/src/lib/layout/column/column.component.spec.ts +0 -33
  60. package/src/lib/layout/column/column.component.ts +0 -49
  61. package/src/lib/layout/container/container.component.css +0 -9
  62. package/src/lib/layout/container/container.component.html +0 -26
  63. package/src/lib/layout/container/container.component.spec.ts +0 -205
  64. package/src/lib/layout/container/container.component.ts +0 -140
  65. package/src/lib/layout/contentlet/contentlet.component.spec.ts +0 -22
  66. package/src/lib/layout/dotcms-layout/dotcms-layout.component.css +0 -3
  67. package/src/lib/layout/dotcms-layout/dotcms-layout.component.spec.ts +0 -195
  68. package/src/lib/layout/dotcms-layout/dotcms-layout.component.ts +0 -150
  69. package/src/lib/layout/row/row.component.css +0 -6
  70. package/src/lib/layout/row/row.component.spec.ts +0 -28
  71. package/src/lib/layout/row/row.component.ts +0 -32
  72. package/src/lib/services/dotcms-context/page-context.spec.ts +0 -80
  73. package/src/lib/utils/index.ts +0 -92
  74. package/src/lib/utils/testing.utils.ts +0 -1019
  75. package/src/test-setup.ts +0 -8
  76. package/tsconfig.json +0 -29
  77. package/tsconfig.lib.json +0 -12
  78. package/tsconfig.lib.prod.json +0 -9
  79. package/tsconfig.spec.json +0 -11
@@ -0,0 +1,858 @@
1
+ import { TINYMCE_SCRIPT_SRC, EditorComponent } from '@tinymce/tinymce-angular';
2
+ import * as i0 from '@angular/core';
3
+ import { inject, Renderer2, ElementRef, SecurityContext, Component, ViewChild, Input, HostListener, Injectable, ChangeDetectionStrategy, HostBinding, signal, computed, DestroyRef } from '@angular/core';
4
+ import { DomSanitizer } from '@angular/platform-browser';
5
+ import { isInsideEditor, DotCmsClient, postMessageToEditor, CUSTOMER_ACTIONS, initEditor, updateNavigation } from '@dotcms/client';
6
+ import { AsyncPipe, NgComponentOutlet } from '@angular/common';
7
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
8
+ import { ActivatedRoute } from '@angular/router';
9
+ import { BehaviorSubject } from 'rxjs';
10
+ import { map } from 'rxjs/operators';
11
+
12
+ const DEFAULT_TINYMCE_CONFIG = {
13
+ menubar: false,
14
+ inline: true,
15
+ valid_styles: {
16
+ '*': 'font-size,font-family,color,text-decoration,text-align'
17
+ },
18
+ powerpaste_word_import: 'clean',
19
+ powerpaste_html_import: 'clean',
20
+ suffix: '.min', // Suffix to use when loading resources
21
+ license_key: 'gpl'
22
+ };
23
+ const TINYMCE_CONFIG = {
24
+ minimal: {
25
+ ...DEFAULT_TINYMCE_CONFIG,
26
+ plugins: 'link autolink',
27
+ toolbar: 'bold italic underline | link',
28
+ valid_elements: 'strong,em,span[style],a[href]'
29
+ },
30
+ full: {
31
+ ...DEFAULT_TINYMCE_CONFIG,
32
+ plugins: 'link lists autolink charmap',
33
+ style_formats: [
34
+ { title: 'Paragraph', format: 'p' },
35
+ { title: 'Header 1', format: 'h1' },
36
+ { title: 'Header 2', format: 'h2' },
37
+ { title: 'Header 3', format: 'h3' },
38
+ { title: 'Header 4', format: 'h4' },
39
+ { title: 'Header 5', format: 'h5' },
40
+ { title: 'Header 6', format: 'h6' },
41
+ { title: 'Pre', format: 'pre' },
42
+ { title: 'Code', format: 'code' }
43
+ ],
44
+ toolbar: [
45
+ 'styleselect undo redo | bold italic underline | forecolor backcolor | alignleft aligncenter alignright alignfull | numlist bullist outdent indent | hr charmap removeformat | link'
46
+ ]
47
+ },
48
+ plain: {
49
+ ...DEFAULT_TINYMCE_CONFIG,
50
+ plugins: '',
51
+ toolbar: ''
52
+ }
53
+ };
54
+
55
+ /**
56
+ * Dot editable text component.
57
+ * This component is responsible to render a text field that can be edited inline.
58
+ *
59
+ * @export
60
+ * @class DotEditableTextComponent
61
+ * @implements {OnInit}
62
+ * @implements {OnChanges}
63
+ */
64
+ class DotEditableTextComponent {
65
+ constructor() {
66
+ /**
67
+ * Represents the mode of the editor which can be `plain`, `minimal`, or `full`
68
+ *
69
+ * @type {DOT_EDITABLE_TEXT_MODE}
70
+ * @memberof DotEditableTextComponent
71
+ */
72
+ this.mode = 'plain';
73
+ /**
74
+ * Represents the format of the editor which can be `text` or `html`
75
+ *
76
+ * @type {DOT_EDITABLE_TEXT_FORMAT}
77
+ * @memberof DotEditableTextComponent
78
+ */
79
+ this.format = 'text';
80
+ /**
81
+ * Represents the field name of the `contentlet` that can be edited
82
+ *
83
+ * @memberof DotEditableTextComponent
84
+ */
85
+ this.fieldName = '';
86
+ /**
87
+ * Represents the content of the `contentlet` that can be edited
88
+ *
89
+ * @protected
90
+ * @memberof DotEditableTextComponent
91
+ */
92
+ this.content = '';
93
+ this.#sanitizer = inject(DomSanitizer);
94
+ this.#renderer = inject(Renderer2);
95
+ this.#elementRef = inject(ElementRef);
96
+ }
97
+ #sanitizer;
98
+ #renderer;
99
+ #elementRef;
100
+ /**
101
+ * The TinyMCE editor
102
+ *
103
+ * @readonly
104
+ * @memberof DotEditableTextComponent
105
+ */
106
+ get editor() {
107
+ return this.editorComponent?.editor;
108
+ }
109
+ /**
110
+ * Returns the number of pages the contentlet is on
111
+ *
112
+ * @readonly
113
+ * @memberof DotEditableTextComponent
114
+ */
115
+ get onNumberOfPages() {
116
+ return this.contentlet['onNumberOfPages'] || 1;
117
+ }
118
+ /**
119
+ * Handle copy contentlet inline editing success event
120
+ *
121
+ * @param {MessageEvent} { data }
122
+ * @return {*}
123
+ * @memberof DotEditableTextComponent
124
+ */
125
+ onMessage({ data }) {
126
+ const { name, payload } = data;
127
+ if (name !== 'COPY_CONTENTLET_INLINE_EDITING_SUCCESS') {
128
+ return;
129
+ }
130
+ const { oldInode, inode } = payload;
131
+ const currentInode = this.contentlet.inode;
132
+ if (currentInode === oldInode || currentInode === inode) {
133
+ this.editorComponent.editor.focus();
134
+ return;
135
+ }
136
+ }
137
+ ngOnInit() {
138
+ this.isInsideEditor = isInsideEditor();
139
+ if (!this.isInsideEditor) {
140
+ this.innerHTMLToElement();
141
+ return;
142
+ }
143
+ this.init = {
144
+ ...TINYMCE_CONFIG[this.mode],
145
+ base_url: `${DotCmsClient.dotcmsUrl}/ext/tinymcev7`
146
+ };
147
+ }
148
+ ngOnChanges() {
149
+ this.content = this.contentlet[this.fieldName] || '';
150
+ if (this.editor) {
151
+ this.editor.setContent(this.content, { format: this.format });
152
+ }
153
+ }
154
+ /**
155
+ * Handle mouse down event
156
+ *
157
+ * @param {EventObj<MouseEvent>} { event }
158
+ * @return {*}
159
+ * @memberof DotEditableTextComponent
160
+ */
161
+ onMouseDown({ event }) {
162
+ if (this.onNumberOfPages <= 1 || this.editorComponent.editor.hasFocus()) {
163
+ return;
164
+ }
165
+ const { inode, languageId: language } = this.contentlet;
166
+ event.stopPropagation();
167
+ event.preventDefault();
168
+ try {
169
+ postMessageToEditor({
170
+ action: CUSTOMER_ACTIONS.COPY_CONTENTLET_INLINE_EDITING,
171
+ payload: {
172
+ dataset: {
173
+ inode,
174
+ language,
175
+ fieldName: this.fieldName
176
+ }
177
+ }
178
+ });
179
+ }
180
+ catch (error) {
181
+ console.error('Failed to post message to editor:', error);
182
+ }
183
+ }
184
+ /**
185
+ * Handle focus out event
186
+ *
187
+ * @return {*}
188
+ * @memberof DotEditableTextComponent
189
+ */
190
+ onFocusOut() {
191
+ const content = this.editor.getContent({ format: this.format });
192
+ if (!this.editor.isDirty() || !this.didContentChange(content)) {
193
+ return;
194
+ }
195
+ const { inode, languageId: langId } = this.contentlet;
196
+ try {
197
+ postMessageToEditor({
198
+ action: CUSTOMER_ACTIONS.UPDATE_CONTENTLET_INLINE_EDITING,
199
+ payload: {
200
+ content,
201
+ dataset: {
202
+ inode,
203
+ langId,
204
+ fieldName: this.fieldName
205
+ }
206
+ }
207
+ });
208
+ }
209
+ catch (error) {
210
+ console.error('Failed to post message to editor:', error);
211
+ }
212
+ }
213
+ /**
214
+ * inner HTML to element
215
+ *
216
+ * @private
217
+ * @param {string} editedContent
218
+ * @return {*}
219
+ * @memberof DotEditableTextComponent
220
+ */
221
+ innerHTMLToElement() {
222
+ const element = this.#elementRef.nativeElement;
223
+ const safeHtml = this.#sanitizer.bypassSecurityTrustHtml(this.content);
224
+ const content = this.#sanitizer.sanitize(SecurityContext.HTML, safeHtml) || '';
225
+ this.#renderer.setProperty(element, 'innerHTML', content);
226
+ }
227
+ /**
228
+ * Check if the content has changed
229
+ *
230
+ * @private
231
+ * @param {string} editedContent
232
+ * @return {*}
233
+ * @memberof DotEditableTextComponent
234
+ */
235
+ didContentChange(editedContent) {
236
+ return this.content !== editedContent;
237
+ }
238
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotEditableTextComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
239
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: DotEditableTextComponent, isStandalone: true, selector: "dot-editable-text", inputs: { mode: "mode", format: "format", contentlet: "contentlet", fieldName: "fieldName" }, host: { listeners: { "window:message": "onMessage($event)" } }, providers: [
240
+ {
241
+ provide: TINYMCE_SCRIPT_SRC,
242
+ useFactory: () => {
243
+ return `${DotCmsClient.dotcmsUrl}/ext/tinymcev7/tinymce.min.js`;
244
+ }
245
+ }
246
+ ], viewQueries: [{ propertyName: "editorComponent", first: true, predicate: EditorComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (isInsideEditor) {\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"] }] }); }
247
+ }
248
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotEditableTextComponent, decorators: [{
249
+ type: Component,
250
+ args: [{ selector: 'dot-editable-text', standalone: true, imports: [EditorComponent], providers: [
251
+ {
252
+ provide: TINYMCE_SCRIPT_SRC,
253
+ useFactory: () => {
254
+ return `${DotCmsClient.dotcmsUrl}/ext/tinymcev7/tinymce.min.js`;
255
+ }
256
+ }
257
+ ], template: "@if (isInsideEditor) {\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"] }]
258
+ }], propDecorators: { editorComponent: [{
259
+ type: ViewChild,
260
+ args: [EditorComponent]
261
+ }], mode: [{
262
+ type: Input
263
+ }], format: [{
264
+ type: Input
265
+ }], contentlet: [{
266
+ type: Input
267
+ }], fieldName: [{
268
+ type: Input
269
+ }], onMessage: [{
270
+ type: HostListener,
271
+ args: ['window:message', ['$event']]
272
+ }] } });
273
+
274
+ /**
275
+ * @author dotCMS
276
+ * @description This service is responsible for managing the page context.
277
+ * @export
278
+ * @class PageContextService
279
+ */
280
+ class PageContextService {
281
+ constructor() {
282
+ this.context$ = new BehaviorSubject(null);
283
+ }
284
+ /**
285
+ * @description Get the context
286
+ * @readonly
287
+ * @type {DotCMSPageContext}
288
+ * @memberof PageContextService
289
+ */
290
+ get context() {
291
+ return this.context$.getValue();
292
+ }
293
+ /**
294
+ * @description Get the context as an observable
295
+ * @readonly
296
+ * @memberof PageContextService
297
+ */
298
+ get contextObs$() {
299
+ return this.context$.asObservable();
300
+ }
301
+ /**
302
+ * @description Get the current page asset
303
+ * @readonly
304
+ * @type {(Observable<DotCMSPageAsset | null>)}
305
+ * @memberof PageContextService
306
+ */
307
+ get currentPage$() {
308
+ return this.contextObs$.pipe(map((context) => context?.pageAsset || null));
309
+ }
310
+ /**
311
+ *
312
+ * @description Set the context
313
+ * @param {DotCMSPageAsset} value
314
+ * @memberof DotcmsContextService
315
+ */
316
+ setContext(pageAsset, components) {
317
+ this.context$.next({
318
+ pageAsset,
319
+ components,
320
+ isInsideEditor: isInsideEditor()
321
+ });
322
+ }
323
+ /**
324
+ * @description Set the page asset in the context
325
+ * @param {DotCMSPageAsset} pageAsset
326
+ * @memberof PageContextService
327
+ */
328
+ setPageAsset(pageAsset) {
329
+ this.context$.next({
330
+ ...this.context,
331
+ pageAsset
332
+ });
333
+ }
334
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: PageContextService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
335
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: PageContextService, providedIn: 'root' }); }
336
+ }
337
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: PageContextService, decorators: [{
338
+ type: Injectable,
339
+ args: [{
340
+ providedIn: 'root'
341
+ }]
342
+ }] });
343
+
344
+ //Changed the type, to avoid SQ issue.
345
+ //This should be put inside a lib
346
+ /**
347
+ * Represents a mapping of numbers to corresponding CSS class names for column end values.
348
+ * @typedef {Record<number, string | null>} EndClassMap
349
+ */
350
+ const endClassMap = {
351
+ 1: 'col-end-1',
352
+ 2: 'col-end-2',
353
+ 3: 'col-end-3',
354
+ 4: 'col-end-4',
355
+ 5: 'col-end-5',
356
+ 6: 'col-end-6',
357
+ 7: 'col-end-7',
358
+ 8: 'col-end-8',
359
+ 9: 'col-end-9',
360
+ 10: 'col-end-10',
361
+ 11: 'col-end-11',
362
+ 12: 'col-end-12',
363
+ 13: 'col-end-13'
364
+ };
365
+ //Changed the type, to avoid SQ issue.
366
+ //This should be put inside a lib
367
+ /**
368
+ * Represents a mapping of numbers to CSS class names for starting columns.
369
+ * @typedef {Record<number, string | null>} StartClassMap
370
+ */
371
+ const startClassMap = {
372
+ 1: 'col-start-1',
373
+ 2: 'col-start-2',
374
+ 3: 'col-start-3',
375
+ 4: 'col-start-4',
376
+ 5: 'col-start-5',
377
+ 6: 'col-start-6',
378
+ 7: 'col-start-7',
379
+ 8: 'col-start-8',
380
+ 9: 'col-start-9',
381
+ 10: 'col-start-10',
382
+ 11: 'col-start-11',
383
+ 12: 'col-start-12'
384
+ };
385
+ /**
386
+ * Retrieves the data for a set of containers.
387
+ *
388
+ * @param containers - The DotCMSPageAssetContainer object containing the containers.
389
+ * @param containerRef - The DotCMSContainer object representing the container reference.
390
+ * @returns An object containing the container data, accept types, contentlets, and variant ID.
391
+ */
392
+ const getContainersData = (containers, containerRef) => {
393
+ const { identifier, uuid } = containerRef;
394
+ const { containerStructures, container } = containers[identifier];
395
+ const { variantId } = container?.parentPermissionable || {};
396
+ const acceptTypes = containerStructures
397
+ .map((structure) => structure.contentTypeVar)
398
+ .join(',');
399
+ const contentlets = containers[identifier].contentlets[`uuid-${uuid}`];
400
+ return {
401
+ ...containers[identifier].container,
402
+ acceptTypes,
403
+ contentlets,
404
+ variantId
405
+ };
406
+ };
407
+ /**
408
+ * Returns the position style classes based on the start and end values.
409
+ * Used to set the grid column start and end values.
410
+ * @param start - The start value.
411
+ * @param end - The end value.
412
+ * @returns An object containing the startClass and endClass.
413
+ */
414
+ const getPositionStyleClasses = (start, end) => {
415
+ const startClass = startClassMap[start];
416
+ const endClass = endClassMap[end];
417
+ return {
418
+ startClass,
419
+ endClass
420
+ };
421
+ };
422
+
423
+ /**
424
+ * This component is responsible to display a message when there is no component for a contentlet.
425
+ *
426
+ * @export
427
+ * @class NoComponent
428
+ */
429
+ class NoComponent {
430
+ constructor() {
431
+ /**
432
+ * The data-testid attribute used for identifying the component during testing.
433
+ */
434
+ this.testId = 'no-component';
435
+ }
436
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: NoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
437
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: NoComponent, isStandalone: true, selector: "dotcms-no-component", inputs: { contentlet: "contentlet" }, host: { properties: { "attr.data-testid": "this.testId" } }, ngImport: i0, template: `
438
+ No Component for {{ contentlet.contentType }}
439
+ `, isInline: true, styles: [":host{display:block}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
440
+ }
441
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: NoComponent, decorators: [{
442
+ type: Component,
443
+ args: [{ selector: 'dotcms-no-component', standalone: true, template: `
444
+ No Component for {{ contentlet.contentType }}
445
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}\n"] }]
446
+ }], propDecorators: { contentlet: [{
447
+ type: Input
448
+ }], testId: [{
449
+ type: HostBinding,
450
+ args: ['attr.data-testid']
451
+ }] } });
452
+
453
+ /**
454
+ * This component is responsible to display a contentlet.
455
+ *
456
+ * @export
457
+ * @class ContentletComponent
458
+ * @implements {OnChanges}
459
+ */
460
+ class ContentletComponent {
461
+ constructor() {
462
+ /**
463
+ * The identifier of contentlet component.
464
+ *
465
+ * @type {(string | null)}
466
+ * @memberof ContentletComponent
467
+ */
468
+ this.identifier = null;
469
+ /**
470
+ * The base type of contentlet component.
471
+ *
472
+ * @type {(string | null)}
473
+ * @memberof ContentletComponent
474
+ */
475
+ this.baseType = null;
476
+ /**
477
+ * The title of contentlet component.
478
+ *
479
+ * @type {(string | null)}
480
+ * @memberof ContentletComponent
481
+ */
482
+ this.title = null;
483
+ /**
484
+ * The inode of contentlet component.
485
+ *
486
+ * @type {(string | null)}
487
+ * @memberof ContentletComponent
488
+ */
489
+ this.inode = null;
490
+ /**
491
+ * The type of contentlet component.
492
+ *
493
+ * @type {(string | null)}
494
+ * @memberof ContentletComponent
495
+ */
496
+ this.dotType = null;
497
+ /**
498
+ * The container of contentlet component.
499
+ *
500
+ * @type {(string | null)}
501
+ * @memberof ContentletComponent
502
+ */
503
+ this.dotContainer = null;
504
+ /**
505
+ * The number of pages where the contentlet appears
506
+ *
507
+ * @type {(string | null)}
508
+ * @memberof ContentletComponent
509
+ */
510
+ this.numberOfPages = null;
511
+ /**
512
+ * The content of contentlet component.
513
+ *
514
+ * @type {(string | null)}
515
+ * @memberof ContentletComponent
516
+ */
517
+ this.dotContent = null;
518
+ }
519
+ ngOnChanges() {
520
+ this.identifier = this.contentlet.identifier;
521
+ this.baseType = this.contentlet.baseType;
522
+ this.title = this.contentlet.title;
523
+ this.inode = this.contentlet.inode;
524
+ this.dotType = this.contentlet.contentType;
525
+ this.dotContainer = this.container;
526
+ this.numberOfPages = this.contentlet['onNumberOfPages'];
527
+ this.dotContent = 'contentlet';
528
+ }
529
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ContentletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
530
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.3", type: ContentletComponent, isStandalone: true, selector: "dotcms-contentlet-wrapper", inputs: { contentlet: "contentlet", container: "container" }, host: { properties: { "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.dotType", "attr.data-dot-container": "this.dotContainer", "attr.data-dot-on-number-of-pages": "this.numberOfPages", "attr.data-dot-object": "this.dotContent" } }, usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
531
+ }
532
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ContentletComponent, decorators: [{
533
+ type: Component,
534
+ args: [{
535
+ selector: 'dotcms-contentlet-wrapper',
536
+ standalone: true,
537
+ template: '<ng-content></ng-content>',
538
+ changeDetection: ChangeDetectionStrategy.OnPush
539
+ }]
540
+ }], propDecorators: { contentlet: [{
541
+ type: Input,
542
+ args: [{ required: true }]
543
+ }], container: [{
544
+ type: Input
545
+ }], identifier: [{
546
+ type: HostBinding,
547
+ args: ['attr.data-dot-identifier']
548
+ }], baseType: [{
549
+ type: HostBinding,
550
+ args: ['attr.data-dot-basetype']
551
+ }], title: [{
552
+ type: HostBinding,
553
+ args: ['attr.data-dot-title']
554
+ }], inode: [{
555
+ type: HostBinding,
556
+ args: ['attr.data-dot-inode']
557
+ }], dotType: [{
558
+ type: HostBinding,
559
+ args: ['attr.data-dot-type']
560
+ }], dotContainer: [{
561
+ type: HostBinding,
562
+ args: ['attr.data-dot-container']
563
+ }], numberOfPages: [{
564
+ type: HostBinding,
565
+ args: ['attr.data-dot-on-number-of-pages']
566
+ }], dotContent: [{
567
+ type: HostBinding,
568
+ args: ['attr.data-dot-object']
569
+ }] } });
570
+
571
+ /**
572
+ * This component is responsible to display a container with contentlets.
573
+ *
574
+ * @export
575
+ * @class ContainerComponent
576
+ * @implements {OnChanges}
577
+ */
578
+ class ContainerComponent {
579
+ constructor() {
580
+ this.pageContextService = inject(PageContextService);
581
+ this.NoComponent = NoComponent;
582
+ this.$isInsideEditor = signal(false);
583
+ this.$contentlets = signal([]);
584
+ this.$dotContainer = signal(null);
585
+ this.$dotContainerAsString = computed(() => JSON.stringify(this.$dotContainer()));
586
+ /**
587
+ * The accept types for the container component.
588
+ *
589
+ * @type {(string | null)}
590
+ * @memberof ContainerComponent
591
+ */
592
+ this.acceptTypes = null;
593
+ /**
594
+ * The identifier for the container component.
595
+ *
596
+ * @type {(string | null)}
597
+ * @memberof ContainerComponent
598
+ */
599
+ this.identifier = null;
600
+ /**
601
+ * The max contentlets for the container component.
602
+ *
603
+ * @type {(number | null)}
604
+ * @memberof ContainerComponent
605
+ */
606
+ this.maxContentlets = null;
607
+ /**
608
+ * The uuid for the container component.
609
+ *
610
+ * @type {(string | null)}
611
+ * @memberof ContainerComponent
612
+ */
613
+ this.uuid = null;
614
+ /**
615
+ * The class for the container component.
616
+ *
617
+ * @type {(string | null)}
618
+ * @memberof ContainerComponent
619
+ */
620
+ this.class = null;
621
+ /**
622
+ * The dot object for the container component.
623
+ *
624
+ * @type {(string | null)}
625
+ * @memberof ContainerComponent
626
+ */
627
+ this.dotObject = null;
628
+ /**
629
+ * The data-testid attribute used for identifying the component during testing.
630
+ *
631
+ * @memberof ContainerComponent
632
+ */
633
+ this.testId = 'dot-container';
634
+ }
635
+ ngOnChanges() {
636
+ const { pageAsset, components, isInsideEditor } = this.pageContextService.context;
637
+ const { acceptTypes, maxContentlets, variantId, path, contentlets } = getContainersData(pageAsset.containers, this.container);
638
+ const { identifier, uuid } = this.container;
639
+ this.componentsMap = components;
640
+ this.$isInsideEditor.set(isInsideEditor);
641
+ this.$contentlets.set(contentlets);
642
+ this.$dotContainer.set({
643
+ identifier: path ?? identifier,
644
+ acceptTypes,
645
+ maxContentlets,
646
+ variantId,
647
+ uuid
648
+ });
649
+ if (this.$isInsideEditor()) {
650
+ this.acceptTypes = acceptTypes;
651
+ this.identifier = identifier;
652
+ this.maxContentlets = maxContentlets;
653
+ this.uuid = uuid;
654
+ this.class = this.$contentlets().length ? null : 'empty-container';
655
+ this.dotObject = 'container';
656
+ }
657
+ }
658
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
659
+ 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-accept-types": "this.acceptTypes", "attr.data-dot-identifier": "this.identifier", "attr.data-max-contentlets": "this.maxContentlets", "attr.data-dot-uuid": "this.uuid", "class": "this.class", "attr.data-dot-object": "this.dotObject", "attr.data-testid": "this.testId" } }, usesOnChanges: true, ngImport: i0, template: "@if ($isInsideEditor()) {\n @if ($contentlets().length) {\n @for (contentlet of $contentlets(); track $index) {\n <dotcms-contentlet-wrapper\n [contentlet]=\"contentlet\"\n [container]=\"$dotContainerAsString()\">\n <ng-container\n *ngComponentOutlet=\"\n (componentsMap[contentlet.contentType] || componentsMap['CustomNoComponent']\n | async) || NoComponent;\n inputs: { contentlet }\n \" />\n </dotcms-contentlet-wrapper>\n }\n } @else {\n This container is empty.\n }\n} @else {\n @for (contentlet of $contentlets(); track $index) {\n <ng-container\n *ngComponentOutlet=\"\n componentsMap[contentlet.contentType] | async;\n inputs: { contentlet }\n \" />\n }\n}\n", styles: [":host.empty-container{width:100%;background-color:#ecf0fd;display:flex;justify-content:center;align-items:center;color:#030e32;height:10rem}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: ContentletComponent, selector: "dotcms-contentlet-wrapper", inputs: ["contentlet", "container"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
660
+ }
661
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ContainerComponent, decorators: [{
662
+ type: Component,
663
+ args: [{ selector: 'dotcms-container', standalone: true, imports: [AsyncPipe, NgComponentOutlet, NoComponent, ContentletComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if ($isInsideEditor()) {\n @if ($contentlets().length) {\n @for (contentlet of $contentlets(); track $index) {\n <dotcms-contentlet-wrapper\n [contentlet]=\"contentlet\"\n [container]=\"$dotContainerAsString()\">\n <ng-container\n *ngComponentOutlet=\"\n (componentsMap[contentlet.contentType] || componentsMap['CustomNoComponent']\n | async) || NoComponent;\n inputs: { contentlet }\n \" />\n </dotcms-contentlet-wrapper>\n }\n } @else {\n This container is empty.\n }\n} @else {\n @for (contentlet of $contentlets(); track $index) {\n <ng-container\n *ngComponentOutlet=\"\n componentsMap[contentlet.contentType] | async;\n inputs: { contentlet }\n \" />\n }\n}\n", styles: [":host.empty-container{width:100%;background-color:#ecf0fd;display:flex;justify-content:center;align-items:center;color:#030e32;height:10rem}\n"] }]
664
+ }], propDecorators: { container: [{
665
+ type: Input,
666
+ args: [{ required: true }]
667
+ }], acceptTypes: [{
668
+ type: HostBinding,
669
+ args: ['attr.data-dot-accept-types']
670
+ }], identifier: [{
671
+ type: HostBinding,
672
+ args: ['attr.data-dot-identifier']
673
+ }], maxContentlets: [{
674
+ type: HostBinding,
675
+ args: ['attr.data-max-contentlets']
676
+ }], uuid: [{
677
+ type: HostBinding,
678
+ args: ['attr.data-dot-uuid']
679
+ }], class: [{
680
+ type: HostBinding,
681
+ args: ['class']
682
+ }], dotObject: [{
683
+ type: HostBinding,
684
+ args: ['attr.data-dot-object']
685
+ }], testId: [{
686
+ type: HostBinding,
687
+ args: ['attr.data-testid']
688
+ }] } });
689
+
690
+ /**
691
+ * This component is responsible to display a column with containers.
692
+ *
693
+ * @export
694
+ * @class ColumnComponent
695
+ * @implements {OnInit}
696
+ */
697
+ class ColumnComponent {
698
+ constructor() {
699
+ /**
700
+ * The data-testid attribute used for identifying the component during testing.
701
+ *
702
+ * @memberof ColumnComponent
703
+ */
704
+ this.containerClasses = '';
705
+ }
706
+ ngOnInit() {
707
+ const { startClass, endClass } = getPositionStyleClasses(this.column.leftOffset, this.column.width + this.column.leftOffset);
708
+ this.containerClasses = `${startClass} ${endClass}`;
709
+ }
710
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ColumnComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
711
+ 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.containerClasses" } }, ngImport: i0, template: `
712
+ @for (container of column.containers; track $index) {
713
+ <dotcms-container [container]="container" />
714
+ }
715
+ `, 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 }); }
716
+ }
717
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: ColumnComponent, decorators: [{
718
+ type: Component,
719
+ args: [{ selector: 'dotcms-column', standalone: true, imports: [ContainerComponent], template: `
720
+ @for (container of column.containers; track $index) {
721
+ <dotcms-container [container]="container" />
722
+ }
723
+ `, 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"] }]
724
+ }], propDecorators: { column: [{
725
+ type: Input
726
+ }], containerClasses: [{
727
+ type: HostBinding,
728
+ args: ['class']
729
+ }] } });
730
+
731
+ /**
732
+ * This component is responsible to display a row with columns.
733
+ *
734
+ * @export
735
+ * @class RowComponent
736
+ */
737
+ class RowComponent {
738
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: RowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
739
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: RowComponent, isStandalone: true, selector: "dotcms-row", inputs: { row: "row" }, ngImport: i0, template: `
740
+ @for (column of row.columns; track $index) {
741
+ <dotcms-column [column]="column" />
742
+ }
743
+ `, isInline: true, styles: [":host{display:grid;grid-template-columns:repeat(12,1fr);gap:1rem;row-gap:1rem}\n"], dependencies: [{ kind: "component", type: ColumnComponent, selector: "dotcms-column", inputs: ["column"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
744
+ }
745
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: RowComponent, decorators: [{
746
+ type: Component,
747
+ args: [{ selector: 'dotcms-row', standalone: true, imports: [ColumnComponent], template: `
748
+ @for (column of row.columns; track $index) {
749
+ <dotcms-column [column]="column" />
750
+ }
751
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:grid;grid-template-columns:repeat(12,1fr);gap:1rem;row-gap:1rem}\n"] }]
752
+ }], propDecorators: { row: [{
753
+ type: Input,
754
+ args: [{ required: true }]
755
+ }] } });
756
+
757
+ /**
758
+ * `DotcmsLayoutComponent` is a class that represents the layout for a DotCMS page.
759
+ * It includes a `pageAsset` property that represents the DotCMS page asset and a `components` property that represents the dynamic components for the page.
760
+ *
761
+ * @export
762
+ * @class DotcmsLayoutComponent
763
+ */
764
+ class DotcmsLayoutComponent {
765
+ constructor() {
766
+ this.route = inject(ActivatedRoute);
767
+ this.pageContextService = inject(PageContextService);
768
+ this.destroyRef$ = inject(DestroyRef);
769
+ this.pageAsset$ = this.pageContextService.currentPage$;
770
+ }
771
+ /**
772
+ * Represents the DotCMS page asset.
773
+ *
774
+ * @type {DotCMSPageAsset}
775
+ * @memberof DotcmsLayoutComponent
776
+ */
777
+ set pageAsset(value) {
778
+ this._pageAsset = value;
779
+ if (!value.layout) {
780
+ console.warn('Warning: pageAsset does not have a `layout` property. Might be using an advaced template or your dotCMS instance not have a enterprise license.');
781
+ }
782
+ }
783
+ /**
784
+ * Returns the DotCMS page asset.
785
+ *
786
+ * @readonly
787
+ * @type {DotCMSPageAsset}
788
+ * @memberof DotcmsLayoutComponent
789
+ */
790
+ get pageAsset() {
791
+ return this._pageAsset;
792
+ }
793
+ ngOnInit() {
794
+ this.pageContextService.setContext(this.pageAsset, this.components);
795
+ if (!isInsideEditor()) {
796
+ return;
797
+ }
798
+ this.client = DotCmsClient.instance;
799
+ this.route.url.pipe(takeUntilDestroyed(this.destroyRef$)).subscribe((urlSegments) => {
800
+ const pathname = '/' + urlSegments.join('/');
801
+ initEditor({ pathname });
802
+ updateNavigation(pathname || '/');
803
+ });
804
+ this.client.editor.on('changes', (data) => {
805
+ if (this.onReload) {
806
+ this.onReload();
807
+ return;
808
+ }
809
+ this.pageContextService.setPageAsset(data);
810
+ });
811
+ postMessageToEditor({ action: CUSTOMER_ACTIONS.CLIENT_READY, payload: this.editor });
812
+ }
813
+ ngOnDestroy() {
814
+ if (!isInsideEditor()) {
815
+ return;
816
+ }
817
+ this.client.editor.off('changes');
818
+ }
819
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotcmsLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
820
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.3", type: DotcmsLayoutComponent, isStandalone: true, selector: "dotcms-layout", inputs: { pageAsset: "pageAsset", components: "components", onReload: "onReload", editor: "editor" }, ngImport: i0, template: `
821
+ @if (pageAsset$ | async; as page) {
822
+ @for (row of this.page?.layout?.body?.rows; track $index) {
823
+ <dotcms-row [row]="row" />
824
+ }
825
+ }
826
+ `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: RowComponent, selector: "dotcms-row", inputs: ["row"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
827
+ }
828
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.3", ngImport: i0, type: DotcmsLayoutComponent, decorators: [{
829
+ type: Component,
830
+ args: [{ selector: 'dotcms-layout', standalone: true, imports: [RowComponent, AsyncPipe], template: `
831
+ @if (pageAsset$ | async; as page) {
832
+ @for (row of this.page?.layout?.body?.rows; track $index) {
833
+ <dotcms-row [row]="row" />
834
+ }
835
+ }
836
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}\n"] }]
837
+ }], propDecorators: { pageAsset: [{
838
+ type: Input,
839
+ args: [{ required: true }]
840
+ }], components: [{
841
+ type: Input,
842
+ args: [{ required: true }]
843
+ }], onReload: [{
844
+ type: Input
845
+ }], editor: [{
846
+ type: Input
847
+ }] } });
848
+
849
+ /* eslint-disable @typescript-eslint/no-explicit-any */
850
+
851
+ /* eslint-disable @typescript-eslint/no-explicit-any */
852
+
853
+ /**
854
+ * Generated bundle index. Do not edit.
855
+ */
856
+
857
+ export { DotEditableTextComponent, DotcmsLayoutComponent, PageContextService };
858
+ //# sourceMappingURL=dotcms-angular.mjs.map