@designcrowd/library.brand-page 6.0.6-json-prereq-7 → 6.0.6-tracker-1
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/lib/src/{CreatedOnBrandCrowd-de-de-SPVLPi8n.js → CreatedOnBrandCrowd-de-de-DD0OBnij.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-CvtrCPHd.js → CreatedOnBrandCrowd-en-us-DysrpsmM.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-BSsac7jB.js → CreatedOnBrandCrowd-es-es-B6twGr9h.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-BauENV2a.js → CreatedOnBrandCrowd-fr-ca-yxl0ih_4.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-BauENV2a.js → CreatedOnBrandCrowd-fr-fr-yxl0ih_4.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-Be0hawmr.js → CreatedOnBrandCrowd-pt-br-BtXDrIcx.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-Be0hawmr.js → CreatedOnBrandCrowd-pt-pt-BtXDrIcx.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-CTjE2Tmn.js → CreatedOnDcom-de-de-ho_ROy1L.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-DnZRp5Pg.js → CreatedOnDcom-en-us-C91p9kls.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-J-9qvjy8.js → CreatedOnDcom-es-es-B3FYmObE.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-BDNHqm4G.js → CreatedOnDcom-fr-ca-D40m7fPx.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-B_2-ceuO.js → CreatedOnDcom-fr-fr-Cd57oYyc.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-76lJVrAY.js → CreatedOnDcom-pt-br-Du57mWxG.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-TQp3CNcu.js → CreatedOnDcom-pt-pt-fYoPZWwr.js} +1 -1
- package/lib/src/brand-page/models/index.d.ts +26 -34
- package/lib/src/brand-page/utils/migration.util.js +0 -11
- package/lib/src/brand-page/utils/text.util.d.ts +1 -1
- package/lib/src/brand-page/utils/text.util.js +0 -32
- package/lib/src/brand-page/utils/vcard.util.js +4 -4
- package/lib/src/brand-page/utils/view-model.util.d.ts +0 -1
- package/lib/src/brand-page/utils/view-model.util.js +20 -68
- package/lib/src/brand-page/view-models.d.ts +3 -3
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +99 -20
- package/lib/src/brand-page-maker/utils/index.d.ts +0 -2
- package/lib/src/brand-page-maker/utils/index.js +0 -2
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +5 -19
- package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +5 -35
- package/lib/src/brand-page-maker/validators/field.validator.js +2 -10
- package/lib/src/css/library.brand-page-brandCrowd.min.css +1 -1
- package/lib/src/css/library.brand-page-brandPage.min.css +1 -1
- package/lib/src/css/library.brand-page-designCom.min.css +1 -1
- package/lib/src/css/library.brand-page-preview.min.css +1 -1
- package/lib/src/index.d.ts +0 -1
- package/lib/src/index.mjs +137 -141
- package/lib/src/{lib-Bh9Y5_-x.js → lib-lMNy66QO.js} +43580 -44184
- package/lib/src/lib.js +0 -2
- package/lib/src/metadata-builder/builders/update-content-text-builder.js +15 -20
- package/lib/src/metadata-builder/builders/update-content-text-style-builder.js +3 -5
- package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +1 -1
- package/lib/src/metadata-builder/helpers/rte.helpers.js +3 -6
- package/lib/src/shared/content-settings/components/GenericTextInput.mixin.js +1 -14
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +3 -12
- package/lib/src/tracker.d.ts +2 -0
- package/lib/src/tracker.js +12 -0
- package/lib/src/tracker.mjs +12 -0
- package/lib/src/useEventTracker-DmQ6AkNn.js +356 -0
- package/lib/src/utils/minify-brand-page-metadata.js +1 -4
- package/package.json +16 -1
- package/src/brand-page/components/text-wrapper/TextWrapper.vue +6 -17
- package/src/brand-page/models/index.ts +26 -35
- package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -3
- package/src/brand-page/utils/migration.util.ts +0 -12
- package/src/brand-page/utils/style.util.test.ts +0 -51
- package/src/brand-page/utils/text.util.ts +4 -43
- package/src/brand-page/utils/vcard.util.ts +4 -6
- package/src/brand-page/utils/view-model.util.ts +26 -94
- package/src/brand-page/view-models.ts +2 -3
- package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +106 -22
- package/src/brand-page-maker/utils/index.ts +0 -2
- package/src/brand-page-maker/utils/rich-text-editor.util.test.ts +3 -4
- package/src/brand-page-maker/utils/rich-text-editor.util.ts +11 -50
- package/src/brand-page-maker/validators/field.validator.ts +2 -10
- package/src/lib.ts +0 -9
- package/src/metadata-builder/builders/update-content-text-builder.ts +18 -32
- package/src/metadata-builder/builders/update-content-text-style-builder.ts +4 -6
- package/src/metadata-builder/helpers/rte.helpers.ts +7 -11
- package/src/shared/content-settings/components/GenericTextInput.mixin.ts +1 -17
- package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +3 -16
- package/src/tracker.ts +28 -0
- package/src/utils/minify-brand-page-metadata.ts +1 -4
- package/lib/src/brand-page/utils/migration/migration-18.d.ts +0 -2
- package/lib/src/brand-page/utils/migration/migration-18.js +0 -71
- package/lib/src/brand-page-maker/__fixtures__/complex-rte.fixture.d.ts +0 -22
- package/lib/src/brand-page-maker/__fixtures__/complex-rte.fixture.js +0 -22
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.d.ts +0 -14
- package/lib/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.js +0 -39
- package/lib/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.d.ts +0 -28
- package/lib/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.js +0 -66
- package/lib/src/brand-page-maker/utils/rte-render.util.d.ts +0 -33
- package/lib/src/brand-page-maker/utils/rte-render.util.js +0 -50
- package/lib/src/brand-page-maker/utils/rte-sanitize.util.d.ts +0 -6
- package/lib/src/brand-page-maker/utils/rte-sanitize.util.js +0 -158
- package/lib/src/brand-page-maker/utils/rte-serializer.d.ts +0 -5
- package/lib/src/brand-page-maker/utils/rte-serializer.js +0 -112
- package/src/brand-page/utils/migration/migration-18.test.ts +0 -72
- package/src/brand-page/utils/migration/migration-18.ts +0 -83
- package/src/brand-page/utils/text.util.test.ts +0 -47
- package/src/brand-page/utils/view-model.pageid-rte.test.ts +0 -104
- package/src/brand-page-maker/__fixtures__/complex-rte.fixture.ts +0 -23
- package/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.test.ts +0 -52
- package/src/brand-page-maker/composables/rich-text-editor/extensions/FontFamily.ts +0 -42
- package/src/brand-page-maker/composables/rich-text-editor/getRteExtensions.ts +0 -113
- package/src/brand-page-maker/utils/__snapshots__/rte-render-parity.test.ts.snap +0 -200
- package/src/brand-page-maker/utils/rte-render-parity.test.ts +0 -156
- package/src/brand-page-maker/utils/rte-render.util.ts +0 -77
- package/src/brand-page-maker/utils/rte-sanitize-json.test.ts +0 -158
- package/src/brand-page-maker/utils/rte-sanitize.util.ts +0 -195
- package/src/brand-page-maker/utils/rte-serializer.ts +0 -172
- package/src/brand-page-maker/validators/field.validator.test.ts +0 -55
|
@@ -29,15 +29,6 @@ import { EMPTY_LOGO_IMAGE_MODEL, LogoStyles } from './logo.model';
|
|
|
29
29
|
import type { LogoImageModel, LogoTemplateImageModel } from './logo.model';
|
|
30
30
|
import cloneDeep from 'lodash.clonedeep';
|
|
31
31
|
import type { BrandPagePaymentConfig } from './payment.model';
|
|
32
|
-
import type { JSONContent } from '@tiptap/vue-3';
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* BP-5787 — a rich-text field is either a legacy inline-HTML string or a
|
|
36
|
-
* Tiptap JSON document. Typing RTE content fields as RichTextValue (instead of
|
|
37
|
-
* `string`) forces every consumer to handle both forms — surfacing at compile
|
|
38
|
-
* time any code that assumes a plain string (e.g. `.replace`, `.length`).
|
|
39
|
-
*/
|
|
40
|
-
export type RichTextValue = string | JSONContent;
|
|
41
32
|
|
|
42
33
|
export * from './brand-page-context.model';
|
|
43
34
|
export * from './payment.model';
|
|
@@ -281,7 +272,7 @@ export interface TextContent extends Content {
|
|
|
281
272
|
/**
|
|
282
273
|
* For BrandPage/BrandContact only
|
|
283
274
|
*/
|
|
284
|
-
text:
|
|
275
|
+
text: string;
|
|
285
276
|
/**
|
|
286
277
|
* For BrandSite
|
|
287
278
|
*/
|
|
@@ -305,9 +296,9 @@ export interface TextContent extends Content {
|
|
|
305
296
|
|
|
306
297
|
export interface ProfileContent extends Content {
|
|
307
298
|
avatarImageUrl: string;
|
|
308
|
-
name:
|
|
309
|
-
title:
|
|
310
|
-
description:
|
|
299
|
+
name: string;
|
|
300
|
+
title: string;
|
|
301
|
+
description: string;
|
|
311
302
|
backgroundColor: BrandPageCssStyle;
|
|
312
303
|
colorReplacements: ColorReplacement[];
|
|
313
304
|
mediaType?: string;
|
|
@@ -328,7 +319,7 @@ export interface MapContent extends Content {
|
|
|
328
319
|
|
|
329
320
|
export interface MailingListContent extends Content {
|
|
330
321
|
acceptedFields?: 'emailOnly' | 'nameAndEmail';
|
|
331
|
-
title:
|
|
322
|
+
title: string;
|
|
332
323
|
buttonText: string;
|
|
333
324
|
titleStyle: TextStyleDeclaration;
|
|
334
325
|
buttonTextStyle: TextStyleDeclaration;
|
|
@@ -387,10 +378,10 @@ export interface FormField {
|
|
|
387
378
|
export interface ContactFormContent extends Content {
|
|
388
379
|
type: 'contact-form';
|
|
389
380
|
displayStyle: string;
|
|
390
|
-
title:
|
|
391
|
-
description:
|
|
381
|
+
title: string;
|
|
382
|
+
description: string;
|
|
392
383
|
buttonText: string;
|
|
393
|
-
successMessage:
|
|
384
|
+
successMessage: string;
|
|
394
385
|
fields: FormField[];
|
|
395
386
|
responseEmail: string;
|
|
396
387
|
imageUrl?: string;
|
|
@@ -410,8 +401,8 @@ export interface ContactFormContent extends Content {
|
|
|
410
401
|
export interface BannerSectionContent extends Content {
|
|
411
402
|
type: 'banner-section';
|
|
412
403
|
imageUrl: string;
|
|
413
|
-
title:
|
|
414
|
-
description:
|
|
404
|
+
title: string;
|
|
405
|
+
description: string;
|
|
415
406
|
buttonText: string | false;
|
|
416
407
|
url: string;
|
|
417
408
|
email?: string;
|
|
@@ -441,8 +432,8 @@ export const MEDIA_TYPES = {
|
|
|
441
432
|
export type MediaType = keyof typeof MEDIA_TYPES;
|
|
442
433
|
|
|
443
434
|
export interface TextMediaItem extends ImageItem {
|
|
444
|
-
title:
|
|
445
|
-
paragraph:
|
|
435
|
+
title: string;
|
|
436
|
+
paragraph: string;
|
|
446
437
|
itemsId: number;
|
|
447
438
|
|
|
448
439
|
buttonText?: string | false;
|
|
@@ -466,8 +457,8 @@ export interface TextShapeItem extends TextMediaItem {
|
|
|
466
457
|
export interface ShapeItem extends ImageItem {
|
|
467
458
|
colorReplacements: ColorReplacement[];
|
|
468
459
|
mediaType: MediaType;
|
|
469
|
-
title?:
|
|
470
|
-
paragraph?:
|
|
460
|
+
title?: string;
|
|
461
|
+
paragraph?: string;
|
|
471
462
|
|
|
472
463
|
// overrides for personalisation
|
|
473
464
|
titleOverride?: string;
|
|
@@ -476,9 +467,9 @@ export interface ShapeItem extends ImageItem {
|
|
|
476
467
|
|
|
477
468
|
export interface TestimonialItems {
|
|
478
469
|
imageUrl: string;
|
|
479
|
-
name:
|
|
480
|
-
position:
|
|
481
|
-
testimonials:
|
|
470
|
+
name: string;
|
|
471
|
+
position: string;
|
|
472
|
+
testimonials: string;
|
|
482
473
|
colorReplacements: ColorReplacement[];
|
|
483
474
|
mediaType: string;
|
|
484
475
|
size?: string;
|
|
@@ -492,7 +483,7 @@ export interface TestimonialItems {
|
|
|
492
483
|
}
|
|
493
484
|
|
|
494
485
|
export interface TextItem {
|
|
495
|
-
text:
|
|
486
|
+
text: string;
|
|
496
487
|
textStyle: TextStyleDeclaration;
|
|
497
488
|
|
|
498
489
|
// overrides for personalisation
|
|
@@ -514,8 +505,8 @@ export interface ImagesSectionContent extends Content, MediaSection {
|
|
|
514
505
|
}
|
|
515
506
|
|
|
516
507
|
export interface MediaSection extends Content {
|
|
517
|
-
title:
|
|
518
|
-
description:
|
|
508
|
+
title: string;
|
|
509
|
+
description: string;
|
|
519
510
|
displayStyle: ImagesSectionContentDisplayStyle;
|
|
520
511
|
items: TextShapeItem[] | TextMediaItem[];
|
|
521
512
|
titleStyle: TextStyleDeclaration;
|
|
@@ -534,7 +525,7 @@ export interface ColorReplacement {
|
|
|
534
525
|
|
|
535
526
|
export interface TestimonialSectionContent extends Content {
|
|
536
527
|
type: 'testimonial-section';
|
|
537
|
-
title:
|
|
528
|
+
title: string;
|
|
538
529
|
displayStyle: string;
|
|
539
530
|
items: TestimonialItems[];
|
|
540
531
|
titleStyle: TextStyleDeclaration;
|
|
@@ -549,8 +540,8 @@ export interface TestimonialSectionContent extends Content {
|
|
|
549
540
|
export interface AboutSectionContent extends Content {
|
|
550
541
|
type: 'about-section';
|
|
551
542
|
imageUrl: string;
|
|
552
|
-
title:
|
|
553
|
-
paragraph:
|
|
543
|
+
title: string;
|
|
544
|
+
paragraph: string;
|
|
554
545
|
displayStyle: string;
|
|
555
546
|
titleStyle: TextStyleDeclaration;
|
|
556
547
|
paragraphStyle: TextStyleDeclaration;
|
|
@@ -577,7 +568,7 @@ export type SocialLinksIconDisplayStyle =
|
|
|
577
568
|
|
|
578
569
|
export interface SocialLinksContent extends Content {
|
|
579
570
|
type: 'social-links';
|
|
580
|
-
title:
|
|
571
|
+
title: string;
|
|
581
572
|
links: LinksItem[];
|
|
582
573
|
iconDisplayStyle: SocialLinksIconDisplayStyle;
|
|
583
574
|
iconFillStyles: BrandPageCssStyle;
|
|
@@ -604,8 +595,8 @@ export interface DividerSectionContent extends Content {
|
|
|
604
595
|
|
|
605
596
|
export interface BookingSectionContent extends Content {
|
|
606
597
|
type: 'booking-section';
|
|
607
|
-
title:
|
|
608
|
-
description:
|
|
598
|
+
title: string;
|
|
599
|
+
description: string;
|
|
609
600
|
buttonText: string;
|
|
610
601
|
url: string;
|
|
611
602
|
email?: string;
|
|
@@ -457,7 +457,7 @@ exports[`migration.util > Banner Contents - text Align and Font Family should no
|
|
|
457
457
|
},
|
|
458
458
|
},
|
|
459
459
|
"userPromptContentKey": undefined,
|
|
460
|
-
"v":
|
|
460
|
+
"v": 17,
|
|
461
461
|
},
|
|
462
462
|
"useOldLogoRenderSize": true,
|
|
463
463
|
}
|
|
@@ -903,7 +903,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
|
|
|
903
903
|
},
|
|
904
904
|
},
|
|
905
905
|
"userPromptContentKey": undefined,
|
|
906
|
-
"v":
|
|
906
|
+
"v": 17,
|
|
907
907
|
},
|
|
908
908
|
"useOldLogoRenderSize": true,
|
|
909
909
|
}
|
|
@@ -1356,7 +1356,7 @@ exports[`migration.util > migrateBrandPageModel should return brand page model w
|
|
|
1356
1356
|
},
|
|
1357
1357
|
},
|
|
1358
1358
|
"userPromptContentKey": undefined,
|
|
1359
|
-
"v":
|
|
1359
|
+
"v": 17,
|
|
1360
1360
|
},
|
|
1361
1361
|
"useOldLogoRenderSize": true,
|
|
1362
1362
|
}
|
|
@@ -20,7 +20,6 @@ import { migration14 } from './migration/migration-14';
|
|
|
20
20
|
import { migration15 } from './migration/migration-15';
|
|
21
21
|
import { migration16 } from './migration/migration-16';
|
|
22
22
|
import { migration17 } from './migration/migration-17';
|
|
23
|
-
import { migration18 } from './migration/migration-18';
|
|
24
23
|
|
|
25
24
|
export interface MigrationData {
|
|
26
25
|
brandPageModel: BrandPageModel;
|
|
@@ -161,17 +160,6 @@ const MIGRATION_TABLE = [
|
|
|
161
160
|
description:
|
|
162
161
|
'Padding Control backfill (BP-5699 Tier 2 + BP-5700 Store): backfill existing top/bottom spacing as explicit padding for text (12px), images/social links/shapes/booking (32px), store (16px), contact form (per layout), banner and about (per display style)',
|
|
163
162
|
},
|
|
164
|
-
{
|
|
165
|
-
version: 18,
|
|
166
|
-
migrateFn: migration18,
|
|
167
|
-
// runAlways: normalise RTE to JSON on every load. Idempotent (only HTML
|
|
168
|
-
// strings are converted; JSON is skipped), so it also catches content the
|
|
169
|
-
// AI section builders still emit as HTML — converting it on the next read
|
|
170
|
-
// without a new migration or changes to those builders.
|
|
171
|
-
runAlways: true,
|
|
172
|
-
description:
|
|
173
|
-
'BP-5787: convert inline-HTML RTE content to Tiptap JSON on load (lazy migrate-on-read for web-renderer; persisted on next maker save; also normalises AI-built HTML)',
|
|
174
|
-
},
|
|
175
163
|
] as MigrationTableItem[];
|
|
176
164
|
|
|
177
165
|
export const GetLatestModelVersion = () =>
|
|
@@ -87,57 +87,6 @@ describe('style.util', () => {
|
|
|
87
87
|
);
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
-
test('applyLogoThemeToBrandPageModel preserves var() token refs in JSON RTE content (BP-5787)', () => {
|
|
91
|
-
// Arrange — title stored as Tiptap JSON with a theme-token colour mark.
|
|
92
|
-
const logoTheme = logoWithFlatColorsTheme;
|
|
93
|
-
const titleDoc = {
|
|
94
|
-
type: 'doc',
|
|
95
|
-
content: [
|
|
96
|
-
{
|
|
97
|
-
type: 'heading',
|
|
98
|
-
attrs: { level: 2, textAlign: 'center' },
|
|
99
|
-
content: [
|
|
100
|
-
{
|
|
101
|
-
type: 'text',
|
|
102
|
-
marks: [
|
|
103
|
-
{
|
|
104
|
-
type: 'textStyle',
|
|
105
|
-
attrs: { color: `var(--${STYLE_THEME_KEYS.LogoTextColor})` },
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
text: 'Themed',
|
|
109
|
-
},
|
|
110
|
-
],
|
|
111
|
-
},
|
|
112
|
-
],
|
|
113
|
-
};
|
|
114
|
-
const brandPageModel = new BrandPageModel({
|
|
115
|
-
...BRAND_SITE,
|
|
116
|
-
pages: [
|
|
117
|
-
{
|
|
118
|
-
title: '1',
|
|
119
|
-
slug: '1',
|
|
120
|
-
contents: [
|
|
121
|
-
{
|
|
122
|
-
...createInitialBannerSectionContent(),
|
|
123
|
-
title: titleDoc,
|
|
124
|
-
} as any,
|
|
125
|
-
],
|
|
126
|
-
},
|
|
127
|
-
],
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// Act
|
|
131
|
-
const { model } = applyLogoThemeToBrandPageModel(logoTheme, brandPageModel);
|
|
132
|
-
|
|
133
|
-
// Assert — JSON RTE content is an object, so the var() token is NOT
|
|
134
|
-
// flattened to rgb(); it survives so a new theme can still propagate.
|
|
135
|
-
const title = JSON.stringify((model.pages[0].contents[0] as any).title);
|
|
136
|
-
|
|
137
|
-
expect(title).toContain(`var(--${STYLE_THEME_KEYS.LogoTextColor})`);
|
|
138
|
-
expect(title).not.toContain(logoTheme.logoTextColor.rgb);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
90
|
test('applyLogoThemeToBrandPageModel should apply logo theme color to content color when content color has a color matched theme key', () => {
|
|
142
91
|
// Arrange
|
|
143
92
|
const logoTheme = logoWithFlatColorsTheme;
|
|
@@ -1,56 +1,17 @@
|
|
|
1
1
|
import { ESCAPED_NEWLINE_CHARACTER } from '../../constants/ui';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* BP-5787 — a Tiptap JSON document is an object with `type: 'doc'`.
|
|
5
|
-
* Inlined here (rather than importing from brand-page-maker) to avoid a
|
|
6
|
-
* circular import: rich-text-editor.util imports getRenderText from this file.
|
|
7
|
-
*/
|
|
8
|
-
const isTiptapDoc = (value: unknown): value is { type: 'doc' } =>
|
|
9
|
-
typeof value === 'object' &&
|
|
10
|
-
value !== null &&
|
|
11
|
-
(value as { type?: string }).type === 'doc';
|
|
12
|
-
|
|
13
|
-
const jsonDocPlainText = (doc: unknown): string => {
|
|
14
|
-
const parts: string[] = [];
|
|
15
|
-
|
|
16
|
-
const walk = (node: any): void => {
|
|
17
|
-
if (typeof node?.text === 'string') parts.push(node.text);
|
|
18
|
-
|
|
19
|
-
node?.content?.forEach(walk);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
walk(doc);
|
|
23
|
-
|
|
24
|
-
return parts.join(' ').replace(/\s+/g, ' ').trim();
|
|
25
|
-
};
|
|
26
|
-
|
|
27
3
|
export const getRenderText = (text: string): string => {
|
|
28
|
-
// BP-5787: RTE fields may now be Tiptap JSON objects. Non-strings pass
|
|
29
|
-
// through untouched so the renderer (TextWrapper) handles them via its
|
|
30
|
-
// JSON-aware path, instead of throwing on `.replace`.
|
|
31
|
-
if (typeof text !== 'string') {
|
|
32
|
-
return text as unknown as string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
4
|
return text.replace(
|
|
36
5
|
new RegExp(`(${ESCAPED_NEWLINE_CHARACTER}|\\n)`, 'g'),
|
|
37
6
|
'<br/>',
|
|
38
7
|
);
|
|
39
8
|
};
|
|
40
9
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
10
|
+
export const escapeContentText = (
|
|
11
|
+
text: string | undefined,
|
|
12
|
+
): string | undefined => {
|
|
44
13
|
if (!text) {
|
|
45
|
-
return text
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (isTiptapDoc(text)) {
|
|
49
|
-
return jsonDocPlainText(text);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (typeof text !== 'string') {
|
|
53
|
-
return undefined;
|
|
14
|
+
return text;
|
|
54
15
|
}
|
|
55
16
|
|
|
56
17
|
return text
|
|
@@ -235,11 +235,9 @@ const addProfileInfo = (
|
|
|
235
235
|
profile: ProfileViewModel,
|
|
236
236
|
vcardLines: string[],
|
|
237
237
|
): void => {
|
|
238
|
-
const name = sanitizeForVCard(
|
|
239
|
-
const title = sanitizeForVCard(
|
|
240
|
-
const description = sanitizeForVCard(
|
|
241
|
-
getPlainTextFromRTE(profile.description) || '',
|
|
242
|
-
);
|
|
238
|
+
const name = sanitizeForVCard(profile.name || '');
|
|
239
|
+
const title = sanitizeForVCard(profile.title || '');
|
|
240
|
+
const description = sanitizeForVCard(profile.description || '');
|
|
243
241
|
|
|
244
242
|
if (name) {
|
|
245
243
|
const nameParts = name.trim().split(/\s+/);
|
|
@@ -318,7 +316,7 @@ export const saveContact = (brandPageData: {
|
|
|
318
316
|
}): void => {
|
|
319
317
|
const vcard = generateVCard(brandPageData);
|
|
320
318
|
const profile = findProfileContent(brandPageData);
|
|
321
|
-
const filename = generateVCardFilename(
|
|
319
|
+
const filename = generateVCardFilename(profile?.name);
|
|
322
320
|
|
|
323
321
|
downloadVCard(vcard, filename);
|
|
324
322
|
};
|
|
@@ -119,7 +119,7 @@ import {
|
|
|
119
119
|
getRouteNameByPageIndex,
|
|
120
120
|
getRouteParamsByPage,
|
|
121
121
|
} from './route.util';
|
|
122
|
-
import { hasRTEContent
|
|
122
|
+
import { hasRTEContent } from '../../brand-page-maker/utils';
|
|
123
123
|
import {
|
|
124
124
|
getPageIdFromHref,
|
|
125
125
|
isHrefPageId,
|
|
@@ -1518,86 +1518,6 @@ const mapPageIdReferencesToRelativePaths = (
|
|
|
1518
1518
|
});
|
|
1519
1519
|
};
|
|
1520
1520
|
|
|
1521
|
-
// Resolve a `pageid:<id>` internal-link href to the published relative path.
|
|
1522
|
-
// Returns the resolved href, or null when `href` is not an internal pageid link
|
|
1523
|
-
// (external/absolute links are left untouched). Falls back to the site root when
|
|
1524
|
-
// the pageid can't be matched to a nav route.
|
|
1525
|
-
const resolvePageIdHref = (
|
|
1526
|
-
href: string,
|
|
1527
|
-
nav: NavViewModel,
|
|
1528
|
-
options: ViewModelMappingOptions,
|
|
1529
|
-
): string | null => {
|
|
1530
|
-
// Only process internal links (no protocol, doesn't start with /)
|
|
1531
|
-
if (!href || href.match(/^(https?:\/\/|\/)/) || !isHrefPageId(href)) {
|
|
1532
|
-
return null;
|
|
1533
|
-
}
|
|
1534
|
-
|
|
1535
|
-
const pageId = getPageIdFromHref(href);
|
|
1536
|
-
const route = findNavItemByPageId(nav.navItems, pageId);
|
|
1537
|
-
const brandPageSlugRoute = options.brandPageSlug
|
|
1538
|
-
? `/${options.brandPageSlug}`
|
|
1539
|
-
: '/';
|
|
1540
|
-
|
|
1541
|
-
if (route) {
|
|
1542
|
-
if (route.isRoot) {
|
|
1543
|
-
return brandPageSlugRoute;
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
return `${brandPageSlugRoute}${brandPageSlugRoute === '/' ? '' : '/'}${route.relativePath}`;
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
// fallback to root if pageid cannot be resolved.
|
|
1550
|
-
return brandPageSlugRoute;
|
|
1551
|
-
};
|
|
1552
|
-
|
|
1553
|
-
// BP-5847: walk a Tiptap JSON doc and rewrite every link mark whose href is a
|
|
1554
|
-
// `pageid:` reference into its published relative path. Returns a NEW doc when
|
|
1555
|
-
// something changed (so the shared model doc is never mutated), else the same
|
|
1556
|
-
// reference.
|
|
1557
|
-
export const resolvePageIdsInRteJson = (
|
|
1558
|
-
doc: unknown,
|
|
1559
|
-
nav: NavViewModel,
|
|
1560
|
-
options: ViewModelMappingOptions,
|
|
1561
|
-
): unknown => {
|
|
1562
|
-
let changed = false;
|
|
1563
|
-
|
|
1564
|
-
const walk = (node: any): any => {
|
|
1565
|
-
if (!node || typeof node !== 'object') {
|
|
1566
|
-
return node;
|
|
1567
|
-
}
|
|
1568
|
-
|
|
1569
|
-
let next = node;
|
|
1570
|
-
|
|
1571
|
-
if (Array.isArray(node.marks)) {
|
|
1572
|
-
const marks = node.marks.map((mark: any) => {
|
|
1573
|
-
if (mark?.type === 'link' && typeof mark.attrs?.href === 'string') {
|
|
1574
|
-
const resolved = resolvePageIdHref(mark.attrs.href, nav, options);
|
|
1575
|
-
|
|
1576
|
-
if (resolved !== null) {
|
|
1577
|
-
changed = true;
|
|
1578
|
-
|
|
1579
|
-
return { ...mark, attrs: { ...mark.attrs, href: resolved } };
|
|
1580
|
-
}
|
|
1581
|
-
}
|
|
1582
|
-
|
|
1583
|
-
return mark;
|
|
1584
|
-
});
|
|
1585
|
-
|
|
1586
|
-
next = { ...next, marks };
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
if (Array.isArray(node.content)) {
|
|
1590
|
-
next = { ...next, content: node.content.map(walk) };
|
|
1591
|
-
}
|
|
1592
|
-
|
|
1593
|
-
return next;
|
|
1594
|
-
};
|
|
1595
|
-
|
|
1596
|
-
const result = walk(doc);
|
|
1597
|
-
|
|
1598
|
-
return changed ? result : doc;
|
|
1599
|
-
};
|
|
1600
|
-
|
|
1601
1521
|
const dynamicallyMapPageIdInHyperlinksToRelativePaths = (
|
|
1602
1522
|
content: any,
|
|
1603
1523
|
nav: NavViewModel,
|
|
@@ -1610,15 +1530,7 @@ const dynamicallyMapPageIdInHyperlinksToRelativePaths = (
|
|
|
1610
1530
|
return;
|
|
1611
1531
|
}
|
|
1612
1532
|
|
|
1613
|
-
if (
|
|
1614
|
-
// BP-5847: RTE fields may now be Tiptap JSON. Resolve pageid link marks
|
|
1615
|
-
// here too, or internal links render as raw `pageid:` and don't navigate.
|
|
1616
|
-
(content as unknown as Record<string, unknown>)[key] =
|
|
1617
|
-
resolvePageIdsInRteJson(value, nav, options);
|
|
1618
|
-
} else if (
|
|
1619
|
-
typeof value === 'object' &&
|
|
1620
|
-
(key === 'items' || key === 'textItems')
|
|
1621
|
-
) {
|
|
1533
|
+
if (typeof value === 'object' && (key === 'items' || key === 'textItems')) {
|
|
1622
1534
|
if (Array.isArray(value)) {
|
|
1623
1535
|
value.forEach((item) => {
|
|
1624
1536
|
dynamicallyMapPageIdInHyperlinksToRelativePaths(item, nav, options);
|
|
@@ -1630,11 +1542,31 @@ const dynamicallyMapPageIdInHyperlinksToRelativePaths = (
|
|
|
1630
1542
|
(content as unknown as Record<string, unknown>)[key] = value.replace(
|
|
1631
1543
|
/<a\s+([^>]*?)href="([^"]*?)"([^>]*?)>/gi,
|
|
1632
1544
|
(match, existingAttrsStart, href, existingAttrsEnd) => {
|
|
1633
|
-
|
|
1545
|
+
// Only process internal links (no protocol, doesn't start with /)
|
|
1546
|
+
if (href && !href.match(/^(https?:\/\/|\/)/) && isHrefPageId(href)) {
|
|
1547
|
+
const pageId = getPageIdFromHref(href);
|
|
1548
|
+
|
|
1549
|
+
const route = findNavItemByPageId(nav.navItems, pageId);
|
|
1550
|
+
|
|
1551
|
+
const brandPageSlugRoute = options.brandPageSlug
|
|
1552
|
+
? `/${options.brandPageSlug}`
|
|
1553
|
+
: '/';
|
|
1554
|
+
|
|
1555
|
+
if (route) {
|
|
1556
|
+
let href = `${brandPageSlugRoute}`;
|
|
1557
|
+
|
|
1558
|
+
if (!route.isRoot) {
|
|
1559
|
+
href = `${brandPageSlugRoute}${brandPageSlugRoute === '/' ? '' : '/'}${route.relativePath}`;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
return `<a ${existingAttrsStart}href="${href}"${existingAttrsEnd}>`;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
// fallback to root if pageid cannot be resolved.
|
|
1566
|
+
return `<a ${existingAttrsStart}href="${brandPageSlugRoute}"${existingAttrsEnd}>`;
|
|
1567
|
+
}
|
|
1634
1568
|
|
|
1635
|
-
return
|
|
1636
|
-
? match
|
|
1637
|
-
: `<a ${existingAttrsStart}href="${resolved}"${existingAttrsEnd}>`;
|
|
1569
|
+
return match;
|
|
1638
1570
|
},
|
|
1639
1571
|
);
|
|
1640
1572
|
}
|
|
@@ -41,7 +41,6 @@ import type {
|
|
|
41
41
|
BackgroundShape,
|
|
42
42
|
PersonalisationRole,
|
|
43
43
|
SaveContactOptions,
|
|
44
|
-
RichTextValue,
|
|
45
44
|
} from './models';
|
|
46
45
|
import type { ImagesSectionContentDisplayStyle } from './constants';
|
|
47
46
|
|
|
@@ -197,8 +196,8 @@ export interface TextImageSectionViewModel {
|
|
|
197
196
|
id: string;
|
|
198
197
|
type: 'images-section';
|
|
199
198
|
role: ContentType;
|
|
200
|
-
title:
|
|
201
|
-
description:
|
|
199
|
+
title: string;
|
|
200
|
+
description: string;
|
|
202
201
|
displayStyle: ImagesSectionContentDisplayStyle;
|
|
203
202
|
aspectRatio: AspectRatio;
|
|
204
203
|
areImagesFullWidth: boolean;
|