@designcrowd/library.brand-page 6.0.19 → 6.0.20
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-DCwwdYPj.js → CreatedOnBrandCrowd-de-de-C52IyXZu.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-DTmZeDQ1.js → CreatedOnBrandCrowd-en-us-DhTy_dEV.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-Dbrz6TXv.js → CreatedOnBrandCrowd-es-es-BJelIAQ4.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-DLQhgn8T.js → CreatedOnBrandCrowd-fr-ca-DwJohy0T.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-DLQhgn8T.js → CreatedOnBrandCrowd-fr-fr-DwJohy0T.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-yAzzD2ik.js → CreatedOnBrandCrowd-pt-br-CMzKbxdG.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-yAzzD2ik.js → CreatedOnBrandCrowd-pt-pt-CMzKbxdG.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-CNmNNE5o.js → CreatedOnDcom-de-de-DAy1GHrw.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-BUmLFlS_.js → CreatedOnDcom-en-us-CgBDAkJN.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-DfygM_0q.js → CreatedOnDcom-es-es-Ds9d5rem.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-DIEft8xE.js → CreatedOnDcom-fr-ca-CZL0BQ-u.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-Cn3jWG2n.js → CreatedOnDcom-fr-fr-BVYh5Wvo.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-DXhgGwEh.js → CreatedOnDcom-pt-br-1hsWNXfq.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-BvE9ckw1.js → CreatedOnDcom-pt-pt-DvM0N-3M.js} +1 -1
- package/lib/src/brand-page/components/contact-form/ContactForm.mixin.js +2 -5
- 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 +100 -21
- 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 +138 -143
- package/lib/src/{lib-Bm-fYap1.js → lib-CK2FPBv5.js} +55098 -55367
- 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 -8
- package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +2 -2
- 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/utils/minify-brand-page-metadata.js +1 -4
- package/package.json +1 -1
- package/src/brand-page/components/contact-form/ContactForm.mixin.ts +2 -5
- 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 +107 -23
- 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 -14
- 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/utils/minify-brand-page-metadata.ts +1 -4
- package/lib/src/brand-page/utils/migration/migration-19.d.ts +0 -2
- package/lib/src/brand-page/utils/migration/migration-19.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-19.test.ts +0 -72
- package/src/brand-page/utils/migration/migration-19.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-features.test.ts +0 -330
- 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
|
@@ -5,7 +5,7 @@ import brandPageClient from '../../clients/brand-page.client';
|
|
|
5
5
|
import { isEmail } from '../../../utils/validator.util';
|
|
6
6
|
import { ALIGN_CARD_CENTER, ALIGN_CARD_CENTER_IMAGE, ALIGN_CENTERED, ALIGN_LEFT_FULL_IMAGE, ALIGN_RIGHT_FULL_IMAGE, DISPLAY_STYLE_COLLAPSED, RECAPTCHA_ACTION_CONTACT_FORM, TEXT_ONLY, } from '../../constants';
|
|
7
7
|
import { getRenderText, contentPaddingStyle as toContentPaddingStyle, mutedTextForBackground, backgroundColorFromStyle, } from '@brand-page/utils';
|
|
8
|
-
import { hasRTEContent
|
|
8
|
+
import { hasRTEContent } from '@brand-page-maker/utils';
|
|
9
9
|
import { useReCaptcha } from '../../composables/recaptcha.composable';
|
|
10
10
|
export default defineComponent({
|
|
11
11
|
props: {
|
|
@@ -113,10 +113,7 @@ export default defineComponent({
|
|
|
113
113
|
isEmail(this.viewModel.responseEmail));
|
|
114
114
|
},
|
|
115
115
|
title() {
|
|
116
|
-
|
|
117
|
-
// throw — read the visible text via getPlainTextFromRTE to decide
|
|
118
|
-
// whether to fall back to the default.
|
|
119
|
-
return getPlainTextFromRTE(this.viewModel.title)
|
|
116
|
+
return this.viewModel.title && this.viewModel.title.trim() !== ''
|
|
120
117
|
? this.viewModel.title
|
|
121
118
|
: 'Contact Us';
|
|
122
119
|
},
|
|
@@ -7,14 +7,6 @@ import { TextStyles } from './styles.model';
|
|
|
7
7
|
import { LogoStyles } from './logo.model';
|
|
8
8
|
import type { LogoImageModel, LogoTemplateImageModel } from './logo.model';
|
|
9
9
|
import type { BrandPagePaymentConfig } from './payment.model';
|
|
10
|
-
import type { JSONContent } from '@tiptap/vue-3';
|
|
11
|
-
/**
|
|
12
|
-
* BP-5787 — a rich-text field is either a legacy inline-HTML string or a
|
|
13
|
-
* Tiptap JSON document. Typing RTE content fields as RichTextValue (instead of
|
|
14
|
-
* `string`) forces every consumer to handle both forms — surfacing at compile
|
|
15
|
-
* time any code that assumes a plain string (e.g. `.replace`, `.length`).
|
|
16
|
-
*/
|
|
17
|
-
export type RichTextValue = string | JSONContent;
|
|
18
10
|
export * from './brand-page-context.model';
|
|
19
11
|
export * from './payment.model';
|
|
20
12
|
export * from './content.model';
|
|
@@ -156,7 +148,7 @@ export interface TextContent extends Content {
|
|
|
156
148
|
/**
|
|
157
149
|
* For BrandPage/BrandContact only
|
|
158
150
|
*/
|
|
159
|
-
text:
|
|
151
|
+
text: string;
|
|
160
152
|
/**
|
|
161
153
|
* For BrandSite
|
|
162
154
|
*/
|
|
@@ -179,9 +171,9 @@ export interface TextContent extends Content {
|
|
|
179
171
|
}
|
|
180
172
|
export interface ProfileContent extends Content {
|
|
181
173
|
avatarImageUrl: string;
|
|
182
|
-
name:
|
|
183
|
-
title:
|
|
184
|
-
description:
|
|
174
|
+
name: string;
|
|
175
|
+
title: string;
|
|
176
|
+
description: string;
|
|
185
177
|
backgroundColor: BrandPageCssStyle;
|
|
186
178
|
colorReplacements: ColorReplacement[];
|
|
187
179
|
mediaType?: string;
|
|
@@ -199,7 +191,7 @@ export interface MapContent extends Content {
|
|
|
199
191
|
}
|
|
200
192
|
export interface MailingListContent extends Content {
|
|
201
193
|
acceptedFields?: 'emailOnly' | 'nameAndEmail';
|
|
202
|
-
title:
|
|
194
|
+
title: string;
|
|
203
195
|
buttonText: string;
|
|
204
196
|
titleStyle: TextStyleDeclaration;
|
|
205
197
|
buttonTextStyle: TextStyleDeclaration;
|
|
@@ -250,10 +242,10 @@ export interface FormField {
|
|
|
250
242
|
export interface ContactFormContent extends Content {
|
|
251
243
|
type: 'contact-form';
|
|
252
244
|
displayStyle: string;
|
|
253
|
-
title:
|
|
254
|
-
description:
|
|
245
|
+
title: string;
|
|
246
|
+
description: string;
|
|
255
247
|
buttonText: string;
|
|
256
|
-
successMessage:
|
|
248
|
+
successMessage: string;
|
|
257
249
|
fields: FormField[];
|
|
258
250
|
responseEmail: string;
|
|
259
251
|
imageUrl?: string;
|
|
@@ -272,8 +264,8 @@ export interface ContactFormContent extends Content {
|
|
|
272
264
|
export interface BannerSectionContent extends Content {
|
|
273
265
|
type: 'banner-section';
|
|
274
266
|
imageUrl: string;
|
|
275
|
-
title:
|
|
276
|
-
description:
|
|
267
|
+
title: string;
|
|
268
|
+
description: string;
|
|
277
269
|
buttonText: string | false;
|
|
278
270
|
url: string;
|
|
279
271
|
email?: string;
|
|
@@ -300,8 +292,8 @@ export declare const MEDIA_TYPES: {
|
|
|
300
292
|
};
|
|
301
293
|
export type MediaType = keyof typeof MEDIA_TYPES;
|
|
302
294
|
export interface TextMediaItem extends ImageItem {
|
|
303
|
-
title:
|
|
304
|
-
paragraph:
|
|
295
|
+
title: string;
|
|
296
|
+
paragraph: string;
|
|
305
297
|
itemsId: number;
|
|
306
298
|
buttonText?: string | false;
|
|
307
299
|
buttonPageId?: string;
|
|
@@ -320,8 +312,8 @@ export interface TextShapeItem extends TextMediaItem {
|
|
|
320
312
|
export interface ShapeItem extends ImageItem {
|
|
321
313
|
colorReplacements: ColorReplacement[];
|
|
322
314
|
mediaType: MediaType;
|
|
323
|
-
title?:
|
|
324
|
-
paragraph?:
|
|
315
|
+
title?: string;
|
|
316
|
+
paragraph?: string;
|
|
325
317
|
titleOverride?: string;
|
|
326
318
|
paragraphOverride?: string;
|
|
327
319
|
}
|
|
@@ -329,9 +321,9 @@ export interface TestimonialItems {
|
|
|
329
321
|
/** Stable per-item identifier. See ImageItem.id. */
|
|
330
322
|
id: string;
|
|
331
323
|
imageUrl: string;
|
|
332
|
-
name:
|
|
333
|
-
position:
|
|
334
|
-
testimonials:
|
|
324
|
+
name: string;
|
|
325
|
+
position: string;
|
|
326
|
+
testimonials: string;
|
|
335
327
|
colorReplacements: ColorReplacement[];
|
|
336
328
|
mediaType: string;
|
|
337
329
|
size?: string;
|
|
@@ -344,7 +336,7 @@ export interface TestimonialItems {
|
|
|
344
336
|
export interface TextItem {
|
|
345
337
|
/** Stable per-item identifier. See ImageItem.id. */
|
|
346
338
|
id: string;
|
|
347
|
-
text:
|
|
339
|
+
text: string;
|
|
348
340
|
textStyle: TextStyleDeclaration;
|
|
349
341
|
textOverride?: string;
|
|
350
342
|
}
|
|
@@ -361,8 +353,8 @@ export interface ImagesSectionContent extends Content, MediaSection {
|
|
|
361
353
|
enablePopup: boolean;
|
|
362
354
|
}
|
|
363
355
|
export interface MediaSection extends Content {
|
|
364
|
-
title:
|
|
365
|
-
description:
|
|
356
|
+
title: string;
|
|
357
|
+
description: string;
|
|
366
358
|
displayStyle: ImagesSectionContentDisplayStyle;
|
|
367
359
|
items: TextShapeItem[] | TextMediaItem[];
|
|
368
360
|
titleStyle: TextStyleDeclaration;
|
|
@@ -379,7 +371,7 @@ export interface ColorReplacement {
|
|
|
379
371
|
}
|
|
380
372
|
export interface TestimonialSectionContent extends Content {
|
|
381
373
|
type: 'testimonial-section';
|
|
382
|
-
title:
|
|
374
|
+
title: string;
|
|
383
375
|
displayStyle: string;
|
|
384
376
|
items: TestimonialItems[];
|
|
385
377
|
titleStyle: TextStyleDeclaration;
|
|
@@ -393,8 +385,8 @@ export interface TestimonialSectionContent extends Content {
|
|
|
393
385
|
export interface AboutSectionContent extends Content {
|
|
394
386
|
type: 'about-section';
|
|
395
387
|
imageUrl: string;
|
|
396
|
-
title:
|
|
397
|
-
paragraph:
|
|
388
|
+
title: string;
|
|
389
|
+
paragraph: string;
|
|
398
390
|
displayStyle: string;
|
|
399
391
|
titleStyle: TextStyleDeclaration;
|
|
400
392
|
paragraphStyle: TextStyleDeclaration;
|
|
@@ -418,7 +410,7 @@ export declare const SOCIAL_LINKS_ICON_DISPLAY_STYLES: {
|
|
|
418
410
|
export type SocialLinksIconDisplayStyle = keyof typeof SOCIAL_LINKS_ICON_DISPLAY_STYLES;
|
|
419
411
|
export interface SocialLinksContent extends Content {
|
|
420
412
|
type: 'social-links';
|
|
421
|
-
title:
|
|
413
|
+
title: string;
|
|
422
414
|
links: LinksItem[];
|
|
423
415
|
iconDisplayStyle: SocialLinksIconDisplayStyle;
|
|
424
416
|
iconFillStyles: BrandPageCssStyle;
|
|
@@ -441,8 +433,8 @@ export interface DividerSectionContent extends Content {
|
|
|
441
433
|
}
|
|
442
434
|
export interface BookingSectionContent extends Content {
|
|
443
435
|
type: 'booking-section';
|
|
444
|
-
title:
|
|
445
|
-
description:
|
|
436
|
+
title: string;
|
|
437
|
+
description: string;
|
|
446
438
|
buttonText: string;
|
|
447
439
|
url: string;
|
|
448
440
|
email?: string;
|
|
@@ -21,7 +21,6 @@ import { migration15 } from './migration/migration-15';
|
|
|
21
21
|
import { migration16 } from './migration/migration-16';
|
|
22
22
|
import { migration17 } from './migration/migration-17';
|
|
23
23
|
import { migration18 } from './migration/migration-18';
|
|
24
|
-
import { migration19 } from './migration/migration-19';
|
|
25
24
|
const MIGRATION_TABLE = [
|
|
26
25
|
{
|
|
27
26
|
version: 1,
|
|
@@ -139,16 +138,6 @@ const MIGRATION_TABLE = [
|
|
|
139
138
|
migrateFn: migration18,
|
|
140
139
|
description: 'BP-5603: backfill stable item ids on all nested items (gallery/section/testimonial/text items, section + footer social links) — the item id is now non-nullable',
|
|
141
140
|
},
|
|
142
|
-
{
|
|
143
|
-
version: 19,
|
|
144
|
-
migrateFn: migration19,
|
|
145
|
-
// runAlways: normalise RTE to JSON on every load. Idempotent (only HTML
|
|
146
|
-
// strings are converted; JSON is skipped), so it also catches content the
|
|
147
|
-
// AI section builders still emit as HTML — converting it on the next read
|
|
148
|
-
// without a new migration or changes to those builders.
|
|
149
|
-
runAlways: true,
|
|
150
|
-
description: '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)',
|
|
151
|
-
},
|
|
152
141
|
];
|
|
153
142
|
export const GetLatestModelVersion = () => Math.max(...MIGRATION_TABLE.map((x) => x.version));
|
|
154
143
|
export const migrateBrandPageModel = async (brandPageModel, options) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const getRenderText: (text: string) => string;
|
|
2
|
-
export declare const escapeContentText: (text:
|
|
2
|
+
export declare const escapeContentText: (text: string | undefined) => string | undefined;
|
|
3
3
|
export declare const decodeHtmlEntities: (text: string) => string;
|
|
4
4
|
export declare const unescapeContentText: (text: string) => string;
|
|
5
5
|
export declare const encodeContentText: (text: string | undefined) => string | undefined;
|
|
@@ -1,43 +1,11 @@
|
|
|
1
1
|
import { ESCAPED_NEWLINE_CHARACTER } from '../../constants/ui';
|
|
2
|
-
/**
|
|
3
|
-
* BP-5787 — a Tiptap JSON document is an object with `type: 'doc'`.
|
|
4
|
-
* Inlined here (rather than importing from brand-page-maker) to avoid a
|
|
5
|
-
* circular import: rich-text-editor.util imports getRenderText from this file.
|
|
6
|
-
*/
|
|
7
|
-
const isTiptapDoc = (value) => typeof value === 'object' &&
|
|
8
|
-
value !== null &&
|
|
9
|
-
value.type === 'doc';
|
|
10
|
-
const jsonDocPlainText = (doc) => {
|
|
11
|
-
const parts = [];
|
|
12
|
-
const walk = (node) => {
|
|
13
|
-
if (typeof node?.text === 'string')
|
|
14
|
-
parts.push(node.text);
|
|
15
|
-
node?.content?.forEach(walk);
|
|
16
|
-
};
|
|
17
|
-
walk(doc);
|
|
18
|
-
return parts.join(' ').replace(/\s+/g, ' ').trim();
|
|
19
|
-
};
|
|
20
2
|
export const getRenderText = (text) => {
|
|
21
|
-
// BP-5787: RTE fields may now be Tiptap JSON objects. Non-strings pass
|
|
22
|
-
// through untouched so the renderer (TextWrapper) handles them via its
|
|
23
|
-
// JSON-aware path, instead of throwing on `.replace`.
|
|
24
|
-
if (typeof text !== 'string') {
|
|
25
|
-
return text;
|
|
26
|
-
}
|
|
27
3
|
return text.replace(new RegExp(`(${ESCAPED_NEWLINE_CHARACTER}|\\n)`, 'g'), '<br/>');
|
|
28
4
|
};
|
|
29
|
-
// Accepts a legacy inline-HTML string or a Tiptap JSON document (BP-5787):
|
|
30
|
-
// for JSON it returns the concatenated visible text; for HTML it strips tags.
|
|
31
5
|
export const escapeContentText = (text) => {
|
|
32
6
|
if (!text) {
|
|
33
7
|
return text;
|
|
34
8
|
}
|
|
35
|
-
if (isTiptapDoc(text)) {
|
|
36
|
-
return jsonDocPlainText(text);
|
|
37
|
-
}
|
|
38
|
-
if (typeof text !== 'string') {
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
9
|
return text
|
|
42
10
|
.replace(/(<([^>]+)>)/gi, '')
|
|
43
11
|
.replace(/(\r\n|\r|\n)/g, ESCAPED_NEWLINE_CHARACTER);
|
|
@@ -150,9 +150,9 @@ const processSocialLinks = (socialLinksContent, vcardLines, addedEntries) => {
|
|
|
150
150
|
});
|
|
151
151
|
};
|
|
152
152
|
const addProfileInfo = (profile, vcardLines) => {
|
|
153
|
-
const name = sanitizeForVCard(
|
|
154
|
-
const title = sanitizeForVCard(
|
|
155
|
-
const description = sanitizeForVCard(
|
|
153
|
+
const name = sanitizeForVCard(profile.name || '');
|
|
154
|
+
const title = sanitizeForVCard(profile.title || '');
|
|
155
|
+
const description = sanitizeForVCard(profile.description || '');
|
|
156
156
|
if (name) {
|
|
157
157
|
const nameParts = name.trim().split(/\s+/);
|
|
158
158
|
const lastName = nameParts.length > 1 ? nameParts.pop() || '' : '';
|
|
@@ -205,6 +205,6 @@ const downloadVCard = (vcard, filename) => {
|
|
|
205
205
|
export const saveContact = (brandPageData) => {
|
|
206
206
|
const vcard = generateVCard(brandPageData);
|
|
207
207
|
const profile = findProfileContent(brandPageData);
|
|
208
|
-
const filename = generateVCardFilename(
|
|
208
|
+
const filename = generateVCardFilename(profile?.name);
|
|
209
209
|
downloadVCard(vcard, filename);
|
|
210
210
|
};
|
|
@@ -28,7 +28,6 @@ interface ViewModelMappingOptions {
|
|
|
28
28
|
setVideoUrlsWithToken?: (token: string, videoUrl: string, previewImageUrl: string, assetId: string) => void;
|
|
29
29
|
}
|
|
30
30
|
export declare const getBrandPageViewModelFromBrandPageModel: (model: BrandPageModel, brandPageToken: string | undefined, showBrandCrowdLogo: boolean | undefined, options: ViewModelMappingOptions) => BrandPageViewModel;
|
|
31
|
-
export declare const resolvePageIdsInRteJson: (doc: unknown, nav: NavViewModel, options: ViewModelMappingOptions) => unknown;
|
|
32
31
|
export declare const isLogoViewModel: (viewModel: ContentViewModel) => viewModel is LogoViewModel;
|
|
33
32
|
/** for service.brand-page website preview by logo draft token */
|
|
34
33
|
export declare const applyLogoImageToBrandPageViewModel: (viewModel: BrandPageViewModel, logoImage: LogoImageModel) => BrandPageViewModel;
|
|
@@ -10,7 +10,7 @@ import { isValidSvgUrl } from './image.util';
|
|
|
10
10
|
import { isLogoContent } from './model.util';
|
|
11
11
|
import { getBoxShadowValue } from './button.util';
|
|
12
12
|
import { findNavItemByPageId, getRouteNameByPageIndex, getRouteParamsByPage, } from './route.util';
|
|
13
|
-
import { hasRTEContent
|
|
13
|
+
import { hasRTEContent } from '../../brand-page-maker/utils';
|
|
14
14
|
import { getPageIdFromHref, isHrefPageId, } from '../../brand-page-maker/composables/rich-text-editor/hyperlink';
|
|
15
15
|
const BUTTON_BORDER_RADIUS = '9999px';
|
|
16
16
|
const CONTENT_BORDER_RADIUS = '48px';
|
|
@@ -863,75 +863,13 @@ const mapPageIdReferencesToRelativePaths = (pages, nav, options) => {
|
|
|
863
863
|
});
|
|
864
864
|
});
|
|
865
865
|
};
|
|
866
|
-
// Resolve a `pageid:<id>` internal-link href to the published relative path.
|
|
867
|
-
// Returns the resolved href, or null when `href` is not an internal pageid link
|
|
868
|
-
// (external/absolute links are left untouched). Falls back to the site root when
|
|
869
|
-
// the pageid can't be matched to a nav route.
|
|
870
|
-
const resolvePageIdHref = (href, nav, options) => {
|
|
871
|
-
// Only process internal links (no protocol, doesn't start with /)
|
|
872
|
-
if (!href || href.match(/^(https?:\/\/|\/)/) || !isHrefPageId(href)) {
|
|
873
|
-
return null;
|
|
874
|
-
}
|
|
875
|
-
const pageId = getPageIdFromHref(href);
|
|
876
|
-
const route = findNavItemByPageId(nav.navItems, pageId);
|
|
877
|
-
const brandPageSlugRoute = options.brandPageSlug
|
|
878
|
-
? `/${options.brandPageSlug}`
|
|
879
|
-
: '/';
|
|
880
|
-
if (route) {
|
|
881
|
-
if (route.isRoot) {
|
|
882
|
-
return brandPageSlugRoute;
|
|
883
|
-
}
|
|
884
|
-
return `${brandPageSlugRoute}${brandPageSlugRoute === '/' ? '' : '/'}${route.relativePath}`;
|
|
885
|
-
}
|
|
886
|
-
// fallback to root if pageid cannot be resolved.
|
|
887
|
-
return brandPageSlugRoute;
|
|
888
|
-
};
|
|
889
|
-
// BP-5847: walk a Tiptap JSON doc and rewrite every link mark whose href is a
|
|
890
|
-
// `pageid:` reference into its published relative path. Returns a NEW doc when
|
|
891
|
-
// something changed (so the shared model doc is never mutated), else the same
|
|
892
|
-
// reference.
|
|
893
|
-
export const resolvePageIdsInRteJson = (doc, nav, options) => {
|
|
894
|
-
let changed = false;
|
|
895
|
-
const walk = (node) => {
|
|
896
|
-
if (!node || typeof node !== 'object') {
|
|
897
|
-
return node;
|
|
898
|
-
}
|
|
899
|
-
let next = node;
|
|
900
|
-
if (Array.isArray(node.marks)) {
|
|
901
|
-
const marks = node.marks.map((mark) => {
|
|
902
|
-
if (mark?.type === 'link' && typeof mark.attrs?.href === 'string') {
|
|
903
|
-
const resolved = resolvePageIdHref(mark.attrs.href, nav, options);
|
|
904
|
-
if (resolved !== null) {
|
|
905
|
-
changed = true;
|
|
906
|
-
return { ...mark, attrs: { ...mark.attrs, href: resolved } };
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
return mark;
|
|
910
|
-
});
|
|
911
|
-
next = { ...next, marks };
|
|
912
|
-
}
|
|
913
|
-
if (Array.isArray(node.content)) {
|
|
914
|
-
next = { ...next, content: node.content.map(walk) };
|
|
915
|
-
}
|
|
916
|
-
return next;
|
|
917
|
-
};
|
|
918
|
-
const result = walk(doc);
|
|
919
|
-
return changed ? result : doc;
|
|
920
|
-
};
|
|
921
866
|
const dynamicallyMapPageIdInHyperlinksToRelativePaths = (content, nav, options) => {
|
|
922
867
|
Object.keys(content).forEach((key) => {
|
|
923
868
|
const value = content[key];
|
|
924
869
|
if (value === undefined || value === null) {
|
|
925
870
|
return;
|
|
926
871
|
}
|
|
927
|
-
if (
|
|
928
|
-
// BP-5847: RTE fields may now be Tiptap JSON. Resolve pageid link marks
|
|
929
|
-
// here too, or internal links render as raw `pageid:` and don't navigate.
|
|
930
|
-
content[key] =
|
|
931
|
-
resolvePageIdsInRteJson(value, nav, options);
|
|
932
|
-
}
|
|
933
|
-
else if (typeof value === 'object' &&
|
|
934
|
-
(key === 'items' || key === 'textItems')) {
|
|
872
|
+
if (typeof value === 'object' && (key === 'items' || key === 'textItems')) {
|
|
935
873
|
if (Array.isArray(value)) {
|
|
936
874
|
value.forEach((item) => {
|
|
937
875
|
dynamicallyMapPageIdInHyperlinksToRelativePaths(item, nav, options);
|
|
@@ -943,10 +881,24 @@ const dynamicallyMapPageIdInHyperlinksToRelativePaths = (content, nav, options)
|
|
|
943
881
|
}
|
|
944
882
|
else if (typeof value === 'string' && hasRTEContent(value)) {
|
|
945
883
|
content[key] = value.replace(/<a\s+([^>]*?)href="([^"]*?)"([^>]*?)>/gi, (match, existingAttrsStart, href, existingAttrsEnd) => {
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
884
|
+
// Only process internal links (no protocol, doesn't start with /)
|
|
885
|
+
if (href && !href.match(/^(https?:\/\/|\/)/) && isHrefPageId(href)) {
|
|
886
|
+
const pageId = getPageIdFromHref(href);
|
|
887
|
+
const route = findNavItemByPageId(nav.navItems, pageId);
|
|
888
|
+
const brandPageSlugRoute = options.brandPageSlug
|
|
889
|
+
? `/${options.brandPageSlug}`
|
|
890
|
+
: '/';
|
|
891
|
+
if (route) {
|
|
892
|
+
let href = `${brandPageSlugRoute}`;
|
|
893
|
+
if (!route.isRoot) {
|
|
894
|
+
href = `${brandPageSlugRoute}${brandPageSlugRoute === '/' ? '' : '/'}${route.relativePath}`;
|
|
895
|
+
}
|
|
896
|
+
return `<a ${existingAttrsStart}href="${href}"${existingAttrsEnd}>`;
|
|
897
|
+
}
|
|
898
|
+
// fallback to root if pageid cannot be resolved.
|
|
899
|
+
return `<a ${existingAttrsStart}href="${brandPageSlugRoute}"${existingAttrsEnd}>`;
|
|
900
|
+
}
|
|
901
|
+
return match;
|
|
950
902
|
});
|
|
951
903
|
}
|
|
952
904
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ButtonWithModalContent, ProfileContent, TextContent, VideoContent, ImageContent, ContentType, ButtonStyles, LogoStyles, MapContent, ImageGalleryContent, GalleryStyles, MailingListContent, RequestPaymentContent, ShopContent, SupportMeContent, ContactFormContent, BannerSectionContent, BrandPageType, SocialLinksContent, TestimonialSectionContent, AboutSectionContent, DividerSectionContent, ShapesSectionContent, ButtonLinkType, PageHeaderMobile, PageHeaderDesktop, PageFooterMobile, PageFooterDesktop, TextMediaItem, TextShapeItem, TextStyleDeclaration, AspectRatio, LogoImageModel, LogoTemplateImageModel, CookieOptions, BookingSectionContent, MediaTypes, TextStyles, BackgroundStyle, BackgroundShape, PersonalisationRole, SaveContactOptions
|
|
1
|
+
import type { ButtonWithModalContent, ProfileContent, TextContent, VideoContent, ImageContent, ContentType, ButtonStyles, LogoStyles, MapContent, ImageGalleryContent, GalleryStyles, MailingListContent, RequestPaymentContent, ShopContent, SupportMeContent, ContactFormContent, BannerSectionContent, BrandPageType, SocialLinksContent, TestimonialSectionContent, AboutSectionContent, DividerSectionContent, ShapesSectionContent, ButtonLinkType, PageHeaderMobile, PageHeaderDesktop, PageFooterMobile, PageFooterDesktop, TextMediaItem, TextShapeItem, TextStyleDeclaration, AspectRatio, LogoImageModel, LogoTemplateImageModel, CookieOptions, BookingSectionContent, MediaTypes, TextStyles, BackgroundStyle, BackgroundShape, PersonalisationRole, SaveContactOptions } from './models';
|
|
2
2
|
import type { ImagesSectionContentDisplayStyle } from './constants';
|
|
3
3
|
export type ViewModelType = 'button' | 'image' | 'image-gallery' | 'logo' | 'map' | 'mailing-list' | 'profile' | 'support-me' | 'request-payment' | 'text' | 'video' | 'contact-form' | 'banner-section' | 'images-section' | 'about-section' | 'divider-section' | 'testimonial-section' | 'social-links' | 'shapes-section' | 'shop-section' | 'booking-section';
|
|
4
4
|
export interface ContentViewModel {
|
|
@@ -94,8 +94,8 @@ export interface TextImageSectionViewModel {
|
|
|
94
94
|
id: string;
|
|
95
95
|
type: 'images-section';
|
|
96
96
|
role: ContentType;
|
|
97
|
-
title:
|
|
98
|
-
description:
|
|
97
|
+
title: string;
|
|
98
|
+
description: string;
|
|
99
99
|
displayStyle: ImagesSectionContentDisplayStyle;
|
|
100
100
|
aspectRatio: AspectRatio;
|
|
101
101
|
areImagesFullWidth: boolean;
|