@nascentdigital/funnel-editor-contentful 4.6.7 → 5.0.2

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 (129) hide show
  1. package/dist/Editor.d.ts +6 -1
  2. package/dist/Editor.js +17 -1
  3. package/dist/EditorApp.js +11 -9
  4. package/dist/EditorPageRouter.d.ts +1 -0
  5. package/dist/EditorPageRouter.js +40 -0
  6. package/dist/EntryEditor.js +43 -1
  7. package/dist/EntrySidebar.js +18 -1
  8. package/dist/asset/index.d.ts +1 -0
  9. package/dist/{page/hooks → asset}/index.js +1 -1
  10. package/dist/asset/repository/AssetRepository.d.ts +10 -0
  11. package/dist/asset/repository/AssetRepository.js +33 -0
  12. package/dist/asset/repository/index.d.ts +1 -0
  13. package/dist/{core/api → asset/repository}/index.js +1 -3
  14. package/dist/collection/controller/ContentfulCollectionController.d.ts +41 -0
  15. package/dist/collection/controller/ContentfulCollectionController.js +278 -0
  16. package/dist/collection/controller/ContentfulCollectionControllerContainer.d.ts +5 -0
  17. package/dist/collection/controller/ContentfulCollectionControllerContainer.js +28 -0
  18. package/dist/collection/controller/index.d.ts +3 -0
  19. package/dist/collection/controller/index.js +19 -0
  20. package/dist/collection/controller/useContentfulCollectionController.d.ts +2 -0
  21. package/dist/collection/controller/useContentfulCollectionController.js +8 -0
  22. package/dist/collection/domain/Collection.d.ts +108 -0
  23. package/dist/collection/domain/Collection.js +386 -0
  24. package/dist/collection/domain/index.d.ts +1 -0
  25. package/dist/collection/domain/index.js +17 -0
  26. package/dist/collection/index.d.ts +3 -0
  27. package/dist/collection/index.js +19 -0
  28. package/dist/collection/repository/CollectionRepository.d.ts +49 -0
  29. package/dist/collection/repository/CollectionRepository.js +210 -0
  30. package/dist/collection/repository/index.d.ts +1 -0
  31. package/dist/collection/repository/index.js +17 -0
  32. package/dist/collection/screens/CollectionEditor.d.ts +1 -0
  33. package/dist/collection/screens/CollectionEditor.js +59 -0
  34. package/dist/collection/screens/index.d.ts +1 -0
  35. package/dist/collection/screens/index.js +17 -0
  36. package/dist/core/bridge/AppBridgeContainer.d.ts +9 -0
  37. package/dist/core/bridge/AppBridgeContainer.js +55 -0
  38. package/dist/core/bridge/AppBridgeContext.d.ts +8 -0
  39. package/dist/core/bridge/AppBridgeContext.js +11 -0
  40. package/dist/core/bridge/AppMessage.d.ts +19 -0
  41. package/dist/core/bridge/AppMessage.js +19 -0
  42. package/dist/core/bridge/index.d.ts +4 -0
  43. package/dist/core/bridge/index.js +20 -0
  44. package/dist/core/bridge/useAppBridge.d.ts +8 -0
  45. package/dist/core/bridge/useAppBridge.js +24 -0
  46. package/dist/core/client/ContentfulClientContainer.d.ts +8 -0
  47. package/dist/core/client/ContentfulClientContainer.js +43 -0
  48. package/dist/core/client/ContentfulClientContext.d.ts +8 -0
  49. package/dist/core/client/ContentfulClientContext.js +8 -0
  50. package/dist/core/client/index.d.ts +3 -0
  51. package/dist/core/client/index.js +19 -0
  52. package/dist/core/client/useContentfulClient.d.ts +4 -0
  53. package/dist/core/client/useContentfulClient.js +24 -0
  54. package/dist/core/contentful/Contentful.d.ts +33 -0
  55. package/dist/core/contentful/Contentful.js +67 -0
  56. package/dist/core/contentful/ContentfulAsset.d.ts +23 -0
  57. package/dist/core/contentful/ContentfulAsset.js +89 -0
  58. package/dist/core/contentful/ContentfulCollection.d.ts +29 -0
  59. package/dist/core/contentful/ContentfulCollection.js +97 -0
  60. package/dist/core/contentful/ContentfulPage.d.ts +31 -0
  61. package/dist/core/contentful/ContentfulPage.js +84 -0
  62. package/dist/core/contentful/ContentfulRefs.d.ts +16 -0
  63. package/dist/core/contentful/ContentfulRefs.js +152 -0
  64. package/dist/core/contentful/index.d.ts +5 -0
  65. package/dist/core/contentful/index.js +21 -0
  66. package/dist/core/index.d.ts +3 -2
  67. package/dist/core/index.js +3 -2
  68. package/dist/core/repository/CollectionSerializer.d.ts +9 -0
  69. package/dist/core/repository/CollectionSerializer.js +41 -0
  70. package/dist/core/repository/LocalCollectionRepository.d.ts +27 -0
  71. package/dist/core/repository/LocalCollectionRepository.js +143 -0
  72. package/dist/core/repository/LocalPageRepository.d.ts +16 -0
  73. package/dist/core/repository/LocalPageRepository.js +153 -0
  74. package/dist/core/repository/PageSerializer.d.ts +3 -3
  75. package/dist/core/repository/PageSerializer.js +18 -14
  76. package/dist/core/repository/RemoteCollectionRepository.d.ts +19 -0
  77. package/dist/core/repository/RemoteCollectionRepository.js +236 -0
  78. package/dist/core/repository/RemotePageRepository.d.ts +14 -0
  79. package/dist/core/repository/RemotePageRepository.js +113 -0
  80. package/dist/core/repository/index.d.ts +4 -1
  81. package/dist/core/repository/index.js +4 -1
  82. package/dist/explore/components/Header.d.ts +26 -0
  83. package/dist/explore/components/Header.js +31 -0
  84. package/dist/explore/components/index.d.ts +1 -0
  85. package/dist/explore/components/index.js +17 -0
  86. package/dist/explore/index.d.ts +1 -0
  87. package/dist/explore/index.js +17 -0
  88. package/dist/explore/screens/Dashboard.d.ts +1 -0
  89. package/dist/explore/screens/Dashboard.js +22 -0
  90. package/dist/explore/screens/PageExplorer.d.ts +1 -0
  91. package/dist/explore/screens/PageExplorer.js +9 -0
  92. package/dist/explore/screens/SiteExplorer.d.ts +1 -0
  93. package/dist/explore/screens/SiteExplorer.js +24 -0
  94. package/dist/explore/screens/index.d.ts +3 -0
  95. package/dist/explore/screens/index.js +19 -0
  96. package/dist/page/{hooks/PageController.d.ts → controller/ContentfulPageController.d.ts} +17 -6
  97. package/dist/page/controller/ContentfulPageController.js +277 -0
  98. package/dist/page/controller/ContentfulPageControllerContainer.d.ts +5 -0
  99. package/dist/page/controller/ContentfulPageControllerContainer.js +28 -0
  100. package/dist/page/controller/index.d.ts +3 -0
  101. package/dist/page/controller/index.js +19 -0
  102. package/dist/page/controller/useContentfulPageController.d.ts +2 -0
  103. package/dist/page/controller/useContentfulPageController.js +8 -0
  104. package/dist/{core → page}/domain/Page.d.ts +71 -10
  105. package/dist/page/domain/Page.js +631 -0
  106. package/dist/page/index.d.ts +3 -0
  107. package/dist/page/index.js +3 -0
  108. package/dist/page/repository/PageRepository.d.ts +45 -0
  109. package/dist/page/repository/PageRepository.js +224 -0
  110. package/dist/page/repository/index.d.ts +1 -0
  111. package/dist/page/repository/index.js +17 -0
  112. package/dist/page/screens/PageEditor.js +29 -15
  113. package/package.json +10 -4
  114. package/dist/core/api/EditorApiClient.d.ts +0 -7
  115. package/dist/core/api/EditorApiClient.js +0 -29
  116. package/dist/core/api/EditorApiContainer.d.ts +0 -5
  117. package/dist/core/api/EditorApiContainer.js +0 -16
  118. package/dist/core/api/EditorApiContext.d.ts +0 -7
  119. package/dist/core/api/EditorApiContext.js +0 -6
  120. package/dist/core/api/index.d.ts +0 -3
  121. package/dist/core/api/useEditorApi.d.ts +0 -2
  122. package/dist/core/api/useEditorApi.js +0 -12
  123. package/dist/core/domain/Page.js +0 -180
  124. package/dist/core/repository/PageRepository.d.ts +0 -12
  125. package/dist/core/repository/PageRepository.js +0 -23
  126. package/dist/page/hooks/PageController.js +0 -107
  127. package/dist/page/hooks/index.d.ts +0 -1
  128. /package/dist/{core → page}/domain/index.d.ts +0 -0
  129. /package/dist/{core → page}/domain/index.js +0 -0
