@ethlete/contentful 4.0.0-next.12 → 4.0.0-next.13
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/CHANGELOG.md +23 -0
- package/fesm2022/ethlete-contentful.mjs +224 -107
- package/fesm2022/ethlete-contentful.mjs.map +1 -1
- package/generators/generators.json +6 -1
- package/generators/migrate-contentful-asset-classes/migration.js +163 -0
- package/generators/migrate-contentful-asset-classes/schema.json +26 -0
- package/generators/migrate-contentful-default-components/contentful-default-components.js +15 -1
- package/generators/migrate-contentful-default-components/migration.js +22 -5
- package/generators/migrate-contentful-default-components/schema.json +1 -1
- package/generators/migrate-to-contentful-v5/migration.js +3 -3
- package/migrations.json +12 -1
- package/package.json +6 -6
- package/types/ethlete-contentful.d.ts +68 -22
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { NgClass, DOCUMENT } from '@angular/common';
|
|
2
1
|
import * as i0 from '@angular/core';
|
|
3
2
|
import { input, computed, ViewEncapsulation, Component, InjectionToken, inject, numberAttribute, booleanAttribute, isDevMode, ViewContainerRef, ElementRef, effect, untracked, signal, reflectComponentType, inputBinding } from '@angular/core';
|
|
4
3
|
import { formatFileSize, normalizePictureSizes, PictureComponent } from '@ethlete/components';
|
|
5
|
-
import { defineLabels, toProvideFn, toInjectFn, toToken, injectUrl, RuntimeError, isObject,
|
|
4
|
+
import { defineLabels, toProvideFn, toInjectFn, toToken, injectUrl, RuntimeError, isObject, getObjectProperty, injectRenderer } from '@ethlete/core';
|
|
5
|
+
import { DOCUMENT, Location } from '@angular/common';
|
|
6
6
|
import { Router, RouterLink } from '@angular/router';
|
|
7
7
|
|
|
8
8
|
const GQL_FRAGMENT_CONTENTFUL_ASSET = `
|
|
@@ -29,12 +29,6 @@ class ContentfulAudioComponent {
|
|
|
29
29
|
constructor() {
|
|
30
30
|
this.asset = input.required(/* @ts-ignore */
|
|
31
31
|
...(ngDevMode ? [{ debugName: "asset" }] : /* istanbul ignore next */ []));
|
|
32
|
-
this.audioClass = input(null, /* @ts-ignore */
|
|
33
|
-
...(ngDevMode ? [{ debugName: "audioClass" }] : /* istanbul ignore next */ []));
|
|
34
|
-
this.figureClass = input(null, /* @ts-ignore */
|
|
35
|
-
...(ngDevMode ? [{ debugName: "figureClass" }] : /* istanbul ignore next */ []));
|
|
36
|
-
this.figcaptionClass = input(null, /* @ts-ignore */
|
|
37
|
-
...(ngDevMode ? [{ debugName: "figcaptionClass" }] : /* istanbul ignore next */ []));
|
|
38
32
|
this.data = computed(() => {
|
|
39
33
|
const asset = this.asset();
|
|
40
34
|
if (!asset) {
|
|
@@ -57,14 +51,16 @@ class ContentfulAudioComponent {
|
|
|
57
51
|
...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
58
52
|
}
|
|
59
53
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ContentfulAudioComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
60
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ContentfulAudioComponent, isStandalone: true, selector: "et-contentful-audio", inputs: { asset: { classPropertyName: "asset", publicName: "asset", isSignal: true, isRequired: true, transformFunction: null }
|
|
54
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ContentfulAudioComponent, isStandalone: true, selector: "et-contentful-audio", inputs: { asset: { classPropertyName: "asset", publicName: "asset", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "et-contentful-audio" }, ngImport: i0, template: `
|
|
61
55
|
@if (data(); as data) {
|
|
62
|
-
<figure
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
<figure class="et-contentful-audio-figure">
|
|
57
|
+
@if (data.title) {
|
|
58
|
+
<figcaption class="et-contentful-audio-figcaption">{{ data.title }}</figcaption>
|
|
59
|
+
}
|
|
60
|
+
<audio [src]="data.url" class="et-contentful-audio-audio" controls></audio>
|
|
65
61
|
</figure>
|
|
66
62
|
}
|
|
67
|
-
`, isInline: true,
|
|
63
|
+
`, isInline: true, encapsulation: i0.ViewEncapsulation.None }); }
|
|
68
64
|
}
|
|
69
65
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ContentfulAudioComponent, decorators: [{
|
|
70
66
|
type: Component,
|
|
@@ -72,19 +68,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
72
68
|
selector: 'et-contentful-audio',
|
|
73
69
|
template: `
|
|
74
70
|
@if (data(); as data) {
|
|
75
|
-
<figure
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
<figure class="et-contentful-audio-figure">
|
|
72
|
+
@if (data.title) {
|
|
73
|
+
<figcaption class="et-contentful-audio-figcaption">{{ data.title }}</figcaption>
|
|
74
|
+
}
|
|
75
|
+
<audio [src]="data.url" class="et-contentful-audio-audio" controls></audio>
|
|
78
76
|
</figure>
|
|
79
77
|
}
|
|
80
78
|
`,
|
|
81
79
|
encapsulation: ViewEncapsulation.None,
|
|
82
|
-
imports: [NgClass],
|
|
83
80
|
host: {
|
|
84
81
|
class: 'et-contentful-audio',
|
|
85
82
|
},
|
|
86
83
|
}]
|
|
87
|
-
}], propDecorators: { asset: [{ type: i0.Input, args: [{ isSignal: true, alias: "asset", required: true }] }]
|
|
84
|
+
}], propDecorators: { asset: [{ type: i0.Input, args: [{ isSignal: true, alias: "asset", required: true }] }] } });
|
|
88
85
|
|
|
89
86
|
/** The built-in English labels. */
|
|
90
87
|
const DEFAULT_CONTENTFUL_FILE_LABELS = {
|
|
@@ -107,8 +104,6 @@ class ContentfulFileComponent {
|
|
|
107
104
|
this.labels = injectContentfulFileLabels();
|
|
108
105
|
this.asset = input.required(/* @ts-ignore */
|
|
109
106
|
...(ngDevMode ? [{ debugName: "asset" }] : /* istanbul ignore next */ []));
|
|
110
|
-
this.fileClass = input(null, /* @ts-ignore */
|
|
111
|
-
...(ngDevMode ? [{ debugName: "fileClass" }] : /* istanbul ignore next */ []));
|
|
112
107
|
this.data = computed(() => {
|
|
113
108
|
const asset = this.asset();
|
|
114
109
|
if (!asset) {
|
|
@@ -133,16 +128,16 @@ class ContentfulFileComponent {
|
|
|
133
128
|
...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
134
129
|
}
|
|
135
130
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ContentfulFileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
136
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ContentfulFileComponent, isStandalone: true, selector: "et-contentful-file", inputs: { asset: { classPropertyName: "asset", publicName: "asset", isSignal: true, isRequired: true, transformFunction: null }
|
|
131
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ContentfulFileComponent, isStandalone: true, selector: "et-contentful-file", inputs: { asset: { classPropertyName: "asset", publicName: "asset", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "et-contentful-file" }, ngImport: i0, template: `
|
|
137
132
|
@if (data(); as data) {
|
|
138
|
-
<a [href]="data.url"
|
|
133
|
+
<a [href]="data.url" class="et-contentful-file-anchor" target="_blank" rel="noopener noreferrer">
|
|
139
134
|
{{ data.title }}
|
|
140
135
|
@if (data.size !== null) {
|
|
141
136
|
{{ labels().fileSize(data.size) }}
|
|
142
137
|
}
|
|
143
138
|
</a>
|
|
144
139
|
}
|
|
145
|
-
`, isInline: true,
|
|
140
|
+
`, isInline: true, encapsulation: i0.ViewEncapsulation.None }); }
|
|
146
141
|
}
|
|
147
142
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ContentfulFileComponent, decorators: [{
|
|
148
143
|
type: Component,
|
|
@@ -150,7 +145,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
150
145
|
selector: 'et-contentful-file',
|
|
151
146
|
template: `
|
|
152
147
|
@if (data(); as data) {
|
|
153
|
-
<a [href]="data.url"
|
|
148
|
+
<a [href]="data.url" class="et-contentful-file-anchor" target="_blank" rel="noopener noreferrer">
|
|
154
149
|
{{ data.title }}
|
|
155
150
|
@if (data.size !== null) {
|
|
156
151
|
{{ labels().fileSize(data.size) }}
|
|
@@ -159,12 +154,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
159
154
|
}
|
|
160
155
|
`,
|
|
161
156
|
encapsulation: ViewEncapsulation.None,
|
|
162
|
-
imports: [NgClass],
|
|
163
157
|
host: {
|
|
164
158
|
class: 'et-contentful-file',
|
|
165
159
|
},
|
|
166
160
|
}]
|
|
167
|
-
}], propDecorators: { asset: [{ type: i0.Input, args: [{ isSignal: true, alias: "asset", required: true }] }]
|
|
161
|
+
}], propDecorators: { asset: [{ type: i0.Input, args: [{ isSignal: true, alias: "asset", required: true }] }] } });
|
|
168
162
|
|
|
169
163
|
const CONTENTFUL_CONFIG = new InjectionToken('ContentfulConfig');
|
|
170
164
|
|
|
@@ -183,13 +177,16 @@ const CONTENTFUL_FALLBACK_CONFIG = {
|
|
|
183
177
|
backgroundColor: null,
|
|
184
178
|
},
|
|
185
179
|
};
|
|
180
|
+
const withoutUndefined = (value) => Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined));
|
|
186
181
|
const createContentfulConfig = (options) => {
|
|
187
182
|
const config = options ?? {};
|
|
188
183
|
return {
|
|
189
184
|
...CONTENTFUL_FALLBACK_CONFIG,
|
|
190
185
|
...config,
|
|
191
186
|
components: config.components ?? CONTENTFUL_FALLBACK_CONFIG.components,
|
|
192
|
-
|
|
187
|
+
customComponents: config.customComponents ?? CONTENTFUL_FALLBACK_CONFIG.customComponents,
|
|
188
|
+
internalHosts: config.internalHosts ?? CONTENTFUL_FALLBACK_CONFIG.internalHosts,
|
|
189
|
+
imageOptions: { ...CONTENTFUL_FALLBACK_CONFIG.imageOptions, ...withoutUndefined(config.imageOptions) },
|
|
193
190
|
};
|
|
194
191
|
};
|
|
195
192
|
/**
|
|
@@ -199,29 +196,8 @@ const createContentfulConfig = (options) => {
|
|
|
199
196
|
const injectContentfulConfig = () => inject(CONTENTFUL_CONFIG, { optional: true }) ?? CONTENTFUL_FALLBACK_CONFIG;
|
|
200
197
|
|
|
201
198
|
const generateDefaultContentfulImageSource = (data) => {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
return {
|
|
205
|
-
type: '',
|
|
206
|
-
srcset: '',
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
return {
|
|
210
|
-
type: data.contentType,
|
|
211
|
-
srcset: data.url,
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
const file = data.fields.file;
|
|
215
|
-
if (!file?.contentType || !file.url) {
|
|
216
|
-
return {
|
|
217
|
-
type: '',
|
|
218
|
-
srcset: '',
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
return {
|
|
222
|
-
type: file.contentType,
|
|
223
|
-
srcset: file.url,
|
|
224
|
-
};
|
|
199
|
+
const { url, contentType } = isContentfulGqlAsset(data) ? data : (data.fields.file ?? {});
|
|
200
|
+
return url ? { type: contentType ?? '', srcset: url } : { type: '', srcset: '' };
|
|
225
201
|
};
|
|
226
202
|
/**
|
|
227
203
|
* Parses source set sizes into an object containing with and height. Eg.
|
|
@@ -267,7 +243,7 @@ const generateContentfulImageSources = (data, options = {}) => {
|
|
|
267
243
|
const queryParams = [];
|
|
268
244
|
queryParams.push(`fm=${type.split('/')[1]}`);
|
|
269
245
|
if (backgroundColor) {
|
|
270
|
-
queryParams.push(`bg=rgb:${backgroundColor}`);
|
|
246
|
+
queryParams.push(`bg=rgb:${backgroundColor.replace(/^#/, '')}`);
|
|
271
247
|
}
|
|
272
248
|
if (quality !== null && Number.isFinite(quality)) {
|
|
273
249
|
queryParams.push(`q=${quality}`);
|
|
@@ -292,6 +268,11 @@ const generateContentfulImageSources = (data, options = {}) => {
|
|
|
292
268
|
const derivedWidth = Math.round((height * imageDimensions.width) / imageDimensions.height);
|
|
293
269
|
sourceSets.push(`${urlWithParams}&w=${derivedWidth}&h=${height} ${derivedWidth}w`);
|
|
294
270
|
}
|
|
271
|
+
else if (ngDevMode && type === SOURCE_TYPES[0]) {
|
|
272
|
+
console.warn(height
|
|
273
|
+
? `Contentful image: srcsetSizes entry "${size}" is dropped. A height-only size needs the asset's width and height to derive a width descriptor.`
|
|
274
|
+
: `Contentful image: srcsetSizes entry "${size}" is not a valid size and is dropped. Use "400", "400w", "400h" or "400x300"; viewport sizes like "50vw" belong in sizes.`);
|
|
275
|
+
}
|
|
295
276
|
}
|
|
296
277
|
}
|
|
297
278
|
sources.push({
|
|
@@ -377,7 +358,7 @@ class ContentfulImageComponent {
|
|
|
377
358
|
[sizes]="sizes()"
|
|
378
359
|
[sources]="sourcesValue()"
|
|
379
360
|
/>
|
|
380
|
-
`, isInline: true, dependencies: [{ kind: "component", type: PictureComponent, selector: "et-picture", inputs: ["sources", "defaultSrc", "alt", "figcaption", "priority", "width", "height", "aspectRatio", "sizes", "fit"], outputs: ["
|
|
361
|
+
`, isInline: true, dependencies: [{ kind: "component", type: PictureComponent, selector: "et-picture", inputs: ["sources", "defaultSrc", "alt", "figcaption", "priority", "width", "height", "aspectRatio", "sizes", "fit"], outputs: ["imageLoad", "imageError"] }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
381
362
|
}
|
|
382
363
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ContentfulImageComponent, decorators: [{
|
|
383
364
|
type: Component,
|
|
@@ -433,10 +414,18 @@ const isExternalWebHref = (href, context) => {
|
|
|
433
414
|
const url = parseWebUrl(href);
|
|
434
415
|
return url !== null && !isInternalWebUrl(url, context);
|
|
435
416
|
};
|
|
417
|
+
const hasUrlScheme = (href) => /^[a-z][a-z\d+.-]*:/i.test(href);
|
|
418
|
+
const isRouteRelativeHref = (href) => !hasUrlScheme(href) && !href.startsWith('/');
|
|
419
|
+
const resolveHrefAgainstRoute = (href, routerUrl) => {
|
|
420
|
+
const resolved = new URL(href, 'https://contentful.invalid' + routerUrl);
|
|
421
|
+
return resolved.pathname + resolved.search + resolved.hash;
|
|
422
|
+
};
|
|
436
423
|
|
|
424
|
+
const RICH_TEXT_ANCHOR_CLASSES = ['et-contentful-rich-text-default-element', 'et-contentful-rich-text-default-a'];
|
|
437
425
|
class ContentfulLinkComponent {
|
|
438
426
|
constructor() {
|
|
439
427
|
this.document = inject(DOCUMENT);
|
|
428
|
+
this.location = inject(Location);
|
|
440
429
|
this.router = inject(Router);
|
|
441
430
|
this.config = injectContentfulConfig();
|
|
442
431
|
this.url = injectUrl();
|
|
@@ -444,10 +433,10 @@ class ContentfulLinkComponent {
|
|
|
444
433
|
...(ngDevMode ? [{ debugName: "href" }] : /* istanbul ignore next */ []));
|
|
445
434
|
this.text = input.required(/* @ts-ignore */
|
|
446
435
|
...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
|
|
447
|
-
this.
|
|
448
|
-
...(ngDevMode ? [{ debugName: "
|
|
449
|
-
this.
|
|
450
|
-
...(ngDevMode ? [{ debugName: "
|
|
436
|
+
this.marks = input([], /* @ts-ignore */
|
|
437
|
+
...(ngDevMode ? [{ debugName: "marks" }] : /* istanbul ignore next */ []));
|
|
438
|
+
this.richText = input(false, /* @ts-ignore */
|
|
439
|
+
...(ngDevMode ? [{ debugName: "richText" }] : /* istanbul ignore next */ []));
|
|
451
440
|
this.usesRouterLink = computed(() => {
|
|
452
441
|
const href = this.href();
|
|
453
442
|
const absoluteUrl = parseWebUrl(href);
|
|
@@ -457,9 +446,14 @@ class ContentfulLinkComponent {
|
|
|
457
446
|
internalHosts: this.config.internalHosts,
|
|
458
447
|
});
|
|
459
448
|
}
|
|
460
|
-
return !href.startsWith('#') &&
|
|
449
|
+
return !href.startsWith('#') && !hasUrlScheme(href);
|
|
461
450
|
}, /* @ts-ignore */
|
|
462
451
|
...(ngDevMode ? [{ debugName: "usesRouterLink" }] : /* istanbul ignore next */ []));
|
|
452
|
+
this.anchorHref = computed(() => {
|
|
453
|
+
const href = this.href();
|
|
454
|
+
return href.startsWith('#') ? this.location.prepareExternalUrl(resolveHrefAgainstRoute(href, this.url())) : href;
|
|
455
|
+
}, /* @ts-ignore */
|
|
456
|
+
...(ngDevMode ? [{ debugName: "anchorHref" }] : /* istanbul ignore next */ []));
|
|
463
457
|
this.openInNewTab = computed(() => Boolean(parseWebUrl(this.href())) && !this.usesRouterLink(), /* @ts-ignore */
|
|
464
458
|
...(ngDevMode ? [{ debugName: "openInNewTab" }] : /* istanbul ignore next */ []));
|
|
465
459
|
this.internalPath = computed(() => {
|
|
@@ -471,25 +465,28 @@ class ContentfulLinkComponent {
|
|
|
471
465
|
if (href.startsWith('/')) {
|
|
472
466
|
return href;
|
|
473
467
|
}
|
|
474
|
-
|
|
475
|
-
return resolved.pathname + resolved.search + resolved.hash;
|
|
468
|
+
return resolveHrefAgainstRoute(href, this.url());
|
|
476
469
|
}, /* @ts-ignore */
|
|
477
470
|
...(ngDevMode ? [{ debugName: "internalPath" }] : /* istanbul ignore next */ []));
|
|
478
471
|
this.internalUrlTree = computed(() => this.router.parseUrl(this.internalPath()), /* @ts-ignore */
|
|
479
472
|
...(ngDevMode ? [{ debugName: "internalUrlTree" }] : /* istanbul ignore next */ []));
|
|
480
|
-
this.
|
|
481
|
-
|
|
473
|
+
this.modifierClasses = computed(() => [
|
|
474
|
+
...(this.richText() ? RICH_TEXT_ANCHOR_CLASSES : []),
|
|
475
|
+
...this.marks().map((mark) => `et-contentful-rich-text-mark-${mark}`),
|
|
476
|
+
], /* @ts-ignore */
|
|
477
|
+
...(ngDevMode ? [{ debugName: "modifierClasses" }] : /* istanbul ignore next */ []));
|
|
482
478
|
}
|
|
483
479
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ContentfulLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
484
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ContentfulLinkComponent, isStandalone: true, selector: "et-contentful-link", inputs: { href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: true, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null },
|
|
480
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ContentfulLinkComponent, isStandalone: true, selector: "et-contentful-link", inputs: { href: { classPropertyName: "href", publicName: "href", isSignal: true, isRequired: true, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, marks: { classPropertyName: "marks", publicName: "marks", isSignal: true, isRequired: false, transformFunction: null }, richText: { classPropertyName: "richText", publicName: "richText", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "et-contentful-link" }, ngImport: i0, template: `
|
|
485
481
|
@if (usesRouterLink()) {
|
|
486
|
-
<a [class]="
|
|
482
|
+
<a [class]="modifierClasses()" [routerLink]="internalUrlTree()" class="et-contentful-link-anchor">{{ text() }}</a>
|
|
487
483
|
} @else {
|
|
488
484
|
<a
|
|
489
|
-
[class]="
|
|
490
|
-
[href]="
|
|
491
|
-
[target]="openInNewTab() ? '_blank' : null"
|
|
492
|
-
[rel]="openInNewTab() ? 'noopener noreferrer' : null"
|
|
485
|
+
[class]="modifierClasses()"
|
|
486
|
+
[href]="anchorHref()"
|
|
487
|
+
[attr.target]="openInNewTab() ? '_blank' : null"
|
|
488
|
+
[attr.rel]="openInNewTab() ? 'noopener noreferrer' : null"
|
|
489
|
+
class="et-contentful-link-anchor"
|
|
493
490
|
>{{ text() }}</a
|
|
494
491
|
>
|
|
495
492
|
}
|
|
@@ -499,20 +496,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
499
496
|
type: Component,
|
|
500
497
|
args: [{ selector: 'et-contentful-link', template: `
|
|
501
498
|
@if (usesRouterLink()) {
|
|
502
|
-
<a [class]="
|
|
499
|
+
<a [class]="modifierClasses()" [routerLink]="internalUrlTree()" class="et-contentful-link-anchor">{{ text() }}</a>
|
|
503
500
|
} @else {
|
|
504
501
|
<a
|
|
505
|
-
[class]="
|
|
506
|
-
[href]="
|
|
507
|
-
[target]="openInNewTab() ? '_blank' : null"
|
|
508
|
-
[rel]="openInNewTab() ? 'noopener noreferrer' : null"
|
|
502
|
+
[class]="modifierClasses()"
|
|
503
|
+
[href]="anchorHref()"
|
|
504
|
+
[attr.target]="openInNewTab() ? '_blank' : null"
|
|
505
|
+
[attr.rel]="openInNewTab() ? 'noopener noreferrer' : null"
|
|
506
|
+
class="et-contentful-link-anchor"
|
|
509
507
|
>{{ text() }}</a
|
|
510
508
|
>
|
|
511
509
|
}
|
|
512
510
|
`, encapsulation: ViewEncapsulation.None, imports: [RouterLink], host: {
|
|
513
511
|
class: 'et-contentful-link',
|
|
514
512
|
}, styles: ["@layer components{.et-contentful-link{display:contents}}\n"] }]
|
|
515
|
-
}], propDecorators: { href: [{ type: i0.Input, args: [{ isSignal: true, alias: "href", required: true }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: true }] }],
|
|
513
|
+
}], propDecorators: { href: [{ type: i0.Input, args: [{ isSignal: true, alias: "href", required: true }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: true }] }], marks: [{ type: i0.Input, args: [{ isSignal: true, alias: "marks", required: false }] }], richText: [{ type: i0.Input, args: [{ isSignal: true, alias: "richText", required: false }] }] } });
|
|
516
514
|
|
|
517
515
|
/**
|
|
518
516
|
* The `BLOCKS` node type strings of `@contentful/rich-text-types`, as a plain literal map.
|
|
@@ -558,8 +556,9 @@ const CF_INLINES = {
|
|
|
558
556
|
};
|
|
559
557
|
|
|
560
558
|
const RICH_TEXT_RENDERER_ERRORS = {
|
|
561
|
-
|
|
559
|
+
rich_text_not_object: (data) => `The value at richTextPath is a ${data.type}, not a rich-text document object. Point richTextPath at the rich-text field itself (e.g. items[0].fields.body).`,
|
|
562
560
|
rich_text_wrong_type: 'The rich text object does not satisfy the RichTextResponse interface. It should contain a property named "nodeType" with the value "document".',
|
|
561
|
+
rich_text_conflicting_inputs: 'gqlRichText cannot be combined with content or richTextPath. Pass either a GraphQL rich-text field through gqlRichText, or a REST response through content and richTextPath.',
|
|
563
562
|
asset_id_not_found: 'The asset ID was not found. This node is not supported.',
|
|
564
563
|
entry_id_not_found: 'The entry ID was not found. This node is not supported.',
|
|
565
564
|
text_parent_not_found: 'The parent node is not found. This structure is not supported.',
|
|
@@ -567,8 +566,9 @@ const RICH_TEXT_RENDERER_ERRORS = {
|
|
|
567
566
|
cached_command_not_component: 'The rendered node for a component command is not a component. The renderer state is out of sync.',
|
|
568
567
|
};
|
|
569
568
|
const RICH_TEXT_RENDERER_ERROR_CODES = {
|
|
570
|
-
|
|
569
|
+
rich_text_not_object: 0,
|
|
571
570
|
rich_text_wrong_type: 1,
|
|
571
|
+
rich_text_conflicting_inputs: 11,
|
|
572
572
|
asset_id_not_found: 2,
|
|
573
573
|
entry_id_not_found: 3,
|
|
574
574
|
text_parent_not_found: 7,
|
|
@@ -576,10 +576,75 @@ const RICH_TEXT_RENDERER_ERROR_CODES = {
|
|
|
576
576
|
cached_command_not_component: 10,
|
|
577
577
|
};
|
|
578
578
|
const richTextRendererError = (code, data) => {
|
|
579
|
-
const
|
|
579
|
+
const entry = RICH_TEXT_RENDERER_ERRORS[code];
|
|
580
|
+
const message = `<et-contentful-rich-text-renderer>: ${typeof entry === 'function' ? entry(data) : entry}`;
|
|
580
581
|
throw new RuntimeError(RICH_TEXT_RENDERER_ERROR_CODES[code], message, data);
|
|
581
582
|
};
|
|
582
583
|
|
|
584
|
+
const lowerCaseFirst = (value) => value.charAt(0).toLowerCase() + value.slice(1);
|
|
585
|
+
const toRestAsset = (asset) => ({
|
|
586
|
+
sys: { type: 'Asset', id: asset.sys.id, createdAt: '', updatedAt: '', locale: '' },
|
|
587
|
+
fields: {
|
|
588
|
+
title: asset.title ?? '',
|
|
589
|
+
description: asset.description ?? '',
|
|
590
|
+
file: {
|
|
591
|
+
url: asset.url,
|
|
592
|
+
details: {
|
|
593
|
+
size: asset.size,
|
|
594
|
+
...(asset.width !== null && asset.height !== null
|
|
595
|
+
? { image: { width: asset.width, height: asset.height } }
|
|
596
|
+
: {}),
|
|
597
|
+
},
|
|
598
|
+
fileName: asset.fileName ?? null,
|
|
599
|
+
contentType: asset.contentType,
|
|
600
|
+
},
|
|
601
|
+
},
|
|
602
|
+
metadata: { tags: [] },
|
|
603
|
+
});
|
|
604
|
+
const toRestEntry = (entry) => {
|
|
605
|
+
const { __typename, sys, ...fields } = entry;
|
|
606
|
+
if (!__typename) {
|
|
607
|
+
return null;
|
|
608
|
+
}
|
|
609
|
+
return {
|
|
610
|
+
sys: {
|
|
611
|
+
type: 'Entry',
|
|
612
|
+
id: sys.id,
|
|
613
|
+
createdAt: '',
|
|
614
|
+
updatedAt: '',
|
|
615
|
+
locale: '',
|
|
616
|
+
contentType: { sys: { type: 'Link', linkType: 'ContentType', id: lowerCaseFirst(__typename) } },
|
|
617
|
+
},
|
|
618
|
+
fields,
|
|
619
|
+
metadata: { tags: [] },
|
|
620
|
+
};
|
|
621
|
+
};
|
|
622
|
+
const present = (items) => (items ?? []).filter((item) => item !== null && item !== undefined);
|
|
623
|
+
/**
|
|
624
|
+
* Maps the `links` of a GraphQL rich-text field to the entries and assets the renderer resolves
|
|
625
|
+
* embeds against. An entry's content type id is its `__typename` with the first letter lower-cased,
|
|
626
|
+
* which is how Contentful derives a GraphQL type name from a content type id. Entries without a
|
|
627
|
+
* `__typename` are dropped.
|
|
628
|
+
*/
|
|
629
|
+
const mapContentfulGqlLinks = (links) => {
|
|
630
|
+
const assets = new Map();
|
|
631
|
+
const entries = new Map();
|
|
632
|
+
for (const asset of [...present(links?.assets?.block), ...present(links?.assets?.hyperlink)]) {
|
|
633
|
+
assets.set(asset.sys.id, toRestAsset(asset));
|
|
634
|
+
}
|
|
635
|
+
for (const gqlEntry of [
|
|
636
|
+
...present(links?.entries?.block),
|
|
637
|
+
...present(links?.entries?.inline),
|
|
638
|
+
...present(links?.entries?.hyperlink),
|
|
639
|
+
]) {
|
|
640
|
+
const entry = toRestEntry(gqlEntry);
|
|
641
|
+
if (entry) {
|
|
642
|
+
entries.set(entry.sys.id, entry);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
return { assets: [...assets.values()], entries: [...entries.values()] };
|
|
646
|
+
};
|
|
647
|
+
|
|
583
648
|
const isRichTextRootNode = (node) => {
|
|
584
649
|
return isObject(node) && 'nodeType' in node && node['nodeType'] === 'document';
|
|
585
650
|
};
|
|
@@ -681,7 +746,7 @@ const createContentfulIncludeMap = (config) => {
|
|
|
681
746
|
const entry = entryMap.get(id);
|
|
682
747
|
if (!entry) {
|
|
683
748
|
if (isDevMode()) {
|
|
684
|
-
console.warn('Entry not found! Will return null. Is the include query param too low?', { id
|
|
749
|
+
console.warn('Entry not found! Will return null. Is it unpublished or deleted, or is the include query param too low?', { id });
|
|
685
750
|
}
|
|
686
751
|
return null;
|
|
687
752
|
}
|
|
@@ -720,6 +785,23 @@ const createContentfulIncludeMap = (config) => {
|
|
|
720
785
|
getAssets,
|
|
721
786
|
};
|
|
722
787
|
};
|
|
788
|
+
const warnedRichTextPaths = /* @__PURE__ */ new Set();
|
|
789
|
+
const warnOnUnresolvedParentPath = (content, richTextPath) => {
|
|
790
|
+
const segments = richTextPath.split('.');
|
|
791
|
+
const root = content;
|
|
792
|
+
if (segments.length < 2 || isObject(getObjectProperty(root, segments.slice(0, -1).join('.'))))
|
|
793
|
+
return;
|
|
794
|
+
if (warnedRichTextPaths.has(richTextPath))
|
|
795
|
+
return;
|
|
796
|
+
warnedRichTextPaths.add(richTextPath);
|
|
797
|
+
let resolvedSegments = 0;
|
|
798
|
+
while (resolvedSegments < segments.length - 1 &&
|
|
799
|
+
isObject(getObjectProperty(root, segments.slice(0, resolvedSegments + 1).join('.')))) {
|
|
800
|
+
resolvedSegments++;
|
|
801
|
+
}
|
|
802
|
+
const resolvedPath = segments.slice(0, resolvedSegments).join('.') || '(the content itself)';
|
|
803
|
+
console.warn(`<et-contentful-rich-text-renderer>: richTextPath "${richTextPath}" does not resolve, so nothing is rendered. The deepest part that resolves is ${resolvedPath}; check the next segment for a typo or a missing item.`, { content, richTextPath });
|
|
804
|
+
};
|
|
723
805
|
class ContentfulRichTextRendererComponent {
|
|
724
806
|
constructor() {
|
|
725
807
|
this.viewContainerRef = inject(ViewContainerRef);
|
|
@@ -727,38 +809,72 @@ class ContentfulRichTextRendererComponent {
|
|
|
727
809
|
this.elementRef = inject(ElementRef);
|
|
728
810
|
this.config = injectContentfulConfig();
|
|
729
811
|
this.document = inject(DOCUMENT);
|
|
812
|
+
this.location = inject(Location);
|
|
813
|
+
this.url = injectUrl();
|
|
730
814
|
/**
|
|
731
815
|
* The contentful response gotten via their REST api.
|
|
732
816
|
* @see https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/entries/entries-collection
|
|
733
817
|
*/
|
|
734
|
-
this.content = input
|
|
735
|
-
...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
|
|
818
|
+
this.content = input(/* @ts-ignore */
|
|
819
|
+
...(ngDevMode ? [undefined, { debugName: "content" }] : /* istanbul ignore next */ []));
|
|
736
820
|
/**
|
|
737
821
|
* The path to where the rich text field is inside the contentful response. Dot and array notation is allowed.
|
|
738
822
|
* @example "items[0].fields.html"
|
|
739
823
|
*/
|
|
740
|
-
this.richTextPath = input
|
|
741
|
-
...(ngDevMode ? [{ debugName: "richTextPath" }] : /* istanbul ignore next */ []));
|
|
824
|
+
this.richTextPath = input(/* @ts-ignore */
|
|
825
|
+
...(ngDevMode ? [undefined, { debugName: "richTextPath" }] : /* istanbul ignore next */ []));
|
|
826
|
+
/**
|
|
827
|
+
* A rich-text field from the Contentful GraphQL API, passed as-is. An alternative to `content` and
|
|
828
|
+
* `richTextPath`; setting both is an error in dev mode.
|
|
829
|
+
* @example { json, links: { assets: { block, hyperlink }, entries: { block, inline, hyperlink } } }
|
|
830
|
+
*/
|
|
831
|
+
this.gqlRichText = input(/* @ts-ignore */
|
|
832
|
+
...(ngDevMode ? [undefined, { debugName: "gqlRichText" }] : /* istanbul ignore next */ []));
|
|
742
833
|
this.executedCommandsCache = new Map();
|
|
743
|
-
this.
|
|
744
|
-
const
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
834
|
+
this.includes = computed(() => {
|
|
835
|
+
const gqlRichText = this.gqlRichText();
|
|
836
|
+
if (gqlRichText) {
|
|
837
|
+
return mapContentfulGqlLinks(gqlRichText.links);
|
|
838
|
+
}
|
|
839
|
+
const includes = this.content()?.includes;
|
|
840
|
+
return { assets: includes?.Asset ?? [], entries: includes?.Entry ?? [] };
|
|
748
841
|
}, /* @ts-ignore */
|
|
842
|
+
...(ngDevMode ? [{ debugName: "includes" }] : /* istanbul ignore next */ []));
|
|
843
|
+
this.contentIncludesMap = computed(() => createContentfulIncludeMap(this.includes()), /* @ts-ignore */
|
|
749
844
|
...(ngDevMode ? [{ debugName: "contentIncludesMap" }] : /* istanbul ignore next */ []));
|
|
845
|
+
this.includedEntries = computed(() => new Map(this.includes().entries.map((entry) => [entry.sys.id, entry])), /* @ts-ignore */
|
|
846
|
+
...(ngDevMode ? [{ debugName: "includedEntries" }] : /* istanbul ignore next */ []));
|
|
750
847
|
this.richTextData = computed(() => {
|
|
848
|
+
const gqlRichText = this.gqlRichText();
|
|
751
849
|
const content = this.content();
|
|
752
850
|
const richTextPath = this.richTextPath();
|
|
851
|
+
if (ngDevMode && gqlRichText && (content || richTextPath)) {
|
|
852
|
+
throw richTextRendererError('rich_text_conflicting_inputs', { gqlRichText, content, richTextPath });
|
|
853
|
+
}
|
|
854
|
+
if (gqlRichText) {
|
|
855
|
+
if (!isRichTextRootNode(gqlRichText.json)) {
|
|
856
|
+
throw richTextRendererError('rich_text_wrong_type', { gqlRichText });
|
|
857
|
+
}
|
|
858
|
+
return gqlRichText.json;
|
|
859
|
+
}
|
|
753
860
|
if (!content) {
|
|
754
861
|
return null;
|
|
755
862
|
}
|
|
863
|
+
if (!richTextPath) {
|
|
864
|
+
if (ngDevMode) {
|
|
865
|
+
console.warn('<et-contentful-rich-text-renderer>: content is set without richTextPath, so nothing is rendered. Set richTextPath, or pass a GraphQL field through gqlRichText.');
|
|
866
|
+
}
|
|
867
|
+
return null;
|
|
868
|
+
}
|
|
756
869
|
const richText = getObjectProperty(content, richTextPath);
|
|
757
870
|
if (richText === null || richText === undefined) {
|
|
871
|
+
if (ngDevMode && richText === undefined) {
|
|
872
|
+
warnOnUnresolvedParentPath(content, richTextPath);
|
|
873
|
+
}
|
|
758
874
|
return null;
|
|
759
875
|
}
|
|
760
876
|
if (!isObject(richText)) {
|
|
761
|
-
throw richTextRendererError('
|
|
877
|
+
throw richTextRendererError('rich_text_not_object', { content, richTextPath, type: typeof richText });
|
|
762
878
|
}
|
|
763
879
|
if (!isRichTextRootNode(richText)) {
|
|
764
880
|
throw richTextRendererError('rich_text_wrong_type', { content, richTextPath });
|
|
@@ -892,8 +1008,7 @@ class ContentfulRichTextRendererComponent {
|
|
|
892
1008
|
}
|
|
893
1009
|
const contentType = asset.fields.file?.contentType;
|
|
894
1010
|
const assetComponents = this.config.components;
|
|
895
|
-
|
|
896
|
-
if (isMissing) {
|
|
1011
|
+
if (!asset.fields.file?.url) {
|
|
897
1012
|
if (isDevMode()) {
|
|
898
1013
|
console.warn('Asset is missing file data! Asset will be skipped. Did you forget to upload a file for the current translation in Contentful?', { asset });
|
|
899
1014
|
}
|
|
@@ -945,10 +1060,16 @@ class ContentfulRichTextRendererComponent {
|
|
|
945
1060
|
href = url ? normalizeHref(url) : null;
|
|
946
1061
|
}
|
|
947
1062
|
const linkTexts = node.content.filter((child) => child.nodeType === 'text' && Boolean(child.value));
|
|
1063
|
+
if (!linkTexts.length) {
|
|
1064
|
+
break;
|
|
1065
|
+
}
|
|
948
1066
|
const linkText = linkTexts.map((child) => child.value).join('');
|
|
949
1067
|
const linkComponent = href ? this.config.components.link : null;
|
|
950
1068
|
if (href && !linkComponent) {
|
|
951
|
-
const
|
|
1069
|
+
const anchorHref = isRouteRelativeHref(href)
|
|
1070
|
+
? this.location.prepareExternalUrl(resolveHrefAgainstRoute(href, this.url()))
|
|
1071
|
+
: href;
|
|
1072
|
+
const attributes = { class: DEFAULT_ANCHOR_CLASS, href: anchorHref };
|
|
952
1073
|
if (isExternalWebHref(href, { location: this.document.location, internalHosts: this.config.internalHosts })) {
|
|
953
1074
|
attributes['target'] = '_blank';
|
|
954
1075
|
attributes['rel'] = 'noopener noreferrer';
|
|
@@ -993,7 +1114,6 @@ class ContentfulRichTextRendererComponent {
|
|
|
993
1114
|
break;
|
|
994
1115
|
}
|
|
995
1116
|
const sharedMarks = linkTexts[0]?.marks.filter((mark) => linkTexts.every((child) => child.marks.some((other) => other.type === mark.type))) ?? [];
|
|
996
|
-
const textClass = marksToClass(sharedMarks);
|
|
997
1117
|
let linkComponentId = componentIdMap.get(LINK_COMPONENT_TYPE) ?? -1;
|
|
998
1118
|
const linkId = LINK_COMPONENT_TYPE + ++linkComponentId;
|
|
999
1119
|
componentIdMap.set(LINK_COMPONENT_TYPE, linkComponentId);
|
|
@@ -1003,7 +1123,7 @@ class ContentfulRichTextRendererComponent {
|
|
|
1003
1123
|
domPosition,
|
|
1004
1124
|
parentId: openElementIds.at(-1) ?? null,
|
|
1005
1125
|
component: linkComponent,
|
|
1006
|
-
inputs: { href, text: linkText,
|
|
1126
|
+
inputs: { href, text: linkText, marks: sharedMarks.map((mark) => mark.type), richText: true },
|
|
1007
1127
|
id: linkId,
|
|
1008
1128
|
});
|
|
1009
1129
|
domPosition++;
|
|
@@ -1015,10 +1135,10 @@ class ContentfulRichTextRendererComponent {
|
|
|
1015
1135
|
if (!entryId) {
|
|
1016
1136
|
throw richTextRendererError('entry_id_not_found', { node });
|
|
1017
1137
|
}
|
|
1018
|
-
const entry = this.
|
|
1138
|
+
const entry = this.includedEntries().get(entryId);
|
|
1019
1139
|
if (!entry) {
|
|
1020
1140
|
if (isDevMode()) {
|
|
1021
|
-
console.warn('Embedded entry is missing from the includes! The entry will be skipped. Is it unpublished or deleted?', { entryId, node });
|
|
1141
|
+
console.warn('Embedded entry is missing from the includes! The entry will be skipped. Is it unpublished or deleted, or is the include query param too low?', { entryId, node });
|
|
1022
1142
|
}
|
|
1023
1143
|
break;
|
|
1024
1144
|
}
|
|
@@ -1263,7 +1383,7 @@ class ContentfulRichTextRendererComponent {
|
|
|
1263
1383
|
this.renderer.insertBefore(parentElement, node, previousSibling ? previousSibling.nextSibling : parentElement.firstChild);
|
|
1264
1384
|
}
|
|
1265
1385
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ContentfulRichTextRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1266
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: ContentfulRichTextRendererComponent, isStandalone: true, selector: "et-contentful-rich-text-renderer", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired:
|
|
1386
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", type: ContentfulRichTextRendererComponent, isStandalone: true, selector: "et-contentful-rich-text-renderer", inputs: { content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, richTextPath: { classPropertyName: "richTextPath", publicName: "richTextPath", isSignal: true, isRequired: false, transformFunction: null }, gqlRichText: { classPropertyName: "gqlRichText", publicName: "gqlRichText", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "et-contentful-rich-text-renderer" }, ngImport: i0, template: ``, isInline: true, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1267
1387
|
}
|
|
1268
1388
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ContentfulRichTextRendererComponent, decorators: [{
|
|
1269
1389
|
type: Component,
|
|
@@ -1275,14 +1395,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
1275
1395
|
class: 'et-contentful-rich-text-renderer',
|
|
1276
1396
|
},
|
|
1277
1397
|
}]
|
|
1278
|
-
}], ctorParameters: () => [], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required:
|
|
1398
|
+
}], ctorParameters: () => [], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], richTextPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "richTextPath", required: false }] }], gqlRichText: [{ type: i0.Input, args: [{ isSignal: true, alias: "gqlRichText", required: false }] }] } });
|
|
1279
1399
|
|
|
1280
1400
|
class ContentfulVideoComponent {
|
|
1281
1401
|
constructor() {
|
|
1282
1402
|
this.asset = input.required(/* @ts-ignore */
|
|
1283
1403
|
...(ngDevMode ? [{ debugName: "asset" }] : /* istanbul ignore next */ []));
|
|
1284
|
-
this.videoClass = input(null, /* @ts-ignore */
|
|
1285
|
-
...(ngDevMode ? [{ debugName: "videoClass" }] : /* istanbul ignore next */ []));
|
|
1286
1404
|
this.data = computed(() => {
|
|
1287
1405
|
const asset = this.asset();
|
|
1288
1406
|
if (!asset) {
|
|
@@ -1305,13 +1423,13 @@ class ContentfulVideoComponent {
|
|
|
1305
1423
|
...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
1306
1424
|
}
|
|
1307
1425
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ContentfulVideoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1308
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ContentfulVideoComponent, isStandalone: true, selector: "et-contentful-video", inputs: { asset: { classPropertyName: "asset", publicName: "asset", isSignal: true, isRequired: true, transformFunction: null }
|
|
1426
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ContentfulVideoComponent, isStandalone: true, selector: "et-contentful-video", inputs: { asset: { classPropertyName: "asset", publicName: "asset", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "et-contentful-video" }, ngImport: i0, template: `
|
|
1309
1427
|
@if (data(); as data) {
|
|
1310
|
-
<video
|
|
1311
|
-
<source [src]="data.url" [type]="data.contentType" />
|
|
1428
|
+
<video class="et-contentful-video-video" controls>
|
|
1429
|
+
<source [src]="data.url" [attr.type]="data.contentType || null" class="et-contentful-video-source" />
|
|
1312
1430
|
</video>
|
|
1313
1431
|
}
|
|
1314
|
-
`, isInline: true,
|
|
1432
|
+
`, isInline: true, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1315
1433
|
}
|
|
1316
1434
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ContentfulVideoComponent, decorators: [{
|
|
1317
1435
|
type: Component,
|
|
@@ -1319,18 +1437,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
|
|
|
1319
1437
|
selector: 'et-contentful-video',
|
|
1320
1438
|
template: `
|
|
1321
1439
|
@if (data(); as data) {
|
|
1322
|
-
<video
|
|
1323
|
-
<source [src]="data.url" [type]="data.contentType" />
|
|
1440
|
+
<video class="et-contentful-video-video" controls>
|
|
1441
|
+
<source [src]="data.url" [attr.type]="data.contentType || null" class="et-contentful-video-source" />
|
|
1324
1442
|
</video>
|
|
1325
1443
|
}
|
|
1326
1444
|
`,
|
|
1327
1445
|
encapsulation: ViewEncapsulation.None,
|
|
1328
|
-
imports: [NgClass],
|
|
1329
1446
|
host: {
|
|
1330
1447
|
class: 'et-contentful-video',
|
|
1331
1448
|
},
|
|
1332
1449
|
}]
|
|
1333
|
-
}], propDecorators: { asset: [{ type: i0.Input, args: [{ isSignal: true, alias: "asset", required: true }] }]
|
|
1450
|
+
}], propDecorators: { asset: [{ type: i0.Input, args: [{ isSignal: true, alias: "asset", required: true }] }] } });
|
|
1334
1451
|
|
|
1335
1452
|
const ContentfulImports = [
|
|
1336
1453
|
ContentfulAudioComponent,
|
|
@@ -1367,5 +1484,5 @@ const isContentfulEntryType = (entry, type) => entry.sys.contentType.sys.id ===
|
|
|
1367
1484
|
* Generated bundle index. Do not edit.
|
|
1368
1485
|
*/
|
|
1369
1486
|
|
|
1370
|
-
export { CONTENTFUL_CONFIG, CONTENTFUL_DEFAULT_COMPONENTS, CONTENTFUL_FILE_LABELS, ContentfulAudioComponent, ContentfulFileComponent, ContentfulImageComponent, ContentfulImports, ContentfulLinkComponent, ContentfulRichTextRendererComponent, ContentfulVideoComponent, DEFAULT_CONTENTFUL_FILE_LABELS, ET_CONTENTFUL_ANY_ENTRY_CONTENT_TYPE_SYS_ID, GQL_FRAGMENT_CONTENTFUL_ASSET, createContentfulConfig, createContentfulIncludeMap, generateContentfulImageSources, generateDefaultContentfulImageSource, injectContentfulConfig, injectContentfulFileLabels, isContentfulEntryType, isContentfulGqlAsset, isRichTextRootNode, marksToClass, marksToTags, parseContentfulImageSize, provideContentfulConfig, provideContentfulFileLabels, translateContentfulNodeTypeToHtmlTag };
|
|
1487
|
+
export { CONTENTFUL_CONFIG, CONTENTFUL_DEFAULT_COMPONENTS, CONTENTFUL_FILE_LABELS, ContentfulAudioComponent, ContentfulFileComponent, ContentfulImageComponent, ContentfulImports, ContentfulLinkComponent, ContentfulRichTextRendererComponent, ContentfulVideoComponent, DEFAULT_CONTENTFUL_FILE_LABELS, ET_CONTENTFUL_ANY_ENTRY_CONTENT_TYPE_SYS_ID, GQL_FRAGMENT_CONTENTFUL_ASSET, createContentfulConfig, createContentfulIncludeMap, generateContentfulImageSources, generateDefaultContentfulImageSource, injectContentfulConfig, injectContentfulFileLabels, isContentfulEntryType, isContentfulGqlAsset, isRichTextRootNode, mapContentfulGqlLinks, marksToClass, marksToTags, parseContentfulImageSize, provideContentfulConfig, provideContentfulFileLabels, translateContentfulNodeTypeToHtmlTag };
|
|
1371
1488
|
//# sourceMappingURL=ethlete-contentful.mjs.map
|