@dotcms/angular 0.0.1-alpha.37 → 0.0.1-alpha.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +18 -0
- package/README.md +128 -78
- package/jest.config.ts +22 -0
- package/ng-package.json +7 -0
- package/package.json +4 -21
- package/project.json +33 -0
- package/{index.d.ts → src/index.ts} +0 -1
- package/src/lib/components/dot-editable-text/dot-editable-text.component.css +4 -0
- package/src/lib/components/dot-editable-text/dot-editable-text.component.html +8 -0
- package/src/lib/components/dot-editable-text/dot-editable-text.component.spec.ts +424 -0
- package/src/lib/components/dot-editable-text/dot-editable-text.component.ts +269 -0
- package/src/lib/components/dot-editable-text/utils.ts +51 -0
- package/src/lib/components/no-component/no-component.component.css +3 -0
- package/src/lib/components/no-component/no-component.component.spec.ts +24 -0
- package/src/lib/components/no-component/no-component.component.ts +31 -0
- package/src/lib/layout/column/column.component.css +99 -0
- package/src/lib/layout/column/column.component.spec.ts +33 -0
- package/src/lib/layout/column/column.component.ts +49 -0
- package/src/lib/layout/container/container.component.css +9 -0
- package/src/lib/layout/container/container.component.html +26 -0
- package/src/lib/layout/container/container.component.spec.ts +205 -0
- package/src/lib/layout/container/container.component.ts +140 -0
- package/src/lib/layout/contentlet/contentlet.component.spec.ts +22 -0
- package/src/lib/layout/contentlet/contentlet.component.ts +101 -0
- package/src/lib/layout/dotcms-layout/dotcms-layout.component.css +3 -0
- package/src/lib/layout/dotcms-layout/dotcms-layout.component.spec.ts +195 -0
- package/src/lib/layout/dotcms-layout/dotcms-layout.component.ts +150 -0
- package/src/lib/layout/row/row.component.css +6 -0
- package/src/lib/layout/row/row.component.spec.ts +28 -0
- package/src/lib/layout/row/row.component.ts +32 -0
- package/{lib/models/dotcms.model.d.ts → src/lib/models/dotcms.model.ts} +21 -3
- package/src/lib/models/index.ts +47 -0
- package/{lib/services/dotcms-context/page-context.service.d.ts → src/lib/services/dotcms-context/page-context.service.ts} +41 -12
- package/src/lib/services/dotcms-context/page-context.spec.ts +80 -0
- package/src/lib/utils/index.ts +92 -0
- package/src/lib/utils/testing.utils.ts +1019 -0
- package/src/test-setup.ts +8 -0
- package/tsconfig.json +29 -0
- package/tsconfig.lib.json +12 -0
- package/tsconfig.lib.prod.json +9 -0
- package/tsconfig.spec.json +11 -0
- package/dotcms-angular.d.ts.map +0 -1
- package/esm2022/dotcms-angular.mjs +0 -5
- package/esm2022/index.mjs +0 -5
- package/esm2022/lib/components/dot-editable-text/dot-editable-text.component.mjs +0 -225
- package/esm2022/lib/components/dot-editable-text/utils.mjs +0 -43
- package/esm2022/lib/components/no-component/no-component.component.mjs +0 -27
- package/esm2022/lib/layout/column/column.component.mjs +0 -33
- package/esm2022/lib/layout/container/container.component.mjs +0 -78
- package/esm2022/lib/layout/contentlet/contentlet.component.mjs +0 -65
- package/esm2022/lib/layout/dotcms-layout/dotcms-layout.component.mjs +0 -87
- package/esm2022/lib/layout/row/row.component.mjs +0 -23
- package/esm2022/lib/models/dotcms.model.mjs +0 -3
- package/esm2022/lib/models/index.mjs +0 -3
- package/esm2022/lib/services/dotcms-context/page-context.service.mjs +0 -75
- package/esm2022/lib/utils/index.mjs +0 -57
- package/fesm2022/dotcms-angular.mjs +0 -697
- package/fesm2022/dotcms-angular.mjs.map +0 -1
- package/index.d.ts.map +0 -1
- package/lib/components/dot-editable-text/dot-editable-text.component.d.ts +0 -129
- package/lib/components/dot-editable-text/dot-editable-text.component.d.ts.map +0 -1
- package/lib/components/dot-editable-text/utils.d.ts +0 -7
- package/lib/components/dot-editable-text/utils.d.ts.map +0 -1
- package/lib/components/no-component/no-component.component.d.ts +0 -13
- package/lib/components/no-component/no-component.component.d.ts.map +0 -1
- package/lib/layout/column/column.component.d.ts +0 -11
- package/lib/layout/column/column.component.d.ts.map +0 -1
- package/lib/layout/container/container.component.d.ts +0 -34
- package/lib/layout/container/container.component.d.ts.map +0 -1
- package/lib/layout/contentlet/contentlet.component.d.ts +0 -19
- package/lib/layout/contentlet/contentlet.component.d.ts.map +0 -1
- package/lib/layout/dotcms-layout/dotcms-layout.component.d.ts +0 -54
- package/lib/layout/dotcms-layout/dotcms-layout.component.d.ts.map +0 -1
- package/lib/layout/row/row.component.d.ts +0 -8
- package/lib/layout/row/row.component.d.ts.map +0 -1
- package/lib/models/dotcms.model.d.ts.map +0 -1
- package/lib/models/index.d.ts +0 -11
- package/lib/models/index.d.ts.map +0 -1
- package/lib/services/dotcms-context/page-context.service.d.ts.map +0 -1
- package/lib/utils/index.d.ts +0 -49
- package/lib/utils/index.d.ts.map +0 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
|
|
3
|
+
import { ContentletComponent } from './contentlet.component';
|
|
4
|
+
|
|
5
|
+
describe('ContentletComponent', () => {
|
|
6
|
+
let component: ContentletComponent;
|
|
7
|
+
let fixture: ComponentFixture<ContentletComponent>;
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
await TestBed.configureTestingModule({
|
|
11
|
+
imports: [ContentletComponent]
|
|
12
|
+
}).compileComponents();
|
|
13
|
+
|
|
14
|
+
fixture = TestBed.createComponent(ContentletComponent);
|
|
15
|
+
component = fixture.componentInstance;
|
|
16
|
+
fixture.detectChanges();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should create', () => {
|
|
20
|
+
expect(component).toBeTruthy();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, HostBinding, Input, OnChanges } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
import { DotCMSContentlet } from '../../models';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This component is responsible to display a contentlet.
|
|
7
|
+
*
|
|
8
|
+
* @export
|
|
9
|
+
* @class ContentletComponent
|
|
10
|
+
* @implements {OnChanges}
|
|
11
|
+
*/
|
|
12
|
+
@Component({
|
|
13
|
+
selector: 'dotcms-contentlet-wrapper',
|
|
14
|
+
standalone: true,
|
|
15
|
+
template: '<ng-content></ng-content>',
|
|
16
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
17
|
+
})
|
|
18
|
+
export class ContentletComponent implements OnChanges {
|
|
19
|
+
/**
|
|
20
|
+
* The contentlet object containing content data.
|
|
21
|
+
*
|
|
22
|
+
* @type {DotCMSContentlet}
|
|
23
|
+
* @memberof ContentletComponent
|
|
24
|
+
*/
|
|
25
|
+
@Input({ required: true }) contentlet!: DotCMSContentlet;
|
|
26
|
+
/**
|
|
27
|
+
* The container data (as string) where the contentlet is located.
|
|
28
|
+
*
|
|
29
|
+
* @type {string}
|
|
30
|
+
* @memberof ContentletComponent
|
|
31
|
+
*/
|
|
32
|
+
@Input() container!: string;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The identifier of contentlet component.
|
|
36
|
+
*
|
|
37
|
+
* @type {(string | null)}
|
|
38
|
+
* @memberof ContentletComponent
|
|
39
|
+
*/
|
|
40
|
+
@HostBinding('attr.data-dot-identifier') identifier: string | null = null;
|
|
41
|
+
/**
|
|
42
|
+
* The base type of contentlet component.
|
|
43
|
+
*
|
|
44
|
+
* @type {(string | null)}
|
|
45
|
+
* @memberof ContentletComponent
|
|
46
|
+
*/
|
|
47
|
+
@HostBinding('attr.data-dot-basetype') baseType: string | null = null;
|
|
48
|
+
/**
|
|
49
|
+
* The title of contentlet component.
|
|
50
|
+
*
|
|
51
|
+
* @type {(string | null)}
|
|
52
|
+
* @memberof ContentletComponent
|
|
53
|
+
*/
|
|
54
|
+
@HostBinding('attr.data-dot-title') title: string | null = null;
|
|
55
|
+
/**
|
|
56
|
+
* The inode of contentlet component.
|
|
57
|
+
*
|
|
58
|
+
* @type {(string | null)}
|
|
59
|
+
* @memberof ContentletComponent
|
|
60
|
+
*/
|
|
61
|
+
@HostBinding('attr.data-dot-inode') inode: string | null = null;
|
|
62
|
+
/**
|
|
63
|
+
* The type of contentlet component.
|
|
64
|
+
*
|
|
65
|
+
* @type {(string | null)}
|
|
66
|
+
* @memberof ContentletComponent
|
|
67
|
+
*/
|
|
68
|
+
@HostBinding('attr.data-dot-type') dotType: string | null = null;
|
|
69
|
+
/**
|
|
70
|
+
* The container of contentlet component.
|
|
71
|
+
*
|
|
72
|
+
* @type {(string | null)}
|
|
73
|
+
* @memberof ContentletComponent
|
|
74
|
+
*/
|
|
75
|
+
@HostBinding('attr.data-dot-container') dotContainer: string | null = null;
|
|
76
|
+
/**
|
|
77
|
+
* The number of pages where the contentlet appears
|
|
78
|
+
*
|
|
79
|
+
* @type {(string | null)}
|
|
80
|
+
* @memberof ContentletComponent
|
|
81
|
+
*/
|
|
82
|
+
@HostBinding('attr.data-dot-on-number-of-pages') numberOfPages: string | null = null;
|
|
83
|
+
/**
|
|
84
|
+
* The content of contentlet component.
|
|
85
|
+
*
|
|
86
|
+
* @type {(string | null)}
|
|
87
|
+
* @memberof ContentletComponent
|
|
88
|
+
*/
|
|
89
|
+
@HostBinding('attr.data-dot-object') dotContent: string | null = null;
|
|
90
|
+
|
|
91
|
+
ngOnChanges() {
|
|
92
|
+
this.identifier = this.contentlet.identifier;
|
|
93
|
+
this.baseType = this.contentlet.baseType;
|
|
94
|
+
this.title = this.contentlet.title;
|
|
95
|
+
this.inode = this.contentlet.inode;
|
|
96
|
+
this.dotType = this.contentlet.contentType;
|
|
97
|
+
this.dotContainer = this.container;
|
|
98
|
+
this.numberOfPages = this.contentlet['onNumberOfPages'];
|
|
99
|
+
this.dotContent = 'contentlet';
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { expect } from '@jest/globals';
|
|
2
|
+
import { Spectator, createRoutingFactory } from '@ngneat/spectator/jest';
|
|
3
|
+
import { MockComponent } from 'ng-mocks';
|
|
4
|
+
import { of } from 'rxjs';
|
|
5
|
+
|
|
6
|
+
import { Component, Input } from '@angular/core';
|
|
7
|
+
import { ActivatedRoute, Router } from '@angular/router';
|
|
8
|
+
|
|
9
|
+
import * as dotcmsClient from '@dotcms/client';
|
|
10
|
+
|
|
11
|
+
import { PageResponseMock, PageResponseOneRowMock } from './../../utils/testing.utils';
|
|
12
|
+
import { DotcmsLayoutComponent } from './dotcms-layout.component';
|
|
13
|
+
|
|
14
|
+
import { DotCMSContentlet, DotCMSPageAsset } from '../../models';
|
|
15
|
+
import { PageContextService } from '../../services/dotcms-context/page-context.service';
|
|
16
|
+
import { RowComponent } from '../row/row.component';
|
|
17
|
+
|
|
18
|
+
interface Callback {
|
|
19
|
+
[key: string]: (data: unknown) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface DotCmsClientMock extends dotcmsClient.DotCmsClient {
|
|
23
|
+
editor: {
|
|
24
|
+
on: (type: string, callbackFn: (data: unknown) => void) => void;
|
|
25
|
+
off: jest.Mock;
|
|
26
|
+
callbacks: Callback;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Component({
|
|
31
|
+
selector: 'dotcms-mock-component',
|
|
32
|
+
standalone: true,
|
|
33
|
+
template: 'Hello world'
|
|
34
|
+
})
|
|
35
|
+
class DotcmsSDKMockComponent {
|
|
36
|
+
@Input() contentlet!: DotCMSContentlet;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
jest.mock('@dotcms/client', () => ({
|
|
40
|
+
...jest.requireActual('@dotcms/client'),
|
|
41
|
+
isInsideEditor: jest.fn().mockReturnValue(true),
|
|
42
|
+
initEditor: jest.fn(),
|
|
43
|
+
updateNavigation: jest.fn(),
|
|
44
|
+
postMessageToEditor: jest.fn(),
|
|
45
|
+
DotCmsClient: {
|
|
46
|
+
instance: {
|
|
47
|
+
editor: {
|
|
48
|
+
on: function (type: string, callbackFn: (data: unknown) => void): void {
|
|
49
|
+
this.callbacks[type] = callbackFn;
|
|
50
|
+
},
|
|
51
|
+
off: jest.fn(),
|
|
52
|
+
callbacks: {} as Callback
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
CUSTOMER_ACTIONS: {
|
|
57
|
+
GET_PAGE_DATA: 'get-page-data'
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
const { DotCmsClient } = dotcmsClient as jest.Mocked<typeof dotcmsClient>;
|
|
62
|
+
|
|
63
|
+
describe('DotcmsLayoutComponent', () => {
|
|
64
|
+
let spectator: Spectator<DotcmsLayoutComponent>;
|
|
65
|
+
let pageContextService: PageContextService;
|
|
66
|
+
|
|
67
|
+
const createComponent = createRoutingFactory({
|
|
68
|
+
component: DotcmsLayoutComponent,
|
|
69
|
+
imports: [MockComponent(RowComponent)],
|
|
70
|
+
providers: [
|
|
71
|
+
PageContextService,
|
|
72
|
+
{ provide: ActivatedRoute, useValue: { url: of([]) } },
|
|
73
|
+
{ provide: Router, useValue: {} }
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
beforeEach(() => {
|
|
78
|
+
spectator = createComponent({
|
|
79
|
+
props: {
|
|
80
|
+
pageAsset: PageResponseMock as unknown as DotCMSPageAsset,
|
|
81
|
+
components: {
|
|
82
|
+
Banner: Promise.resolve(DotcmsSDKMockComponent)
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
detectChanges: false
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
pageContextService = spectator.inject(PageContextService, true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
afterEach(() => {
|
|
92
|
+
jest.clearAllMocks();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should render rows', () => {
|
|
96
|
+
spectator.detectChanges();
|
|
97
|
+
expect(spectator.queryAll(RowComponent).length).toBe(3);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('should save pageContext', () => {
|
|
101
|
+
const setContextSpy = jest.spyOn(pageContextService, 'setContext');
|
|
102
|
+
spectator.detectChanges();
|
|
103
|
+
expect(setContextSpy).toHaveBeenCalled();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('inside editor', () => {
|
|
107
|
+
it('should call initEditor and updateNavigation from @dotcms/client', () => {
|
|
108
|
+
const initEditorSpy = jest.spyOn(dotcmsClient, 'initEditor');
|
|
109
|
+
const updateNavigationSpy = jest.spyOn(dotcmsClient, 'updateNavigation');
|
|
110
|
+
|
|
111
|
+
spectator.detectChanges();
|
|
112
|
+
expect(initEditorSpy).toHaveBeenCalled();
|
|
113
|
+
expect(updateNavigationSpy).toHaveBeenCalled();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('onReload', () => {
|
|
117
|
+
const client = DotCmsClient.instance;
|
|
118
|
+
let editorOnSpy: jest.SpyInstance;
|
|
119
|
+
|
|
120
|
+
beforeEach(() => {
|
|
121
|
+
editorOnSpy = jest.spyOn(client.editor, 'on');
|
|
122
|
+
spectator.setInput('onReload', () => {
|
|
123
|
+
/* do nothing */
|
|
124
|
+
});
|
|
125
|
+
spectator.detectChanges();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should subscribe to the `CHANGE` event', () => {
|
|
129
|
+
expect(editorOnSpy).toHaveBeenCalled();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should remove listener on unmount', () => {
|
|
133
|
+
spectator.component.ngOnDestroy();
|
|
134
|
+
spectator.detectChanges();
|
|
135
|
+
|
|
136
|
+
expect(client.editor.off).toHaveBeenCalledWith('changes');
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('client is ready', () => {
|
|
141
|
+
const query = { query: 'query { ... }' };
|
|
142
|
+
|
|
143
|
+
beforeEach(() => {
|
|
144
|
+
spectator.setInput('editor', query);
|
|
145
|
+
spectator.detectChanges();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should post message to editor', () => {
|
|
149
|
+
spectator.detectChanges();
|
|
150
|
+
expect(dotcmsClient.postMessageToEditor).toHaveBeenCalledWith({
|
|
151
|
+
action: dotcmsClient.CUSTOMER_ACTIONS.CLIENT_READY,
|
|
152
|
+
payload: query
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('onChange', () => {
|
|
158
|
+
const client = DotCmsClient.instance;
|
|
159
|
+
beforeEach(() => spectator.detectChanges());
|
|
160
|
+
|
|
161
|
+
it('should update the page asset when changes are made in the editor', () => {
|
|
162
|
+
const editorOnSpy = jest.spyOn(client.editor, 'on');
|
|
163
|
+
expect(editorOnSpy).toHaveBeenCalledWith('changes', expect.any(Function));
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe('template', () => {
|
|
169
|
+
beforeEach(() => spectator.detectChanges());
|
|
170
|
+
|
|
171
|
+
it('should render rows', () => {
|
|
172
|
+
expect(spectator.queryAll(RowComponent).length).toBe(3);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should pass the correct row to RowComponent', () => {
|
|
176
|
+
const rowComponents = spectator.queryAll(RowComponent);
|
|
177
|
+
const rows = PageResponseMock.layout.body.rows;
|
|
178
|
+
expect(rowComponents.length).toBe(rows.length);
|
|
179
|
+
|
|
180
|
+
rowComponents.forEach((component, index) => {
|
|
181
|
+
expect(component.row).toEqual(rows[index]);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('should update the page asset when changes are made in the editor', () => {
|
|
186
|
+
const { editor } = DotCmsClient.instance as DotCmsClientMock;
|
|
187
|
+
editor.callbacks['changes'](PageResponseOneRowMock);
|
|
188
|
+
spectator.detectChanges();
|
|
189
|
+
const rowComponents = spectator.queryAll(RowComponent);
|
|
190
|
+
const rows = PageResponseMock.layout.body.rows;
|
|
191
|
+
expect(rowComponents.length).toBe(1);
|
|
192
|
+
expect(rowComponents[0].row).toEqual(rows[0]);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
});
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { AsyncPipe } from '@angular/common';
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
Component,
|
|
5
|
+
DestroyRef,
|
|
6
|
+
Input,
|
|
7
|
+
OnInit,
|
|
8
|
+
inject
|
|
9
|
+
} from '@angular/core';
|
|
10
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
11
|
+
import { ActivatedRoute } from '@angular/router';
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
CUSTOMER_ACTIONS,
|
|
15
|
+
DotCmsClient,
|
|
16
|
+
EditorConfig,
|
|
17
|
+
initEditor,
|
|
18
|
+
isInsideEditor,
|
|
19
|
+
postMessageToEditor,
|
|
20
|
+
updateNavigation
|
|
21
|
+
} from '@dotcms/client';
|
|
22
|
+
|
|
23
|
+
import { DotCMSPageComponent } from '../../models';
|
|
24
|
+
import { DotCMSPageAsset } from '../../models/dotcms.model';
|
|
25
|
+
import { PageContextService } from '../../services/dotcms-context/page-context.service';
|
|
26
|
+
import { RowComponent } from '../row/row.component';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* `DotcmsLayoutComponent` is a class that represents the layout for a DotCMS page.
|
|
30
|
+
* It includes a `pageAsset` property that represents the DotCMS page asset and a `components` property that represents the dynamic components for the page.
|
|
31
|
+
*
|
|
32
|
+
* @export
|
|
33
|
+
* @class DotcmsLayoutComponent
|
|
34
|
+
*/
|
|
35
|
+
@Component({
|
|
36
|
+
selector: 'dotcms-layout',
|
|
37
|
+
standalone: true,
|
|
38
|
+
imports: [RowComponent, AsyncPipe],
|
|
39
|
+
template: `
|
|
40
|
+
@if (pageAsset$ | async; as page) {
|
|
41
|
+
@for (row of this.page?.layout?.body?.rows; track $index) {
|
|
42
|
+
<dotcms-row [row]="row" />
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
`,
|
|
46
|
+
styleUrl: './dotcms-layout.component.css',
|
|
47
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
48
|
+
})
|
|
49
|
+
export class DotcmsLayoutComponent implements OnInit {
|
|
50
|
+
private _pageAsset!: DotCMSPageAsset;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Represents the DotCMS page asset.
|
|
54
|
+
*
|
|
55
|
+
* @type {DotCMSPageAsset}
|
|
56
|
+
* @memberof DotcmsLayoutComponent
|
|
57
|
+
*/
|
|
58
|
+
@Input({ required: true })
|
|
59
|
+
set pageAsset(value: DotCMSPageAsset) {
|
|
60
|
+
this._pageAsset = value;
|
|
61
|
+
if (!value.layout) {
|
|
62
|
+
console.warn(
|
|
63
|
+
'Warning: pageAsset does not have a `layout` property. Might be using an advaced template or your dotCMS instance not have a enterprise license.'
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns the DotCMS page asset.
|
|
70
|
+
*
|
|
71
|
+
* @readonly
|
|
72
|
+
* @type {DotCMSPageAsset}
|
|
73
|
+
* @memberof DotcmsLayoutComponent
|
|
74
|
+
*/
|
|
75
|
+
get pageAsset(): DotCMSPageAsset {
|
|
76
|
+
return this._pageAsset;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The `components` property is a record of dynamic components for each Contentlet on the page.
|
|
81
|
+
*
|
|
82
|
+
* @type {DotCMSPageComponent}
|
|
83
|
+
* @memberof DotcmsLayoutComponent
|
|
84
|
+
* @required
|
|
85
|
+
*/
|
|
86
|
+
@Input({ required: true }) components!: DotCMSPageComponent;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The `onReload` property is a function that reloads the page after changes are made.
|
|
90
|
+
*
|
|
91
|
+
* @memberof DotcmsLayoutComponent
|
|
92
|
+
* @deprecated In future implementation we will be listening for the changes from the editor to update the page state so reload will not be needed.
|
|
93
|
+
*/
|
|
94
|
+
@Input() onReload!: () => void;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
*
|
|
98
|
+
* @type {DotCMSFetchConfig}
|
|
99
|
+
* @memberof DotCMSPageEditorConfig
|
|
100
|
+
* @description The configuration custom params for data fetching on Edit Mode.
|
|
101
|
+
* @example <caption>Example with Custom GraphQL query</caption>
|
|
102
|
+
* <dotcms-layout [editor]="{ query: 'query { ... }' }"/>
|
|
103
|
+
*
|
|
104
|
+
* @example <caption>Example usage with Custom Page API parameters</caption>
|
|
105
|
+
* <dotcms-layout [editor]="{ params: { depth: '2' } }"/>;
|
|
106
|
+
*/
|
|
107
|
+
@Input() editor!: EditorConfig;
|
|
108
|
+
|
|
109
|
+
private readonly route = inject(ActivatedRoute);
|
|
110
|
+
private readonly pageContextService = inject(PageContextService);
|
|
111
|
+
private readonly destroyRef$ = inject(DestroyRef);
|
|
112
|
+
private client!: DotCmsClient;
|
|
113
|
+
protected readonly pageAsset$ = this.pageContextService.currentPage$;
|
|
114
|
+
|
|
115
|
+
ngOnInit() {
|
|
116
|
+
this.pageContextService.setContext(this.pageAsset, this.components);
|
|
117
|
+
|
|
118
|
+
if (!isInsideEditor()) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
this.client = DotCmsClient.instance;
|
|
123
|
+
this.route.url.pipe(takeUntilDestroyed(this.destroyRef$)).subscribe((urlSegments) => {
|
|
124
|
+
const pathname = '/' + urlSegments.join('/');
|
|
125
|
+
|
|
126
|
+
initEditor({ pathname });
|
|
127
|
+
updateNavigation(pathname || '/');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
this.client.editor.on('changes', (data) => {
|
|
131
|
+
if (this.onReload) {
|
|
132
|
+
this.onReload();
|
|
133
|
+
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.pageContextService.setPageAsset(data as DotCMSPageAsset);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
postMessageToEditor({ action: CUSTOMER_ACTIONS.CLIENT_READY, payload: this.editor });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
ngOnDestroy() {
|
|
144
|
+
if (!isInsideEditor()) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
this.client.editor.off('changes');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Spectator, createComponentFactory } from '@ngneat/spectator/jest';
|
|
2
|
+
import { MockComponent } from 'ng-mocks';
|
|
3
|
+
|
|
4
|
+
import { RowComponent } from './row.component';
|
|
5
|
+
|
|
6
|
+
import { DotPageAssetLayoutRow } from '../../models';
|
|
7
|
+
import { PageResponseMock } from '../../utils/testing.utils';
|
|
8
|
+
import { ColumnComponent } from '../column/column.component';
|
|
9
|
+
|
|
10
|
+
describe('RowComponent', () => {
|
|
11
|
+
let spectator: Spectator<RowComponent>;
|
|
12
|
+
const createComponent = createComponentFactory({
|
|
13
|
+
component: RowComponent,
|
|
14
|
+
imports: [MockComponent(ColumnComponent)]
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
spectator = createComponent({
|
|
19
|
+
props: {
|
|
20
|
+
row: PageResponseMock.layout.body.rows[1] as DotPageAssetLayoutRow
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should render two columns', () => {
|
|
26
|
+
expect(spectator.queryAll(ColumnComponent)?.length).toBe(4);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
|
2
|
+
|
|
3
|
+
import { DotPageAssetLayoutRow } from '../../models';
|
|
4
|
+
import { ColumnComponent } from '../column/column.component';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This component is responsible to display a row with columns.
|
|
8
|
+
*
|
|
9
|
+
* @export
|
|
10
|
+
* @class RowComponent
|
|
11
|
+
*/
|
|
12
|
+
@Component({
|
|
13
|
+
selector: 'dotcms-row',
|
|
14
|
+
standalone: true,
|
|
15
|
+
imports: [ColumnComponent],
|
|
16
|
+
template: `
|
|
17
|
+
@for (column of row.columns; track $index) {
|
|
18
|
+
<dotcms-column [column]="column" />
|
|
19
|
+
}
|
|
20
|
+
`,
|
|
21
|
+
styleUrl: './row.component.css',
|
|
22
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
23
|
+
})
|
|
24
|
+
export class RowComponent {
|
|
25
|
+
/**
|
|
26
|
+
* The row object containing the columns.
|
|
27
|
+
*
|
|
28
|
+
* @type {DotPageAssetLayoutRow}
|
|
29
|
+
* @memberof RowComponent
|
|
30
|
+
*/
|
|
31
|
+
@Input({ required: true }) row!: DotPageAssetLayoutRow;
|
|
32
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
1
3
|
export interface DotCMSPageAsset {
|
|
2
4
|
canCreateTemplate: boolean;
|
|
3
5
|
containers: DotCMSPageAssetContainer;
|
|
@@ -20,6 +22,7 @@ export interface DotCMSPageAsset {
|
|
|
20
22
|
forward: boolean;
|
|
21
23
|
};
|
|
22
24
|
}
|
|
25
|
+
|
|
23
26
|
export interface DotPageAssetLayoutRow {
|
|
24
27
|
identifier: number;
|
|
25
28
|
value?: string;
|
|
@@ -27,6 +30,7 @@ export interface DotPageAssetLayoutRow {
|
|
|
27
30
|
columns: DotPageAssetLayoutColumn[];
|
|
28
31
|
styleClass?: string;
|
|
29
32
|
}
|
|
33
|
+
|
|
30
34
|
export interface DotPageAssetLayoutColumn {
|
|
31
35
|
preview: boolean;
|
|
32
36
|
containers: DotCMSContainer[];
|
|
@@ -36,6 +40,7 @@ export interface DotPageAssetLayoutColumn {
|
|
|
36
40
|
left: number;
|
|
37
41
|
styleClass?: string;
|
|
38
42
|
}
|
|
43
|
+
|
|
39
44
|
export interface DotCMSPageAssetContainer {
|
|
40
45
|
[key: string]: {
|
|
41
46
|
container: DotCMSContainer;
|
|
@@ -45,6 +50,7 @@ export interface DotCMSPageAssetContainer {
|
|
|
45
50
|
};
|
|
46
51
|
};
|
|
47
52
|
}
|
|
53
|
+
|
|
48
54
|
export interface DotCMSContainer {
|
|
49
55
|
identifier: string;
|
|
50
56
|
uuid: string;
|
|
@@ -87,6 +93,7 @@ export interface DotCMSContainer {
|
|
|
87
93
|
contentlets: DotCMSContentlet[];
|
|
88
94
|
parentPermissionable: DotCMSSiteParentPermissionable;
|
|
89
95
|
}
|
|
96
|
+
|
|
90
97
|
export interface DotCMSContentlet {
|
|
91
98
|
archived: boolean;
|
|
92
99
|
baseType: string;
|
|
@@ -124,8 +131,9 @@ export interface DotCMSContentlet {
|
|
|
124
131
|
contentTypeIcon?: string;
|
|
125
132
|
variant?: string;
|
|
126
133
|
__icon__?: string;
|
|
127
|
-
[key: string]: any;
|
|
134
|
+
[key: string]: any; // This is a catch-all for any other custom properties that might be on the contentlet.
|
|
128
135
|
}
|
|
136
|
+
|
|
129
137
|
export interface DotcmsNavigationItem {
|
|
130
138
|
code?: any;
|
|
131
139
|
folder: string;
|
|
@@ -139,6 +147,7 @@ export interface DotcmsNavigationItem {
|
|
|
139
147
|
target: string;
|
|
140
148
|
order: number;
|
|
141
149
|
}
|
|
150
|
+
|
|
142
151
|
interface DotCMSTemplate {
|
|
143
152
|
iDate: number;
|
|
144
153
|
type: string;
|
|
@@ -173,6 +182,7 @@ interface DotCMSTemplate {
|
|
|
173
182
|
new: boolean;
|
|
174
183
|
canEdit: boolean;
|
|
175
184
|
}
|
|
185
|
+
|
|
176
186
|
interface DotCMSPage {
|
|
177
187
|
template: string;
|
|
178
188
|
modDate: number;
|
|
@@ -218,6 +228,7 @@ interface DotCMSPage {
|
|
|
218
228
|
liveInode: string;
|
|
219
229
|
shortyLive: string;
|
|
220
230
|
}
|
|
231
|
+
|
|
221
232
|
interface DotCMSViewAs {
|
|
222
233
|
language: {
|
|
223
234
|
id: number;
|
|
@@ -228,6 +239,7 @@ interface DotCMSViewAs {
|
|
|
228
239
|
};
|
|
229
240
|
mode: string;
|
|
230
241
|
}
|
|
242
|
+
|
|
231
243
|
interface DotCMSLayout {
|
|
232
244
|
pageWidth: string;
|
|
233
245
|
width: string;
|
|
@@ -238,6 +250,7 @@ interface DotCMSLayout {
|
|
|
238
250
|
body: DotPageAssetLayoutBody;
|
|
239
251
|
sidebar: DotPageAssetLayoutSidebar;
|
|
240
252
|
}
|
|
253
|
+
|
|
241
254
|
interface DotCMSContainerStructure {
|
|
242
255
|
id: string;
|
|
243
256
|
structureId: string;
|
|
@@ -246,6 +259,7 @@ interface DotCMSContainerStructure {
|
|
|
246
259
|
code: string;
|
|
247
260
|
contentTypeVar: string;
|
|
248
261
|
}
|
|
262
|
+
|
|
249
263
|
interface DotPageAssetLayoutSidebar {
|
|
250
264
|
preview: boolean;
|
|
251
265
|
containers: DotCMSContainer[];
|
|
@@ -253,9 +267,11 @@ interface DotPageAssetLayoutSidebar {
|
|
|
253
267
|
widthPercent: number;
|
|
254
268
|
width: string;
|
|
255
269
|
}
|
|
270
|
+
|
|
256
271
|
interface DotPageAssetLayoutBody {
|
|
257
272
|
rows: DotPageAssetLayoutRow[];
|
|
258
273
|
}
|
|
274
|
+
|
|
259
275
|
interface DotCMSSite {
|
|
260
276
|
lowIndexPriority: boolean;
|
|
261
277
|
name: string;
|
|
@@ -306,12 +322,14 @@ interface DotCMSSite {
|
|
|
306
322
|
sortOrder: number;
|
|
307
323
|
contentType: DotCMSSiteContentType;
|
|
308
324
|
}
|
|
325
|
+
|
|
309
326
|
interface DotCMSSiteContentType {
|
|
310
327
|
owner?: any;
|
|
311
328
|
parentPermissionable: DotCMSSiteParentPermissionable;
|
|
312
329
|
permissionId: string;
|
|
313
330
|
permissionType: string;
|
|
314
331
|
}
|
|
332
|
+
|
|
315
333
|
export interface DotCMSSiteParentPermissionable {
|
|
316
334
|
Inode: string;
|
|
317
335
|
Identifier: string;
|
|
@@ -326,6 +344,7 @@ export interface DotCMSSiteParentPermissionable {
|
|
|
326
344
|
childrenPermissionable?: any;
|
|
327
345
|
variantId?: string;
|
|
328
346
|
}
|
|
347
|
+
|
|
329
348
|
interface DotCMSSiteStructure {
|
|
330
349
|
iDate: number;
|
|
331
350
|
type: string;
|
|
@@ -371,6 +390,7 @@ interface DotCMSSiteStructure {
|
|
|
371
390
|
versionId: string;
|
|
372
391
|
versionType: string;
|
|
373
392
|
}
|
|
393
|
+
|
|
374
394
|
interface DotCMSSiteField {
|
|
375
395
|
iDate: number;
|
|
376
396
|
type: string;
|
|
@@ -412,5 +432,3 @@ interface DotCMSSiteField {
|
|
|
412
432
|
versionId: string;
|
|
413
433
|
versionType: string;
|
|
414
434
|
}
|
|
415
|
-
export {};
|
|
416
|
-
//# sourceMappingURL=dotcms.model.d.ts.map
|