@@ -0,0 +1,631 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.Page = void 0;
15
+ const funnel_core_1 = require("@nascentdigital/funnel-core");
16
+ const components_1 = require("@nascentdigital/funnel-editor/components");
17
+ const rxjs_1 = require("rxjs");
18
+ // class
19
+ class Page {
20
+ constructor(args) {
21
+ var _a, _b, _c;
22
+ // initialize instance variables
23
+ this.id = args.id;
24
+ this.template = args.template;
25
+ this.eventBus = args.eventBus;
26
+ this.groupId = args.groupId;
27
+ this.brand = args.brand;
28
+ this.language = args.language;
29
+ this.region = args.region;
30
+ this.publishedOn = args.publishedOn;
31
+ this.createdOn = args.createdOn;
32
+ this.settings = new components_1.PageSettings(this);
33
+ this._state = args.state;
34
+ this._initialErrors = args.errors;
35
+ this._initialName = this._name = args.name;
36
+ this._updatedOn = args.updatedOn;
37
+ this._discover = args.discover;
38
+ this._content = args.content;
39
+ this._url = args.url;
40
+ this._initialSlug = this._slug = args.slug;
41
+ this._initialPublication = this._publication = args.publication;
42
+ this._assets = (_a = args.files) !== null && _a !== void 0 ? _a : [];
43
+ this._pages = (_b = args.pages) !== null && _b !== void 0 ? _b : [];
44
+ this._collections = (_c = args.collections) !== null && _c !== void 0 ? _c : [];
45
+ this._initialTags = new Set(args.tags);
46
+ this._tags = new Set(args.tags);
47
+ this.references = args.references;
48
+ this._deletedBlocks = [];
49
+ this._syncing = false;
50
+ // bind content
51
+ this._discover.forEach(item => item.bind({ parent: this, area: 'discover' }));
52
+ this._content.forEach((item) => item.bind({ parent: this, area: 'content' }));
53
+ // listen to block/field changes
54
+ this._subscription = this.eventBus.events$
55
+ .pipe((0, rxjs_1.filter)(e => (funnel_core_1.Field.Event.filter(e) && e.type === 'changed' && !e.field.sandboxed)
56
+ || (funnel_core_1.FieldList.Event.filter(e) && e.type === 'changed')
57
+ || (funnel_core_1.ObjectField.Event.filter(e) && e.type === 'changed')
58
+ || (components_1.Item.Event.filter(e) && e.type === 'changed')))
59
+ .subscribe(() => this.raiseEvent('changed'));
60
+ }
61
+ get events$() {
62
+ return this.eventBus.events$;
63
+ }
64
+ get stable$() {
65
+ return this.eventBus.events$.pipe((0, rxjs_1.map)(() => !this._syncing && !this.modified), (0, rxjs_1.distinctUntilChanged)());
66
+ }
67
+ get state() {
68
+ return this._state;
69
+ }
70
+ set state(state) {
71
+ // skip if unchanged
72
+ if (this._state === state) {
73
+ return;
74
+ }
75
+ // update state
76
+ this._state = state;
77
+ this._modifiedOn = Date.now();
78
+ // raise change
79
+ this.raiseEvent('changed');
80
+ }
81
+ get modified() {
82
+ const { _deletedBlocks, initialSlug, _slug, initialPublication, _publication, initialTags, _tags, items } = this;
83
+ return _deletedBlocks.length > 0
84
+ || initialSlug !== _slug
85
+ || initialPublication !== _publication
86
+ || initialTags.symmetricDifference(_tags).size > 0
87
+ || items.some(item => item.modified);
88
+ }
89
+ get updatedOn() {
90
+ return this._updatedOn;
91
+ }
92
+ get changes() {
93
+ return {
94
+ page: this,
95
+ items: this.items.filter(item => item instanceof components_1.Section
96
+ ? item.changes.blocks.length > 0
97
+ : item.changes.fields.length > 0)
98
+ };
99
+ }
100
+ get published() {
101
+ return this.publishedOn !== undefined;
102
+ }
103
+ get type() {
104
+ return this.template.type;
105
+ }
106
+ get syncing() {
107
+ return this._syncing;
108
+ }
109
+ set syncing(syncing) {
110
+ this._syncing = syncing;
111
+ this.raiseEvent('changed');
112
+ }
113
+ repair() {
114
+ // repair all content blocks
115
+ this.blocks.forEach(block => block.repair());
116
+ }
117
+ get url() {
118
+ return this._url;
119
+ }
120
+ get initialSlug() {
121
+ return this._initialSlug;
122
+ }
123
+ get hasSlug() {
124
+ return this.template.variant === 'dynamic';
125
+ }
126
+ set slug(slug) {
127
+ // stop static pages from setting slugs
128
+ if (!this.hasSlug) {
129
+ throw new funnel_core_1.InvalidOperationError('Cannot set slug on static page');
130
+ }
131
+ // or from being unset
132
+ else if (!slug) {
133
+ throw new funnel_core_1.ArgumentError('Slug cannot be unset');
134
+ }
135
+ // ignore if unchanged
136
+ else if (this._slug === slug) {
137
+ return;
138
+ }
139
+ // update slug
140
+ this._slug = slug;
141
+ this._modifiedOn = Date.now();
142
+ // raise change
143
+ this.raiseEvent('modified');
144
+ }
145
+ get slug() {
146
+ return this._slug;
147
+ }
148
+ get initialName() {
149
+ return this._initialName;
150
+ }
151
+ get name() {
152
+ return this._name;
153
+ }
154
+ set name(name) {
155
+ // ignore if unchanged
156
+ if (this._name === name) {
157
+ return;
158
+ }
159
+ // update name
160
+ this._name = name;
161
+ this._modifiedOn = Date.now();
162
+ // raise change
163
+ this.raiseEvent('modified');
164
+ }
165
+ get initialPublication() {
166
+ return this._initialPublication;
167
+ }
168
+ get publication() {
169
+ return this._publication;
170
+ }
171
+ set publication(publication) {
172
+ // ignore if unchanged
173
+ if (this._publication === publication) {
174
+ return;
175
+ }
176
+ // update name
177
+ this._publication = publication;
178
+ this._modifiedOn = Date.now();
179
+ // raise change
180
+ this.raiseEvent('modified');
181
+ }
182
+ get initialErrors() {
183
+ return this._initialErrors;
184
+ }
185
+ get errors() {
186
+ return {
187
+ page: this,
188
+ items: this.items.filter(item => (!item.activated && item.required)
189
+ || (item.activated && !item.valid))
190
+ };
191
+ }
192
+ get valid() {
193
+ return this.errors.items.length === 0;
194
+ }
195
+ get hasErrors() {
196
+ return this.errors.items.length > 0;
197
+ }
198
+ get asRef() {
199
+ const { id, groupId, template, brand, region, language, slug, url, name, tags, state, hasErrors, createdOn, updatedOn, publishedOn } = this;
200
+ return {
201
+ id, groupId, template,
202
+ brand, region, language, slug, url, name, tags: Array.from(tags),
203
+ state, errors: hasErrors, createdOn, updatedOn, publishedOn
204
+ };
205
+ }
206
+ get discover() {
207
+ return this._discover;
208
+ }
209
+ get seo() {
210
+ // get seo (or blow up)
211
+ const seo = this.discover.find(block => block.key === 'seo');
212
+ if (!seo) {
213
+ throw new funnel_core_1.IllegalStateError('Failed to resolve SEO block - should always exist');
214
+ }
215
+ // return seo
216
+ return seo;
217
+ }
218
+ getPreviewBlock() {
219
+ // get preview block identifier
220
+ const previewBlockIdentifier = this.template.preview;
221
+ // bail if no identifier specified
222
+ if (!previewBlockIdentifier) {
223
+ return undefined;
224
+ }
225
+ // otherwise try to get the preview block
226
+ return this.getBlock(previewBlockIdentifier);
227
+ }
228
+ get content() {
229
+ return this._content;
230
+ }
231
+ get blocks() {
232
+ return this.content
233
+ .flatMap((item) => item instanceof components_1.Section ? item.blocks : item);
234
+ }
235
+ get deleteBlocks() {
236
+ return this._deletedBlocks;
237
+ }
238
+ get firstBlock() {
239
+ // find first block
240
+ for (const item of this.content) {
241
+ // return item if it matches
242
+ if (item instanceof components_1.Block) {
243
+ return item;
244
+ }
245
+ // search deeply into sections
246
+ else {
247
+ const { blocks } = item;
248
+ if (blocks.length > 0) {
249
+ return blocks[0];
250
+ }
251
+ }
252
+ }
253
+ // or return undefined
254
+ return undefined;
255
+ }
256
+ get firstItem() {
257
+ return this.content[0];
258
+ }
259
+ get items() {
260
+ return [...this._discover, ...this._content];
261
+ }
262
+ get assets() {
263
+ return this._assets;
264
+ }
265
+ get collections() {
266
+ return this._collections;
267
+ }
268
+ get pages() {
269
+ return this._pages;
270
+ }
271
+ get initialTags() {
272
+ return this._initialTags;
273
+ }
274
+ get tagGroups() {
275
+ return this.template.tags;
276
+ }
277
+ get tags() {
278
+ return this._tags;
279
+ }
280
+ hydrateStores(references) {
281
+ this._assets.push(...references.assets);
282
+ this._pages.push(...references.pages);
283
+ this._collections.push(...references.collections);
284
+ }
285
+ getItem(identifier) {
286
+ // skip if there's no identifier
287
+ if (!identifier) {
288
+ return undefined;
289
+ }
290
+ // or return settings
291
+ else if (identifier === components_1.PageSettings.id) {
292
+ return this.settings;
293
+ }
294
+ // search content for item
295
+ for (const item of this.items) {
296
+ // return item if it matches
297
+ if (item.identifier === identifier) {
298
+ return item;
299
+ }
300
+ // search deeply into sections
301
+ if (item instanceof components_1.Section) {
302
+ for (const block of item.blocks) {
303
+ // return block if it matches
304
+ if (block.identifier === identifier) {
305
+ return block;
306
+ }
307
+ }
308
+ }
309
+ }
310
+ // or return undefined
311
+ return undefined;
312
+ }
313
+ coerceItem(identifier) {
314
+ var _a, _b;
315
+ return (_b = (_a = this.getItem(identifier)) !== null && _a !== void 0 ? _a : this.firstBlock) !== null && _b !== void 0 ? _b : this.firstItem;
316
+ }
317
+ deleteBlock(area, key) {
318
+ // get parent
319
+ let parent;
320
+ switch (area) {
321
+ case 'discover':
322
+ parent = this._discover;
323
+ break;
324
+ case 'content':
325
+ parent = this._content;
326
+ break;
327
+ }
328
+ // skip if item isn't in parent
329
+ const blockIndex = parent.findIndex(item => item.key === key);
330
+ if (!blockIndex) {
331
+ return false;
332
+ }
333
+ // remove item
334
+ const [deletedBlock] = parent.splice(blockIndex, 1);
335
+ this._modifiedOn = Date.now();
336
+ // track deletion of top-level blocks
337
+ if (deletedBlock instanceof components_1.Block) {
338
+ console.debug('Removing deleted block', deletedBlock);
339
+ this._deletedBlocks.push(deletedBlock);
340
+ }
341
+ // raise change
342
+ this.raiseEvent('modified');
343
+ // indicate success
344
+ return true;
345
+ }
346
+ getAsset(assetId) {
347
+ return this._assets.find((asset) => asset.value.id === assetId);
348
+ }
349
+ getAssetScope(range) {
350
+ switch (range) {
351
+ case 'global':
352
+ return funnel_core_1.Schema.AssetScope.global;
353
+ case 'type':
354
+ return new funnel_core_1.Schema.PageTypeAssetScope(this.type);
355
+ case 'instance':
356
+ return new funnel_core_1.Schema.PageInstanceAssetScope(this.groupId);
357
+ }
358
+ }
359
+ getSearchScope() {
360
+ return {
361
+ target: 'page',
362
+ type: this.type,
363
+ groupId: this.groupId
364
+ };
365
+ }
366
+ addAsset(asset) {
367
+ // replace asset if it exists
368
+ const { _assets } = this;
369
+ const { id } = asset.value;
370
+ const assetIndex = _assets.findIndex(asset => asset.value.id === id);
371
+ if (assetIndex >= 0) {
372
+ _assets[assetIndex] = asset;
373
+ }
374
+ // or add asset
375
+ else {
376
+ _assets.push(asset);
377
+ }
378
+ // raise event
379
+ this.raiseEvent('changed');
380
+ }
381
+ removeAsset(assetId) {
382
+ // skip if asset isn't there
383
+ const { _assets } = this;
384
+ const assetIndex = _assets.findIndex(asset => asset.value.id === assetId);
385
+ if (assetIndex < 0) {
386
+ return false;
387
+ }
388
+ // remove asset
389
+ _assets.splice(assetIndex, 1);
390
+ // raise event
391
+ this.raiseEvent('changed');
392
+ // indicate success
393
+ return true;
394
+ }
395
+ getCollection(collectionId) {
396
+ return this._collections.find(collection => collection.id === collectionId);
397
+ }
398
+ addCollection(collection) {
399
+ // replace collection if it exists
400
+ const { _collections } = this;
401
+ const collectionId = collection.id;
402
+ const collectionIndex = _collections.findIndex(collection => collection.id === collectionId);
403
+ if (collectionIndex >= 0) {
404
+ _collections[collectionIndex] = collection;
405
+ }
406
+ // or add collection
407
+ else {
408
+ _collections.push(collection);
409
+ }
410
+ // raise event
411
+ this.raiseEvent('changed');
412
+ }
413
+ removeCollection(collectionId) {
414
+ // skip if collection isn't there
415
+ const { _collections } = this;
416
+ const collectionIndex = _collections.findIndex(collection => collection.id === collectionId);
417
+ if (collectionIndex < 0) {
418
+ return false;
419
+ }
420
+ // remove collection
421
+ const [collection] = _collections.splice(collectionIndex, 1);
422
+ // raise event
423
+ this.raiseEvent('changed');
424
+ // indicate success
425
+ return true;
426
+ }
427
+ getPageRef(pageId) {
428
+ return pageId && pageId !== funnel_core_1.Schema.Page.Id.draft
429
+ ? this._pages.find((ref) => ref.id === pageId)
430
+ : undefined;
431
+ }
432
+ addPageRef(ref) {
433
+ // throw if page is a draft
434
+ if (ref.id === funnel_core_1.Schema.Page.Id.draft) {
435
+ throw new funnel_core_1.InvalidOperationError('Cannot add draft Page as reference');
436
+ }
437
+ // replace ref if it exists
438
+ const { _pages } = this;
439
+ const pageId = ref.id;
440
+ const refIndex = _pages.findIndex(ref => ref.id === pageId);
441
+ if (refIndex >= 0) {
442
+ _pages[refIndex] = ref;
443
+ }
444
+ // or add ref
445
+ else {
446
+ _pages.push(ref);
447
+ }
448
+ // raise event
449
+ this.raiseEvent('changed');
450
+ }
451
+ removePageRef(pageId) {
452
+ // skip if file isn't there
453
+ const { _pages } = this;
454
+ const refIndex = _pages.findIndex(ref => ref.id === pageId);
455
+ if (refIndex < 0) {
456
+ return false;
457
+ }
458
+ // remove file
459
+ _pages.splice(refIndex, 1);
460
+ // raise event
461
+ this.raiseEvent('changed');
462
+ // indicate success
463
+ return true;
464
+ }
465
+ addTag(tag) {
466
+ throw new Error('Method not implemented.');
467
+ }
468
+ removeTag(tag) {
469
+ throw new Error('Method not implemented.');
470
+ }
471
+ onSaveStart() {
472
+ this._savingOn = Date.now();
473
+ }
474
+ onSaveComplete(updatedOn) {
475
+ // update fundamentals
476
+ this._updatedOn = updatedOn;
477
+ this._state = 'draft';
478
+ // reset to values to match save
479
+ const { _modifiedOn, _savingOn } = this;
480
+ if (_savingOn && (!_modifiedOn || _savingOn >= _modifiedOn)) {
481
+ // sync data
482
+ this._initialErrors = !this.valid;
483
+ this._initialSlug = this._slug;
484
+ this._initialName = this._name;
485
+ this._initialTags = new Set(this._tags);
486
+ this._initialPublication = this._publication;
487
+ this._deletedBlocks = [];
488
+ }
489
+ // clear saving flag
490
+ delete this._savingOn;
491
+ }
492
+ getBlock(identifier) {
493
+ // try to find item
494
+ const item = this.getItem(identifier);
495
+ // make sure it is a block
496
+ if (item instanceof components_1.Block) {
497
+ return item;
498
+ }
499
+ // otherwise undefined
500
+ else {
501
+ return undefined;
502
+ }
503
+ }
504
+ raiseEvent(type) {
505
+ this.eventBus.publish(components_1.IPage.Event.create({ type, page: this }));
506
+ }
507
+ }
508
+ exports.Page = Page;
509
+ // extension
510
+ (function (Page) {
511
+ function fromSchemaData({ data, references, eventBus }) {
512
+ // setup
513
+ const { snapshot, discover, content, tags } = data, pageArgs = __rest(data, ["snapshot", "discover", "content", "tags"]);
514
+ const { files = {}, collections = {}, pages = {} } = references !== null && references !== void 0 ? references : {};
515
+ const { discover: discoverSnapshot = {}, content: contentSnapshot = {} } = snapshot !== null && snapshot !== void 0 ? snapshot : {};
516
+ const template = funnel_core_1.Schema.Site.getPage(data.type, data.region);
517
+ eventBus = eventBus !== null && eventBus !== void 0 ? eventBus : new funnel_core_1.EventBus();
518
+ // create page
519
+ return new Page(Object.assign(Object.assign({}, pageArgs), { eventBus,
520
+ template, tags: components_1.TagSerializer.deserializeTags({
521
+ groups: template.tags,
522
+ tagsData: tags !== null && tags !== void 0 ? tags : []
523
+ }), discover: [
524
+ components_1.PageSerializer.deserializeBlock({
525
+ schema: funnel_core_1.Schema.Seo,
526
+ eventBus,
527
+ key: 'seo',
528
+ content: discover['seo'],
529
+ snapshot: discoverSnapshot['seo']
530
+ })
531
+ ], content: Object.entries(template.content).map(([key, schema]) => components_1.PageSerializer.deserializeContent({
532
+ key,
533
+ schema: schema.unwrap(),
534
+ eventBus,
535
+ content: content[key],
536
+ snapshot: contentSnapshot[key],
537
+ })), files: Object.values(files), collections: Object.values(collections), pages: Object.values(pages) }));
538
+ }
539
+ Page.fromSchemaData = fromSchemaData;
540
+ function toUpdates(page, savables) {
541
+ var _a, _b;
542
+ // root page updates
543
+ const { id, discover, content } = page;
544
+ const rootPageUpdates = [];
545
+ // name
546
+ if (page.initialName !== page.name) {
547
+ rootPageUpdates.push({
548
+ type: 'page',
549
+ property: 'name',
550
+ value: page.name
551
+ });
552
+ }
553
+ // tags
554
+ if (page.initialTags.symmetricDifference(page.tags).size > 0) {
555
+ rootPageUpdates.push({
556
+ type: 'page',
557
+ property: 'tags',
558
+ value: Array.from(page.tags).map(tag => tag.data)
559
+ });
560
+ }
561
+ // slug + url
562
+ if (page.initialSlug !== page.slug) {
563
+ rootPageUpdates.push({
564
+ type: 'page',
565
+ property: 'slug',
566
+ value: (_a = page.slug) !== null && _a !== void 0 ? _a : null
567
+ });
568
+ rootPageUpdates.push({
569
+ type: 'page',
570
+ property: 'url',
571
+ value: page.url
572
+ });
573
+ }
574
+ // preview
575
+ const previewBlock = page.getPreviewBlock();
576
+ if (previewBlock && previewBlock.modified) {
577
+ rootPageUpdates.push({
578
+ type: 'page',
579
+ property: 'preview',
580
+ value: previewBlock.value
581
+ });
582
+ }
583
+ // errors
584
+ if (page.initialErrors !== !page.valid) {
585
+ rootPageUpdates.push({
586
+ type: 'page',
587
+ property: 'errors',
588
+ value: !page.valid
589
+ });
590
+ }
591
+ // publication
592
+ if (page.initialPublication !== page.publication) {
593
+ rootPageUpdates.push({
594
+ type: 'page',
595
+ property: 'publication',
596
+ value: (_b = page.publication) !== null && _b !== void 0 ? _b : null
597
+ });
598
+ }
599
+ // aggregate other updates
600
+ return {
601
+ id,
602
+ updatedOn: page.updatedOn,
603
+ updates: [
604
+ ...rootPageUpdates,
605
+ ...discover.reduce((updates, block) => {
606
+ // try to update block
607
+ components_1.SerializePageUpdate.serializeBlockUpdate(updates, block, 'discover', savables);
608
+ // keep reducing
609
+ return updates;
610
+ }, []),
611
+ ...content.reduce((updates, item) => {
612
+ // handle block
613
+ if (item instanceof components_1.Block) {
614
+ components_1.SerializePageUpdate.serializeBlockUpdate(updates, item, 'content', savables);
615
+ }
616
+ // or section
617
+ else {
618
+ components_1.SerializePageUpdate.serializeSectionUpdate(updates, item, 'content', savables);
619
+ }
620
+ // keep reducing
621
+ return updates;
622
+ }, []),
623
+ ...page.deleteBlocks.map(block => ({
624
+ type: 'block.delete',
625
+ path: [block.area, block.key]
626
+ }))
627
+ ]
628
+ };
629
+ }
630
+ Page.toUpdates = toUpdates;
631
+ })(Page || (exports.Page = Page = {}));
@@ -1 +1,4 @@
1
+ export * from './domain';
2
+ export * from './repository';
1
3
  export * from './screens';
