@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
@@ -1,424 +0,0 @@
1
- import { SpyObject } from '@ngneat/spectator';
2
- import { Spectator, createComponentFactory } from '@ngneat/spectator/jest';
3
- import { EditorComponent, TINYMCE_SCRIPT_SRC } from '@tinymce/tinymce-angular';
4
- import { MockComponent } from 'ng-mocks';
5
- import { Editor } from 'tinymce';
6
-
7
- import { DebugElement, ElementRef, Renderer2, SecurityContext } from '@angular/core';
8
- import { By, DomSanitizer } from '@angular/platform-browser';
9
-
10
- import * as dotcmsClient from '@dotcms/client';
11
-
12
- import { DotEditableTextComponent } from './dot-editable-text.component';
13
- import { TINYMCE_CONFIG } from './utils';
14
-
15
- import { dotcmsContentletMock } from '../../utils/testing.utils';
16
-
17
- const { CUSTOMER_ACTIONS, postMessageToEditor } = dotcmsClient;
18
-
19
- // Mock @dotcms/client module
20
- jest.mock('@dotcms/client', () => ({
21
- ...jest.requireActual('@dotcms/client'),
22
- isInsideEditor: jest.fn().mockImplementation(() => true),
23
- postMessageToEditor: jest.fn(),
24
- DotCmsClient: {
25
- dotcmsUrl: 'http://localhost:8080'
26
- }
27
- }));
28
-
29
- const mockedDotcmsClient = dotcmsClient as jest.Mocked<typeof dotcmsClient>;
30
-
31
- const TINYMCE_EDITOR_MOCK: unknown = {
32
- focus: jest.fn(),
33
- getContent: (_data: unknown) => '',
34
- isDirty: () => false,
35
- hasFocus: () => false,
36
- setContent: jest.fn()
37
- };
38
-
39
- const TINYMCE_EDITOR_PROPERTY_MOCK = {
40
- get: jest.fn(() => TINYMCE_EDITOR_MOCK as Editor)
41
- };
42
-
43
- const mockEditorFn = (spectator: Spectator<DotEditableTextComponent>) => {
44
- // Mock the editor property of the EditorComponent
45
- // We need to test that the methods of the editor are called
46
- // We do not care about how the editor handles the calls under the hood
47
- Object.defineProperty(
48
- spectator.component.editorComponent,
49
- 'editor',
50
- TINYMCE_EDITOR_PROPERTY_MOCK
51
- );
52
- };
53
-
54
- describe('DotEditableTextComponent', () => {
55
- let spectator: Spectator<DotEditableTextComponent>;
56
-
57
- const createComponent = createComponentFactory({
58
- component: DotEditableTextComponent,
59
- declarations: [MockComponent(EditorComponent)],
60
- providers: [
61
- Renderer2,
62
- {
63
- provide: DomSanitizer,
64
- useValue: {
65
- bypassSecurityTrustHtml: () => '',
66
- sanitize: () => ''
67
- }
68
- },
69
- {
70
- provide: ElementRef,
71
- useValue: {
72
- nativeElement: document.createElement('div')
73
- }
74
- },
75
- {
76
- provide: TINYMCE_SCRIPT_SRC,
77
- useValue: 'tinymce/tinymce.min.js'
78
- }
79
- ]
80
- });
81
-
82
- beforeEach(() => {
83
- spectator = createComponent({
84
- props: {
85
- contentlet: dotcmsContentletMock,
86
- fieldName: 'title'
87
- },
88
- detectChanges: false
89
- });
90
- });
91
-
92
- describe('Outside Editor', () => {
93
- let renderer2: SpyObject<Renderer2>;
94
- let elementRef: SpyObject<ElementRef>;
95
- let sanitizer: SpyObject<DomSanitizer>;
96
-
97
- beforeEach(() => {
98
- jest.spyOn(mockedDotcmsClient, 'isInsideEditor').mockReturnValue(false);
99
- renderer2 = spectator.inject(Renderer2, true);
100
- elementRef = spectator.inject(ElementRef, true);
101
- sanitizer = spectator.inject(DomSanitizer, true);
102
- });
103
-
104
- describe('Template', () => {
105
- it('Should insert safe HTML content using innerHTML', () => {
106
- const safeHtml = dotcmsContentletMock.title + 'Safe';
107
- const spyRender2 = jest.spyOn(renderer2, 'setProperty');
108
- const spybypassSecurityTrustHtml = jest
109
- .spyOn(sanitizer, 'bypassSecurityTrustHtml')
110
- .mockReturnValue(safeHtml);
111
- const spySanitze = jest.spyOn(sanitizer, 'sanitize').mockReturnValue(safeHtml);
112
-
113
- spectator.detectChanges();
114
-
115
- const nativeElement = elementRef.nativeElement;
116
- const componentHTML = spectator.debugElement.nativeElement.innerHTML;
117
-
118
- expect(componentHTML).toBe(safeHtml);
119
- expect(spybypassSecurityTrustHtml).toHaveBeenCalledWith(dotcmsContentletMock.title);
120
- expect(spySanitze).toHaveBeenCalledWith(SecurityContext.HTML, safeHtml);
121
- expect(spyRender2).toHaveBeenCalledWith(nativeElement, 'innerHTML', safeHtml);
122
- });
123
-
124
- it('Should not initialize the editor', () => {
125
- spectator.detectChanges();
126
-
127
- const editorComponent = spectator.query(EditorComponent);
128
- expect(editorComponent).toBeNull();
129
- });
130
- });
131
- });
132
-
133
- describe('Inside Editor', () => {
134
- beforeEach(() => {
135
- jest.spyOn(mockedDotcmsClient, 'isInsideEditor').mockReturnValue(true);
136
- });
137
-
138
- it('should set content with the right format when the contentlet changes', () => {
139
- spectator.detectChanges();
140
- mockEditorFn(spectator);
141
-
142
- const editorComponent = spectator.query(EditorComponent) as EditorComponent;
143
- const spySetContent = jest.spyOn(editorComponent.editor, 'setContent');
144
-
145
- spectator.setInput('contentlet', {
146
- ...dotcmsContentletMock,
147
- title: 'New title'
148
- });
149
- spectator.detectChanges();
150
- expect(spySetContent).toHaveBeenCalledWith('New title', { format: 'text' });
151
- });
152
-
153
- describe('Configuration', () => {
154
- describe('Editor Configuration', () => {
155
- it('should set a plain mode by default', () => {
156
- spectator.setInput('mode', 'plain');
157
- spectator.detectChanges();
158
- const editorComponent = spectator.query(EditorComponent);
159
-
160
- spectator.detectChanges();
161
- expect(spectator.component.mode).toBe('plain');
162
- expect(editorComponent?.init).toEqual({
163
- ...TINYMCE_CONFIG['plain'],
164
- base_url: 'http://localhost:8080/ext/tinymcev7'
165
- });
166
- });
167
-
168
- it('should set a minimal mode when the mode is set to minimal', () => {
169
- spectator.setInput('mode', 'minimal');
170
- spectator.detectChanges();
171
-
172
- const editorComponent = spectator.query(EditorComponent);
173
-
174
- expect(spectator.component.mode).toBe('minimal');
175
- expect(editorComponent?.init).toEqual({
176
- ...TINYMCE_CONFIG['minimal'],
177
- base_url: 'http://localhost:8080/ext/tinymcev7'
178
- });
179
- });
180
-
181
- it('should set a full mode when the mode is set to full', () => {
182
- spectator.setInput('mode', 'full');
183
- spectator.detectChanges();
184
-
185
- const editorComponent = spectator.query(EditorComponent);
186
-
187
- expect(spectator.component.mode).toBe('full');
188
- expect(editorComponent?.init).toEqual({
189
- ...TINYMCE_CONFIG['full'],
190
- base_url: 'http://localhost:8080/ext/tinymcev7'
191
- });
192
- });
193
- });
194
-
195
- describe('format', () => {
196
- let getContentSpy: jest.SpyInstance;
197
- let editorDebugElement: DebugElement;
198
- let customEvent: {
199
- event: FocusEvent;
200
- editor: unknown;
201
- };
202
-
203
- beforeEach(() => {
204
- spectator.detectChanges();
205
- mockEditorFn(spectator);
206
-
207
- const editor = spectator.component.editorComponent.editor;
208
- getContentSpy = jest.spyOn(editor, 'getContent');
209
- customEvent = {
210
- event: new FocusEvent('focusout'),
211
- editor: TINYMCE_EDITOR_MOCK
212
- };
213
- editorDebugElement = spectator.debugElement.query(
214
- By.directive(EditorComponent)
215
- );
216
- });
217
-
218
- it('should get the content as text by default', () => {
219
- spectator.triggerEventHandler(editorDebugElement, 'onFocusOut', customEvent);
220
- expect(getContentSpy).toHaveBeenCalledWith({ format: 'text' });
221
- });
222
-
223
- it('should get the content as text when format is set to text', () => {
224
- spectator.setInput('format', 'text');
225
- spectator.detectChanges();
226
- spectator.triggerEventHandler(editorDebugElement, 'onFocusOut', customEvent);
227
- expect(getContentSpy).toHaveBeenCalledWith({ format: 'text' });
228
- });
229
-
230
- it('should get the content as html when format is set to html', () => {
231
- spectator.setInput('format', 'html');
232
- spectator.detectChanges();
233
- spectator.triggerEventHandler(editorDebugElement, 'onFocusOut', customEvent);
234
- expect(getContentSpy).toHaveBeenCalledWith({ format: 'html' });
235
- });
236
- });
237
- });
238
-
239
- describe('events', () => {
240
- beforeEach(() => {
241
- spectator.detectChanges();
242
- mockEditorFn(spectator);
243
- });
244
-
245
- describe('Window Message', () => {
246
- let focusSpy: jest.SpyInstance;
247
- beforeEach(() => {
248
- focusSpy = jest.spyOn(spectator.component.editorComponent.editor, 'focus');
249
- });
250
-
251
- it("should focus on the editor when the message is 'COPY_CONTENTLET_INLINE_EDITING_SUCCESS'", () => {
252
- window.dispatchEvent(
253
- new MessageEvent('message', {
254
- data: {
255
- name: 'COPY_CONTENTLET_INLINE_EDITING_SUCCESS',
256
- payload: {
257
- oldInode: dotcmsContentletMock.inode,
258
- inode: dotcmsContentletMock.inode
259
- }
260
- }
261
- })
262
- );
263
- spectator.detectChanges();
264
- expect(focusSpy).toHaveBeenCalled();
265
- });
266
-
267
- it("should not focus on the editor when the message is not 'COPY_CONTENTLET_INLINE_EDITING_SUCCESS'", () => {
268
- window.dispatchEvent(
269
- new MessageEvent('message', {
270
- data: { name: 'ANOTHER_EVENT' }
271
- })
272
- );
273
- spectator.detectChanges();
274
- expect(focusSpy).not.toHaveBeenCalled();
275
- });
276
- });
277
-
278
- describe('mousedown', () => {
279
- let event: MouseEvent;
280
- let editorDebugElement: DebugElement;
281
- let customEvent: {
282
- event: MouseEvent;
283
- editor: unknown;
284
- };
285
-
286
- beforeEach(() => {
287
- spectator.setInput('contentlet', {
288
- ...dotcmsContentletMock,
289
- onNumberOfPages: 2 // This will need to be overridden in tests where a different value is required
290
- });
291
- spectator.detectChanges();
292
-
293
- event = new MouseEvent('mousedown');
294
- customEvent = { event, editor: TINYMCE_EDITOR_MOCK };
295
- editorDebugElement = spectator.debugElement.query(
296
- By.directive(EditorComponent)
297
- );
298
-
299
- jest.spyOn(event, 'stopPropagation');
300
- jest.spyOn(event, 'preventDefault');
301
- });
302
-
303
- it('should postMessage the UVE if the content is in multiple pages', () => {
304
- spectator.triggerEventHandler(editorDebugElement, 'onMouseDown', customEvent);
305
-
306
- const payload = {
307
- dataset: {
308
- fieldName: 'title',
309
- inode: dotcmsContentletMock.inode,
310
- language: dotcmsContentletMock.languageId
311
- }
312
- };
313
-
314
- expect(postMessageToEditor).toHaveBeenCalledWith({
315
- action: CUSTOMER_ACTIONS.COPY_CONTENTLET_INLINE_EDITING,
316
- payload
317
- });
318
- expect(event.stopPropagation).toHaveBeenCalled();
319
- expect(event.preventDefault).toHaveBeenCalled();
320
- });
321
-
322
- it('should not postMessage the UVE if the content is in a single page', () => {
323
- spectator.setInput('contentlet', {
324
- ...dotcmsContentletMock,
325
- onNumberOfPages: 1
326
- });
327
- spectator.detectChanges();
328
- spectator.triggerEventHandler(editorDebugElement, 'onMouseDown', customEvent);
329
- expect(postMessageToEditor).not.toHaveBeenCalled();
330
- expect(event.stopPropagation).not.toHaveBeenCalled();
331
- expect(event.preventDefault).not.toHaveBeenCalled();
332
- });
333
-
334
- it('should not postMessage the UVE if the editor is already focus', () => {
335
- const hasFocusSpy = jest
336
- .spyOn(spectator.component.editorComponent.editor, 'hasFocus')
337
- .mockReturnValue(true);
338
-
339
- spectator.detectChanges();
340
- spectator.triggerEventHandler(editorDebugElement, 'onMouseDown', customEvent);
341
- expect(postMessageToEditor).not.toHaveBeenCalled();
342
- expect(event.stopPropagation).not.toHaveBeenCalled();
343
- expect(event.preventDefault).not.toHaveBeenCalled();
344
- expect(hasFocusSpy).toHaveBeenCalled();
345
- });
346
- });
347
-
348
- describe('focusout', () => {
349
- let isDirtySpy: jest.SpyInstance;
350
- let getContentSpy: jest.SpyInstance;
351
- let event: FocusEvent;
352
- let editorDebugElement: DebugElement;
353
- let customEvent: {
354
- event: FocusEvent;
355
- editor: unknown;
356
- };
357
-
358
- beforeEach(() => {
359
- const editor = spectator.component.editorComponent.editor;
360
- isDirtySpy = jest.spyOn(editor, 'isDirty');
361
- getContentSpy = jest.spyOn(editor, 'getContent');
362
-
363
- event = new FocusEvent('focusout');
364
- customEvent = { event, editor: TINYMCE_EDITOR_MOCK };
365
-
366
- editorDebugElement = spectator.debugElement.query(
367
- By.directive(EditorComponent)
368
- );
369
- });
370
-
371
- it('should not postMessage the UVE if the editor is not dirty', () => {
372
- isDirtySpy.mockReturnValue(false);
373
- getContentSpy.mockReturnValue("I'm not dirty");
374
-
375
- spectator.detectChanges();
376
-
377
- spectator.triggerEventHandler(editorDebugElement, 'onFocusOut', customEvent);
378
-
379
- expect(isDirtySpy).toHaveBeenCalled();
380
- expect(getContentSpy).toHaveBeenCalledWith({ format: 'text' });
381
- expect(postMessageToEditor).not.toHaveBeenCalled();
382
- });
383
-
384
- it('should not postMessage the UVE if the content did not change', () => {
385
- isDirtySpy.mockReturnValue(true);
386
- getContentSpy.mockReturnValue(dotcmsContentletMock.title);
387
-
388
- spectator.detectChanges();
389
- spectator.triggerEventHandler(editorDebugElement, 'onFocusOut', customEvent);
390
-
391
- expect(isDirtySpy).toHaveBeenCalled();
392
- expect(getContentSpy).toHaveBeenCalledWith({ format: 'text' });
393
- expect(postMessageToEditor).not.toHaveBeenCalled();
394
- });
395
-
396
- it('should postMessage the UVE if the content changed', () => {
397
- isDirtySpy.mockReturnValue(true);
398
- getContentSpy.mockReturnValue('New content');
399
-
400
- spectator.detectChanges();
401
- spectator.triggerEventHandler(editorDebugElement, 'onFocusOut', customEvent);
402
-
403
- const postMessageData = {
404
- action: CUSTOMER_ACTIONS.UPDATE_CONTENTLET_INLINE_EDITING,
405
- payload: {
406
- content: 'New content',
407
- dataset: {
408
- inode: dotcmsContentletMock.inode,
409
- langId: dotcmsContentletMock.languageId,
410
- fieldName: 'title'
411
- }
412
- }
413
- };
414
-
415
- expect(isDirtySpy).toHaveBeenCalled();
416
- expect(getContentSpy).toHaveBeenCalledWith({ format: 'text' });
417
- expect(postMessageToEditor).toHaveBeenCalledWith(postMessageData);
418
- });
419
- });
420
- });
421
- });
422
-
423
- afterEach(() => jest.clearAllMocks()); // Clear all mocks to avoid side effects from other tests
424
- });
@@ -1,269 +0,0 @@
1
- import { EditorComponent, TINYMCE_SCRIPT_SRC } from '@tinymce/tinymce-angular';
2
- import { EventObj } from '@tinymce/tinymce-angular/editor/Events';
3
-
4
- import {
5
- Component,
6
- ElementRef,
7
- HostListener,
8
- inject,
9
- Input,
10
- OnChanges,
11
- OnInit,
12
- Renderer2,
13
- SecurityContext,
14
- ViewChild
15
- } from '@angular/core';
16
- import { DomSanitizer } from '@angular/platform-browser';
17
-
18
- import {
19
- CUSTOMER_ACTIONS,
20
- DotCmsClient,
21
- isInsideEditor,
22
- postMessageToEditor
23
- } from '@dotcms/client';
24
-
25
- import { TINYMCE_CONFIG, DOT_EDITABLE_TEXT_FORMAT, DOT_EDITABLE_TEXT_MODE } from './utils';
26
-
27
- import { DotCMSContentlet } from '../../models';
28
-
29
- /**
30
- * Dot editable text component.
31
- * This component is responsible to render a text field that can be edited inline.
32
- *
33
- * @export
34
- * @class DotEditableTextComponent
35
- * @implements {OnInit}
36
- * @implements {OnChanges}
37
- */
38
- @Component({
39
- selector: 'dot-editable-text',
40
- standalone: true,
41
- templateUrl: './dot-editable-text.component.html',
42
- styleUrl: './dot-editable-text.component.css',
43
- imports: [EditorComponent],
44
- providers: [
45
- {
46
- provide: TINYMCE_SCRIPT_SRC,
47
- useFactory: () => {
48
- return `${DotCmsClient.dotcmsUrl}/ext/tinymcev7/tinymce.min.js`;
49
- }
50
- }
51
- ]
52
- })
53
- export class DotEditableTextComponent implements OnInit, OnChanges {
54
- @ViewChild(EditorComponent) editorComponent!: EditorComponent;
55
-
56
- /**
57
- * Represents the mode of the editor which can be `plain`, `minimal`, or `full`
58
- *
59
- * @type {DOT_EDITABLE_TEXT_MODE}
60
- * @memberof DotEditableTextComponent
61
- */
62
- @Input() mode: DOT_EDITABLE_TEXT_MODE = 'plain';
63
- /**
64
- * Represents the format of the editor which can be `text` or `html`
65
- *
66
- * @type {DOT_EDITABLE_TEXT_FORMAT}
67
- * @memberof DotEditableTextComponent
68
- */
69
- @Input() format: DOT_EDITABLE_TEXT_FORMAT = 'text';
70
- /**
71
- * Represents the `contentlet` that can be inline edited
72
- *
73
- * @type {DotCMSContentlet}
74
- * @memberof DotEditableTextComponent
75
- */
76
- @Input() contentlet!: DotCMSContentlet;
77
- /**
78
- * Represents the field name of the `contentlet` that can be edited
79
- *
80
- * @memberof DotEditableTextComponent
81
- */
82
- @Input() fieldName = '';
83
-
84
- /**
85
- * Represents the content of the `contentlet` that can be edited
86
- *
87
- * @protected
88
- * @memberof DotEditableTextComponent
89
- */
90
- protected content = '';
91
- /**
92
- * Represents the configuration of the editor
93
- *
94
- * @protected
95
- * @type {EditorComponent['init']}
96
- * @memberof DotEditableTextComponent
97
- */
98
- protected init!: EditorComponent['init'];
99
- /**
100
- * Represents if the component is inside the editor
101
- *
102
- * @protected
103
- * @type {boolean}
104
- * @memberof DotEditableTextComponent
105
- */
106
- protected isInsideEditor!: boolean;
107
-
108
- readonly #sanitizer = inject<DomSanitizer>(DomSanitizer);
109
- readonly #renderer = inject<Renderer2>(Renderer2);
110
- readonly #elementRef = inject<ElementRef>(ElementRef);
111
-
112
- /**
113
- * The TinyMCE editor
114
- *
115
- * @readonly
116
- * @memberof DotEditableTextComponent
117
- */
118
- get editor() {
119
- return this.editorComponent?.editor;
120
- }
121
-
122
- /**
123
- * Returns the number of pages the contentlet is on
124
- *
125
- * @readonly
126
- * @memberof DotEditableTextComponent
127
- */
128
- get onNumberOfPages() {
129
- return this.contentlet['onNumberOfPages'] || 1;
130
- }
131
-
132
- /**
133
- * Handle copy contentlet inline editing success event
134
- *
135
- * @param {MessageEvent} { data }
136
- * @return {*}
137
- * @memberof DotEditableTextComponent
138
- */
139
- @HostListener('window:message', ['$event'])
140
- onMessage({ data }: MessageEvent) {
141
- const { name, payload } = data;
142
- if (name !== 'COPY_CONTENTLET_INLINE_EDITING_SUCCESS') {
143
- return;
144
- }
145
-
146
- const { oldInode, inode } = payload;
147
- const currentInode = this.contentlet.inode;
148
-
149
- if (currentInode === oldInode || currentInode === inode) {
150
- this.editorComponent.editor.focus();
151
-
152
- return;
153
- }
154
- }
155
-
156
- ngOnInit() {
157
- this.isInsideEditor = isInsideEditor();
158
-
159
- if (!this.isInsideEditor) {
160
- this.innerHTMLToElement();
161
-
162
- return;
163
- }
164
-
165
- this.init = {
166
- ...TINYMCE_CONFIG[this.mode],
167
- base_url: `${DotCmsClient.dotcmsUrl}/ext/tinymcev7`
168
- };
169
- }
170
-
171
- ngOnChanges() {
172
- this.content = this.contentlet[this.fieldName] || '';
173
- if (this.editor) {
174
- this.editor.setContent(this.content, { format: this.format });
175
- }
176
- }
177
-
178
- /**
179
- * Handle mouse down event
180
- *
181
- * @param {EventObj<MouseEvent>} { event }
182
- * @return {*}
183
- * @memberof DotEditableTextComponent
184
- */
185
- onMouseDown({ event }: EventObj<MouseEvent>) {
186
- if (this.onNumberOfPages <= 1 || this.editorComponent.editor.hasFocus()) {
187
- return;
188
- }
189
-
190
- const { inode, languageId: language } = this.contentlet;
191
-
192
- event.stopPropagation();
193
- event.preventDefault();
194
-
195
- try {
196
- postMessageToEditor({
197
- action: CUSTOMER_ACTIONS.COPY_CONTENTLET_INLINE_EDITING,
198
- payload: {
199
- dataset: {
200
- inode,
201
- language,
202
- fieldName: this.fieldName
203
- }
204
- }
205
- });
206
- } catch (error) {
207
- console.error('Failed to post message to editor:', error);
208
- }
209
- }
210
- /**
211
- * Handle focus out event
212
- *
213
- * @return {*}
214
- * @memberof DotEditableTextComponent
215
- */
216
- onFocusOut() {
217
- const content = this.editor.getContent({ format: this.format });
218
-
219
- if (!this.editor.isDirty() || !this.didContentChange(content)) {
220
- return;
221
- }
222
-
223
- const { inode, languageId: langId } = this.contentlet;
224
-
225
- try {
226
- postMessageToEditor({
227
- action: CUSTOMER_ACTIONS.UPDATE_CONTENTLET_INLINE_EDITING,
228
- payload: {
229
- content,
230
- dataset: {
231
- inode,
232
- langId,
233
- fieldName: this.fieldName
234
- }
235
- }
236
- });
237
- } catch (error) {
238
- console.error('Failed to post message to editor:', error);
239
- }
240
- }
241
-
242
- /**
243
- * inner HTML to element
244
- *
245
- * @private
246
- * @param {string} editedContent
247
- * @return {*}
248
- * @memberof DotEditableTextComponent
249
- */
250
- private innerHTMLToElement() {
251
- const element = this.#elementRef.nativeElement;
252
- const safeHtml = this.#sanitizer.bypassSecurityTrustHtml(this.content);
253
- const content = this.#sanitizer.sanitize(SecurityContext.HTML, safeHtml) || '';
254
-
255
- this.#renderer.setProperty(element, 'innerHTML', content);
256
- }
257
-
258
- /**
259
- * Check if the content has changed
260
- *
261
- * @private
262
- * @param {string} editedContent
263
- * @return {*}
264
- * @memberof DotEditableTextComponent
265
- */
266
- private didContentChange(editedContent: string) {
267
- return this.content !== editedContent;
268
- }
269
- }