4
+ export * from './controller';
@@ -14,4 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./domain"), exports);
18
+ __exportStar(require("./repository"), exports);
17
19
  __exportStar(require("./screens"), exports);
20
+ __exportStar(require("./controller"), exports);
@@ -0,0 +1,45 @@
1
+ import { EditorAppSDK, EntrySys } from '@contentful/app-sdk';
2
+ import { ContentfulContentClient } from '@nascentdigital/funnel-cms/contentful';
3
+ import { Schema } from '@nascentdigital/funnel-core';
4
+ import { IPage, IPageRepository, PageSummary } from '@nascentdigital/funnel-editor/components';
5
+ import { Page } from '../domain';
6
+ export declare class PageRepository implements IPageRepository {
7
+ readonly sdk: EditorAppSDK;
8
+ readonly contentfulClient: ContentfulContentClient;
9
+ constructor(args: PageRepository.ConstructorArgs);
10
+ search(args: IPageRepository.Search.Args): Promise<IPageRepository.Search.Result>;
11
+ getOverview({ region }: IPageRepository.GetOverview.Args): Promise<IPageRepository.GetOverview.Result>;
12
+ create(args: IPageRepository.Create.Args): Promise<IPageRepository.Create.Result>;
13
+ createLanguage(args: IPageRepository.CreateLang.Args): Promise<IPageRepository.CreateLang.Result>;
14
+ load(sys?: EntrySys): Promise<PageRepository.Load.Result>;
15
+ save(page: Page): Promise<Page>;
16
+ sync({ page, sys }: PageRepository.Sync.Args): Promise<PageRepository.Sync.Result>;
17
+ unpublish(page: IPage): Promise<void>;
18
+ }
19
+ export declare namespace PageRepository {
20
+ type ConstructorArgs = {
21
+ sdk: EditorAppSDK;
22
+ contentfulClient: ContentfulContentClient;
23
+ };
24
+ namespace Load {
25
+ type Args = {
26
+ pageId?: Schema.Page.Id;
27
+ };
28
+ type Result = {
29
+ pageSummary: PageSummary;
30
+ page: Page;
31
+ sys: EntrySys;
32
+ };
33
+ }
34
+ namespace Sync {
35
+ type Args = {
36
+ page: Page;
37
+ sys: EntrySys;
38
+ };
39
+ type Result = {
40
+ pageSummary?: PageSummary;
41
+ page: Page;
42
+ sys: EntrySys;
43
+ };
44
+ }
45
+ }