@financial-times/cp-content-pipeline-ui 7.3.2 → 7.4.0
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 +13 -0
- package/lib/components/content-tree/Clip/client/index.d.ts +3 -0
- package/lib/components/content-tree/Clip/client/index.js +2 -0
- package/lib/components/content-tree/Clip/client/index.js.map +1 -1
- package/lib/components/content-tree/Clip/components/ClipTag.d.ts +1 -0
- package/lib/components/content-tree/Clip/components/ClipTag.js +2 -2
- package/lib/components/content-tree/Clip/components/ClipTag.js.map +1 -1
- package/lib/components/content-tree/Clip/template/component.js +3 -2
- package/lib/components/content-tree/Clip/template/component.js.map +1 -1
- package/lib/components/content-tree/Clip/test/index.spec.js +21 -0
- package/lib/components/content-tree/Clip/test/index.spec.js.map +1 -1
- package/lib/components/content-tree/CustomCodeComponent/client/index.d.ts +1 -1
- package/lib/components/content-tree/CustomCodeComponent/client/index.js +1 -1
- package/lib/components/content-tree/CustomCodeComponent/client/index.js.map +1 -1
- package/lib/components/content-tree/CustomCodeComponent/client/tracking.d.ts +4 -2
- package/lib/components/content-tree/CustomCodeComponent/client/tracking.js +38 -19
- package/lib/components/content-tree/CustomCodeComponent/client/tracking.js.map +1 -1
- package/lib/components/content-tree/Workarounds.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/content-tree/Clip/client/index.ts +5 -0
- package/src/components/content-tree/Clip/components/ClipTag.tsx +3 -0
- package/src/components/content-tree/Clip/template/component.tsx +3 -0
- package/src/components/content-tree/Clip/test/__snapshots__/snapshot.spec.tsx.snap +8 -0
- package/src/components/content-tree/Clip/test/index.spec.ts +23 -0
- package/src/components/content-tree/CustomCodeComponent/client/index.ts +8 -5
- package/src/components/content-tree/CustomCodeComponent/client/tracking.ts +55 -29
- package/src/components/content-tree/Workarounds.ts +1 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -11,7 +11,7 @@ declare class CustomCodeComponentClient {
|
|
|
11
11
|
*/
|
|
12
12
|
tracking: CustomCodeComponentTracker;
|
|
13
13
|
constructor(el: Element);
|
|
14
|
-
static init(rootEl?: Element):
|
|
14
|
+
static init(rootEl?: Element): CustomCodeComponentClient[] | void;
|
|
15
15
|
static destroy(components: CustomCodeComponentClient[]): void;
|
|
16
16
|
}
|
|
17
17
|
export default CustomCodeComponentClient;
|
|
@@ -20,7 +20,7 @@ class CustomCodeComponentClient {
|
|
|
20
20
|
}
|
|
21
21
|
static init(rootEl) {
|
|
22
22
|
const root = rootEl instanceof Element ? rootEl : document;
|
|
23
|
-
return Array.from(root.querySelectorAll('custom-code-component')).map((el) => new CustomCodeComponentClient(el));
|
|
23
|
+
return Array.from(root.querySelectorAll('custom-code-component:not([data-initialised])')).map((el) => new CustomCodeComponentClient(el));
|
|
24
24
|
}
|
|
25
25
|
static destroy(components) {
|
|
26
26
|
components.forEach((component) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/components/content-tree/CustomCodeComponent/client/index.ts"],"names":[],"mappings":";;AAAA,yCAAuD;AAEvD;;;;;GAKG;AACH,MAAM,yBAAyB;IAM7B,YAAY,EAAW;QACrB,MAAM,YAAY,GAAG;YACnB,SAAS,EAAE;gBACT,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE;gBAC/B,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE;gBACnC,IAAI,EAAE,uBAAuB;aAC9B;SACF,CAAA;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,qCAA0B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/components/content-tree/CustomCodeComponent/client/index.ts"],"names":[],"mappings":";;AAAA,yCAAuD;AAEvD;;;;;GAKG;AACH,MAAM,yBAAyB;IAM7B,YAAY,EAAW;QACrB,MAAM,YAAY,GAAG;YACnB,SAAS,EAAE;gBACT,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE;gBAC/B,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE;gBACnC,IAAI,EAAE,uBAAuB;aAC9B;SACF,CAAA;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,qCAA0B,CAC5C,EAAiB,EACjB,YAAY,CACb,CAAA;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,MAAgB;QAC1B,MAAM,IAAI,GAAG,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAA;QAC1D,OAAO,KAAK,CAAC,IAAI,CACf,IAAI,CAAC,gBAAgB,CAAC,+CAA+C,CAAC,CACvE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,yBAAyB,CAAC,EAAE,CAAC,CAAC,CAAA;IAClD,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,UAAuC;QACpD,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;YAC/B,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;QAC9B,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AAED,kBAAe,yBAAyB,CAAA"}
|
|
@@ -16,10 +16,12 @@ type TrackingData = {
|
|
|
16
16
|
declare class CustomCodeComponentTracker {
|
|
17
17
|
private component;
|
|
18
18
|
private trackingData;
|
|
19
|
-
private
|
|
19
|
+
private mutationObserver?;
|
|
20
|
+
private intersectionObserver?;
|
|
20
21
|
private viewing?;
|
|
21
|
-
constructor(component:
|
|
22
|
+
constructor(component: HTMLElement, trackingData: TrackingData);
|
|
22
23
|
private init;
|
|
24
|
+
private mutationCallback;
|
|
23
25
|
private onCccConnected;
|
|
24
26
|
private onCccError;
|
|
25
27
|
private onView;
|
|
@@ -12,32 +12,53 @@ class CustomCodeComponentTracker {
|
|
|
12
12
|
this.component = component;
|
|
13
13
|
this.trackingData = trackingData;
|
|
14
14
|
this.component = component;
|
|
15
|
-
if (this.component.hasAttribute('data-o-tracking-initialised')) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
15
|
this.trackingData = trackingData;
|
|
19
|
-
//
|
|
16
|
+
// we're using a mutation observer to watch for changes to the component rather than event listeners
|
|
17
|
+
// as dynamic imports in the app are run before the tracking client can be instantiated on second
|
|
18
|
+
// and subsequent page visits in a session
|
|
19
|
+
// the observers need to instantiated here so that they can be accessed correctly in the destroy method
|
|
20
20
|
// called by the app
|
|
21
|
-
this.
|
|
21
|
+
this.mutationObserver = new MutationObserver(this.mutationCallback.bind(this));
|
|
22
|
+
this.mutationObserver.observe(this.component, {
|
|
23
|
+
attributes: true,
|
|
24
|
+
attributeFilter: ['data-ccc-ready', 'data-ccc-error'],
|
|
25
|
+
});
|
|
26
|
+
this.intersectionObserver = new IntersectionObserver(this.onChange.bind(this), {
|
|
22
27
|
rootMargin: `0px 0px -300px 0px`,
|
|
23
28
|
threshold: 0,
|
|
24
29
|
});
|
|
25
|
-
this.
|
|
30
|
+
this.intersectionObserver.observe(this.component);
|
|
26
31
|
this.viewing = false;
|
|
27
32
|
this.destroy = this.destroy.bind(this);
|
|
28
33
|
this.init();
|
|
29
34
|
}
|
|
30
35
|
init() {
|
|
31
36
|
this.dispatchEvent('mount');
|
|
32
|
-
this.component.
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
if (this.component.dataset.cccError) {
|
|
38
|
+
this.onCccError();
|
|
39
|
+
}
|
|
40
|
+
if (this.component.dataset.cccReady) {
|
|
41
|
+
this.onCccConnected();
|
|
42
|
+
}
|
|
43
|
+
this.component.dataset.initialised = 'true';
|
|
44
|
+
}
|
|
45
|
+
mutationCallback(mutationsList) {
|
|
46
|
+
for (const mutation of mutationsList) {
|
|
47
|
+
if (mutation.attributeName === 'data-ccc-ready') {
|
|
48
|
+
this.onCccConnected();
|
|
49
|
+
}
|
|
50
|
+
if (mutation.attributeName === 'data-ccc-error') {
|
|
51
|
+
this.onCccError();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
35
54
|
}
|
|
36
55
|
onCccConnected() {
|
|
37
56
|
this.dispatchEvent('act', { trigger_action: 'success' });
|
|
38
57
|
}
|
|
39
58
|
onCccError() {
|
|
40
|
-
this.dispatchEvent('act', {
|
|
59
|
+
this.dispatchEvent('act', {
|
|
60
|
+
trigger_action: `error: ${this.component.dataset.cccError}`,
|
|
61
|
+
});
|
|
41
62
|
}
|
|
42
63
|
onView() {
|
|
43
64
|
this.dispatchEvent('view');
|
|
@@ -75,15 +96,13 @@ class CustomCodeComponentTracker {
|
|
|
75
96
|
});
|
|
76
97
|
}
|
|
77
98
|
destroy() {
|
|
78
|
-
if (this.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
}
|
|
99
|
+
if (!this.component)
|
|
100
|
+
return;
|
|
101
|
+
this.component.removeAttribute('data-initialised');
|
|
102
|
+
this.mutationObserver?.disconnect();
|
|
103
|
+
this.intersectionObserver?.unobserve(this.component);
|
|
104
|
+
this.intersectionObserver?.disconnect();
|
|
105
|
+
this.viewing && this.onExitView();
|
|
87
106
|
}
|
|
88
107
|
}
|
|
89
108
|
exports.CustomCodeComponentTracker = CustomCodeComponentTracker;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracking.js","sourceRoot":"","sources":["../../../../../src/components/content-tree/CustomCodeComponent/client/tracking.ts"],"names":[],"mappings":";;;AAWA;;;;;GAKG;AACH,MAAM,0BAA0B;
|
|
1
|
+
{"version":3,"file":"tracking.js","sourceRoot":"","sources":["../../../../../src/components/content-tree/CustomCodeComponent/client/tracking.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -33,6 +33,7 @@ interface Opts {
|
|
|
33
33
|
intersectionObserverThreshold?: number
|
|
34
34
|
closedCaption?: boolean
|
|
35
35
|
caption?: string
|
|
36
|
+
systemTitle?: string
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
interface TrackingData {
|
|
@@ -44,8 +45,10 @@ interface TrackingData {
|
|
|
44
45
|
amount?: number
|
|
45
46
|
amountPercentage?: number
|
|
46
47
|
video: {
|
|
48
|
+
id?: string
|
|
47
49
|
duration?: number
|
|
48
50
|
source_url?: string
|
|
51
|
+
name?: string
|
|
49
52
|
layout?: string
|
|
50
53
|
loop?: number
|
|
51
54
|
type: string
|
|
@@ -353,8 +356,10 @@ class Clip extends ClipInterface {
|
|
|
353
356
|
progress: this.getRelevantProgress(),
|
|
354
357
|
url: window.location.href,
|
|
355
358
|
video: {
|
|
359
|
+
id: this.opts.id,
|
|
356
360
|
duration: this.getDuration(),
|
|
357
361
|
source_url: this.opts.id,
|
|
362
|
+
name: this.opts.systemTitle,
|
|
358
363
|
layout: this.opts.layout,
|
|
359
364
|
// Counter of the number of times the video has looped
|
|
360
365
|
loop: this.loops,
|
|
@@ -27,6 +27,7 @@ interface ClipTagProps {
|
|
|
27
27
|
credits?: string
|
|
28
28
|
caption?: string
|
|
29
29
|
preload?: string
|
|
30
|
+
systemTitle?: string
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
export const ClipTag: React.FC<ClipTagProps> = ({
|
|
@@ -47,6 +48,7 @@ export const ClipTag: React.FC<ClipTagProps> = ({
|
|
|
47
48
|
noInfoBox = false,
|
|
48
49
|
noCaption = false,
|
|
49
50
|
dataTrackable,
|
|
51
|
+
systemTitle,
|
|
50
52
|
}) => {
|
|
51
53
|
const { pixelWidth, pixelHeight } = clip?.dataSource?.[0]
|
|
52
54
|
? clip.dataSource[0]
|
|
@@ -68,6 +70,7 @@ export const ClipTag: React.FC<ClipTagProps> = ({
|
|
|
68
70
|
data-trackable={dataTrackable}
|
|
69
71
|
data-o-component="cp-clip"
|
|
70
72
|
data-cp-clip-id={id}
|
|
73
|
+
data-cp-clip-system-title={systemTitle}
|
|
71
74
|
>
|
|
72
75
|
{!noInfoBox && <VideoInfoBox />}
|
|
73
76
|
<div className="cp-clip__video-container">
|
|
@@ -64,6 +64,7 @@ const ClipComponent: React.FC<ClipProps> = ({
|
|
|
64
64
|
clip?.dataSource?.length && content.autoplay ? '' : poster
|
|
65
65
|
const noAudio = content.noAudio ?? false
|
|
66
66
|
const accessibility = content.accessibility ?? {}
|
|
67
|
+
const systemTitle = content.systemTitle ?? ''
|
|
67
68
|
|
|
68
69
|
if (preset === 'thumbnail') {
|
|
69
70
|
return (
|
|
@@ -80,6 +81,7 @@ const ClipComponent: React.FC<ClipProps> = ({
|
|
|
80
81
|
noCaption
|
|
81
82
|
noDescription
|
|
82
83
|
noInfoBox
|
|
84
|
+
systemTitle={systemTitle}
|
|
83
85
|
/>
|
|
84
86
|
)
|
|
85
87
|
}
|
|
@@ -99,6 +101,7 @@ const ClipComponent: React.FC<ClipProps> = ({
|
|
|
99
101
|
clip={clip}
|
|
100
102
|
credits={content.credits ?? ''}
|
|
101
103
|
caption={content.caption ?? ''}
|
|
104
|
+
systemTitle={systemTitle}
|
|
102
105
|
accessibility={accessibility}
|
|
103
106
|
preload={preload}
|
|
104
107
|
dataTrackable="next-article-cp-clip"
|
|
@@ -16,6 +16,7 @@ exports[`Clip Snapshot component rendered on server full-grid default render 1`]
|
|
|
16
16
|
data-trackable=\\"next-article-cp-clip\\"
|
|
17
17
|
data-o-component=\\"cp-clip\\"
|
|
18
18
|
data-cp-clip-id=\\"localhost:8080/fakevideo.mpg\\"
|
|
19
|
+
data-cp-clip-system-title=\\"\\"
|
|
19
20
|
>
|
|
20
21
|
<div
|
|
21
22
|
data-o-component=\\"o-expander\\"
|
|
@@ -82,6 +83,7 @@ exports[`Clip Snapshot component rendered on server full-grid render with attrib
|
|
|
82
83
|
data-trackable=\\"next-article-cp-clip\\"
|
|
83
84
|
data-o-component=\\"cp-clip\\"
|
|
84
85
|
data-cp-clip-id=\\"localhost:8080/fakevideo.mpg\\"
|
|
86
|
+
data-cp-clip-system-title=\\"\\"
|
|
85
87
|
>
|
|
86
88
|
<div
|
|
87
89
|
data-o-component=\\"o-expander\\"
|
|
@@ -172,6 +174,7 @@ exports[`Clip Snapshot component rendered on server in-line render 1`] = `
|
|
|
172
174
|
data-trackable=\\"next-article-cp-clip\\"
|
|
173
175
|
data-o-component=\\"cp-clip\\"
|
|
174
176
|
data-cp-clip-id=\\"localhost:8080/fakevideo.mpg\\"
|
|
177
|
+
data-cp-clip-system-title=\\"\\"
|
|
175
178
|
>
|
|
176
179
|
<div
|
|
177
180
|
data-o-component=\\"o-expander\\"
|
|
@@ -236,6 +239,7 @@ exports[`Clip Snapshot component rendered on server in-line render with attribut
|
|
|
236
239
|
data-trackable=\\"next-article-cp-clip\\"
|
|
237
240
|
data-o-component=\\"cp-clip\\"
|
|
238
241
|
data-cp-clip-id=\\"localhost:8080/fakevideo.mpg\\"
|
|
242
|
+
data-cp-clip-system-title=\\"\\"
|
|
239
243
|
>
|
|
240
244
|
<div
|
|
241
245
|
data-o-component=\\"o-expander\\"
|
|
@@ -330,6 +334,7 @@ exports[`Clip Snapshot component rendered on server mid-grid default render 1`]
|
|
|
330
334
|
data-trackable=\\"next-article-cp-clip\\"
|
|
331
335
|
data-o-component=\\"cp-clip\\"
|
|
332
336
|
data-cp-clip-id=\\"localhost:8080/fakevideo.mpg\\"
|
|
337
|
+
data-cp-clip-system-title=\\"\\"
|
|
333
338
|
>
|
|
334
339
|
<div
|
|
335
340
|
data-o-component=\\"o-expander\\"
|
|
@@ -401,6 +406,7 @@ exports[`Clip Snapshot component rendered on server mid-grid render with attribu
|
|
|
401
406
|
data-trackable=\\"next-article-cp-clip\\"
|
|
402
407
|
data-o-component=\\"cp-clip\\"
|
|
403
408
|
data-cp-clip-id=\\"localhost:8080/fakevideo.mpg\\"
|
|
409
|
+
data-cp-clip-system-title=\\"\\"
|
|
404
410
|
>
|
|
405
411
|
<div
|
|
406
412
|
data-o-component=\\"o-expander\\"
|
|
@@ -498,6 +504,7 @@ exports[`Clip Snapshot component rendered on server renders multiple video sourc
|
|
|
498
504
|
data-trackable=\\"next-article-cp-clip\\"
|
|
499
505
|
data-o-component=\\"cp-clip\\"
|
|
500
506
|
data-cp-clip-id=\\"84d7e1b0-e8b2-4ffc-a798-306f29dc9d52\\"
|
|
507
|
+
data-cp-clip-system-title=\\"\\"
|
|
501
508
|
>
|
|
502
509
|
<div
|
|
503
510
|
data-o-component=\\"o-expander\\"
|
|
@@ -600,6 +607,7 @@ exports[`Clip Snapshot component rendered on server supports new Origami images,
|
|
|
600
607
|
data-trackable=\\"next-article-cp-clip\\"
|
|
601
608
|
data-o-component=\\"cp-clip\\"
|
|
602
609
|
data-cp-clip-id=\\"localhost:8080/fakevideo.mpg\\"
|
|
610
|
+
data-cp-clip-system-title=\\"\\"
|
|
603
611
|
>
|
|
604
612
|
<div
|
|
605
613
|
data-o-component=\\"o-expander\\"
|
|
@@ -183,6 +183,9 @@ describe('Clip', () => {
|
|
|
183
183
|
expect(clip.opts.layout).toBe(
|
|
184
184
|
clip.containerEl.getAttribute('data-cp-clip-layout')
|
|
185
185
|
)
|
|
186
|
+
expect(clip.opts.systemTitle).toBe(
|
|
187
|
+
clip.containerEl.getAttribute('data-cp-clip-system-title')
|
|
188
|
+
)
|
|
186
189
|
})
|
|
187
190
|
|
|
188
191
|
it('dispatches an analytics mount event when the component is initialised', () => {
|
|
@@ -192,10 +195,12 @@ describe('Clip', () => {
|
|
|
192
195
|
expect(data).not.toBeFalsy()
|
|
193
196
|
expect(data.video.duration).toBe(0)
|
|
194
197
|
//expect(data.contentId).toBe(clip.opts.id);
|
|
198
|
+
expect(data.video.id).toBe(clip.opts.id)
|
|
195
199
|
expect(data.video.layout).toBe(clip.opts.layout)
|
|
196
200
|
expect(data.video.loop).toBe(0)
|
|
197
201
|
expect(data.video.type).toBe('clip')
|
|
198
202
|
expect(data.video.automated).toBe(false)
|
|
203
|
+
expect(data.video.name).toBe(clip.opts.systemTitle)
|
|
199
204
|
expect(data.progress).toBe(0)
|
|
200
205
|
expect(data.category).toBe('video')
|
|
201
206
|
expect(data.action).toBe(eventType)
|
|
@@ -210,10 +215,12 @@ describe('Clip', () => {
|
|
|
210
215
|
expect(e.detail.category).toBe('video')
|
|
211
216
|
expect(e.detail.video.duration).toBe(10000)
|
|
212
217
|
//expect(e.detail.contentId).toBe(clip.opts.id);
|
|
218
|
+
expect(e.detail.video.id).toBe(clip.opts.id)
|
|
213
219
|
expect(e.detail.video.layout).toBe(clip.opts.layout)
|
|
214
220
|
expect(e.detail.video.loop).toBe(0)
|
|
215
221
|
expect(e.detail.video.type).toBe('clip')
|
|
216
222
|
expect(e.detail.video.automated).toBe(false)
|
|
223
|
+
expect(e.detail.video.name).toBe(clip.opts.systemTitle)
|
|
217
224
|
expect(e.detail.progress).toBe(0)
|
|
218
225
|
expect(spy).toHaveBeenCalled()
|
|
219
226
|
expect(clip.started).toBe(true)
|
|
@@ -238,10 +245,12 @@ describe('Clip', () => {
|
|
|
238
245
|
expect(e.detail.action).toBe(eventType)
|
|
239
246
|
expect(e.detail.video.duration).toBe(10000)
|
|
240
247
|
//expect(e.detail.contentId).toBe(clip.opts.id);
|
|
248
|
+
expect(e.detail.video.id).toBe(clip.opts.id)
|
|
241
249
|
expect(e.detail.video.layout).toBe(clip.opts.layout)
|
|
242
250
|
expect(e.detail.video.loop).toBe(0)
|
|
243
251
|
expect(e.detail.video.type).toBe('clip')
|
|
244
252
|
expect(e.detail.video.automated).toBe(false)
|
|
253
|
+
expect(e.detail.video.name).toBe(clip.opts.systemTitle)
|
|
245
254
|
expect(e.detail.progress).toBe(0)
|
|
246
255
|
expect(spy).toHaveBeenCalled()
|
|
247
256
|
expect(clip.started).toBe(true)
|
|
@@ -266,10 +275,12 @@ describe('Clip', () => {
|
|
|
266
275
|
expect(e.detail.action).toBe(eventType)
|
|
267
276
|
expect(e.detail.video.duration).toBe(10000)
|
|
268
277
|
//expect(e.detail.contentId).toBe(clip.opts.id);
|
|
278
|
+
expect(e.detail.video.id).toBe(clip.opts.id)
|
|
269
279
|
expect(e.detail.video.layout).toBe(clip.opts.layout)
|
|
270
280
|
expect(e.detail.video.loop).toBe(0)
|
|
271
281
|
expect(e.detail.video.type).toBe('clip')
|
|
272
282
|
expect(e.detail.video.automated).toBe(false)
|
|
283
|
+
expect(e.detail.video.name).toBe(clip.opts.systemTitle)
|
|
273
284
|
expect(e.detail.progress).toBe(25)
|
|
274
285
|
document.body.removeEventListener('oTracking.event', listener)
|
|
275
286
|
done()
|
|
@@ -339,10 +350,12 @@ describe('Clip', () => {
|
|
|
339
350
|
expect(e.detail.action).toBe(eventType)
|
|
340
351
|
expect(e.detail.video.duration).toBe(10000)
|
|
341
352
|
//expect(e.detail.contentId).toBe(clip.opts.id);
|
|
353
|
+
expect(e.detail.video.id).toBe(clip.opts.id)
|
|
342
354
|
expect(e.detail.video.layout).toBe(clip.opts.layout)
|
|
343
355
|
expect(e.detail.video.loop).toBe(0)
|
|
344
356
|
expect(e.detail.video.type).toBe('clip')
|
|
345
357
|
expect(e.detail.video.automated).toBe(false)
|
|
358
|
+
expect(e.detail.video.name).toBe(clip.opts.systemTitle)
|
|
346
359
|
expect(e.detail.progress).toBe(0)
|
|
347
360
|
expect(spy).toHaveBeenCalled()
|
|
348
361
|
expect(spy2).toHaveBeenCalled()
|
|
@@ -374,10 +387,12 @@ describe('Clip', () => {
|
|
|
374
387
|
expect(e.detail.category).toBe('video')
|
|
375
388
|
expect(e.detail.video.duration).toBe(10000)
|
|
376
389
|
//expect(e.detail.contentId).toBe(clip.opts.id);
|
|
390
|
+
expect(e.detail.video.id).toBe(clip.opts.id)
|
|
377
391
|
expect(e.detail.video.layout).toBe(clip.opts.layout)
|
|
378
392
|
expect(e.detail.video.loop).toBe(0)
|
|
379
393
|
expect(e.detail.video.type).toBe('clip')
|
|
380
394
|
expect(e.detail.video.automated).toBe(false)
|
|
395
|
+
expect(e.detail.video.name).toBe(clip.opts.systemTitle)
|
|
381
396
|
expect(spy).toHaveBeenCalled()
|
|
382
397
|
expect(clip.started).toBe(true)
|
|
383
398
|
expect(clip.canAutoplay).toBe(false)
|
|
@@ -492,9 +507,11 @@ describe('Clip', () => {
|
|
|
492
507
|
expect(e.detail.category).toBe('video')
|
|
493
508
|
expect(e.detail.video.duration).toBe(10000)
|
|
494
509
|
//expect(e.detail.contentId).toBe(clip.opts.id);
|
|
510
|
+
expect(e.detail.video.id).toBe(clip.opts.id)
|
|
495
511
|
expect(e.detail.video.layout).toBe(clip.opts.layout)
|
|
496
512
|
expect(e.detail.video.loop).toBe(0)
|
|
497
513
|
expect(e.detail.video.type).toBe('clip')
|
|
514
|
+
expect(e.detail.video.name).toBe(clip.opts.systemTitle)
|
|
498
515
|
expect(e.detail.progress).toBe(0)
|
|
499
516
|
expect(clip.started).toBe(true)
|
|
500
517
|
expect(clip.playStart).not.toBeFalsy()
|
|
@@ -514,9 +531,11 @@ describe('Clip', () => {
|
|
|
514
531
|
expect(e.detail.category).toBe('video')
|
|
515
532
|
expect(e.detail.video.duration).toBe(10000)
|
|
516
533
|
//expect(e.detail.contentId).toBe(clip.opts.id);
|
|
534
|
+
expect(e.detail.video.id).toBe(clip.opts.id)
|
|
517
535
|
expect(e.detail.video.layout).toBe(clip.opts.layout)
|
|
518
536
|
expect(e.detail.video.loop).toBe(0)
|
|
519
537
|
expect(e.detail.video.type).toBe('clip')
|
|
538
|
+
expect(e.detail.video.name).toBe(clip.opts.systemTitle)
|
|
520
539
|
expect(e.detail.progress).toBe(0)
|
|
521
540
|
expect(clip.started).toBe(true)
|
|
522
541
|
expect(clip.playStart).toBeFalsy()
|
|
@@ -537,10 +556,12 @@ describe('Clip', () => {
|
|
|
537
556
|
expect(e.detail.category).toBe('video')
|
|
538
557
|
expect(e.detail.video.duration).toBe(10000)
|
|
539
558
|
//expect(e.detail.contentId).toBe(clip.opts.id);
|
|
559
|
+
expect(e.detail.video.id).toBe(clip.opts.id)
|
|
540
560
|
expect(e.detail.video.layout).toBe(clip.opts.layout)
|
|
541
561
|
expect(e.detail.video.loop).toBe(0)
|
|
542
562
|
expect(e.detail.video.type).toBe('clip')
|
|
543
563
|
expect(e.detail.video.automated).toBe(false)
|
|
564
|
+
expect(e.detail.video.name).toBe(clip.opts.systemTitle)
|
|
544
565
|
expect(e.detail.progress).toBe(0)
|
|
545
566
|
expect(clip.started).toBe(true)
|
|
546
567
|
expect(clip.canAutoplay).toBe(false)
|
|
@@ -562,10 +583,12 @@ describe('Clip', () => {
|
|
|
562
583
|
expect(e.detail.category).toBe('video')
|
|
563
584
|
expect(e.detail.video.duration).toBe(10000)
|
|
564
585
|
//expect(e.detail.contentId).toBe(clip.opts.id);
|
|
586
|
+
expect(e.detail.video.id).toBe(clip.opts.id)
|
|
565
587
|
expect(e.detail.video.layout).toBe(clip.opts.layout)
|
|
566
588
|
expect(e.detail.video.loop).toBe(0)
|
|
567
589
|
expect(e.detail.video.type).toBe('clip')
|
|
568
590
|
expect(e.detail.video.automated).toBe(false)
|
|
591
|
+
expect(e.detail.video.name).toBe(clip.opts.systemTitle)
|
|
569
592
|
expect(e.detail.progress).toBe(0)
|
|
570
593
|
expect(clip.started).toBe(true)
|
|
571
594
|
expect(clip.canAutoplay).toBe(false)
|
|
@@ -20,14 +20,17 @@ class CustomCodeComponentClient {
|
|
|
20
20
|
type: 'custom-code-component',
|
|
21
21
|
},
|
|
22
22
|
}
|
|
23
|
-
this.tracking = new CustomCodeComponentTracker(
|
|
23
|
+
this.tracking = new CustomCodeComponentTracker(
|
|
24
|
+
el as HTMLElement,
|
|
25
|
+
trackingData
|
|
26
|
+
)
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
static init(rootEl?: Element):
|
|
29
|
+
static init(rootEl?: Element): CustomCodeComponentClient[] | void {
|
|
27
30
|
const root = rootEl instanceof Element ? rootEl : document
|
|
28
|
-
return Array.from(
|
|
29
|
-
(
|
|
30
|
-
)
|
|
31
|
+
return Array.from(
|
|
32
|
+
root.querySelectorAll('custom-code-component:not([data-initialised])')
|
|
33
|
+
).map((el) => new CustomCodeComponentClient(el))
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
static destroy(components: CustomCodeComponentClient[]): void {
|
|
@@ -16,22 +16,36 @@ type TrackingData = {
|
|
|
16
16
|
* @param {TrackingData} trackingData - The specific component data
|
|
17
17
|
*/
|
|
18
18
|
class CustomCodeComponentTracker {
|
|
19
|
-
private
|
|
19
|
+
private mutationObserver?: MutationObserver
|
|
20
|
+
private intersectionObserver?: IntersectionObserver
|
|
20
21
|
private viewing?: boolean
|
|
21
22
|
|
|
22
|
-
constructor(
|
|
23
|
+
constructor(
|
|
24
|
+
private component: HTMLElement,
|
|
25
|
+
private trackingData: TrackingData
|
|
26
|
+
) {
|
|
23
27
|
this.component = component
|
|
24
|
-
if (this.component.hasAttribute('data-o-tracking-initialised')) {
|
|
25
|
-
return
|
|
26
|
-
}
|
|
27
28
|
this.trackingData = trackingData
|
|
28
|
-
//
|
|
29
|
+
// we're using a mutation observer to watch for changes to the component rather than event listeners
|
|
30
|
+
// as dynamic imports in the app are run before the tracking client can be instantiated on second
|
|
31
|
+
// and subsequent page visits in a session
|
|
32
|
+
// the observers need to instantiated here so that they can be accessed correctly in the destroy method
|
|
29
33
|
// called by the app
|
|
30
|
-
this.
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
this.mutationObserver = new MutationObserver(
|
|
35
|
+
this.mutationCallback.bind(this)
|
|
36
|
+
)
|
|
37
|
+
this.mutationObserver.observe(this.component, {
|
|
38
|
+
attributes: true,
|
|
39
|
+
attributeFilter: ['data-ccc-ready', 'data-ccc-error'],
|
|
33
40
|
})
|
|
34
|
-
this.
|
|
41
|
+
this.intersectionObserver = new IntersectionObserver(
|
|
42
|
+
this.onChange.bind(this),
|
|
43
|
+
{
|
|
44
|
+
rootMargin: `0px 0px -300px 0px`,
|
|
45
|
+
threshold: 0,
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
this.intersectionObserver.observe(this.component)
|
|
35
49
|
this.viewing = false
|
|
36
50
|
this.destroy = this.destroy.bind(this)
|
|
37
51
|
this.init()
|
|
@@ -39,12 +53,26 @@ class CustomCodeComponentTracker {
|
|
|
39
53
|
|
|
40
54
|
private init() {
|
|
41
55
|
this.dispatchEvent('mount')
|
|
42
|
-
this.component.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
)
|
|
47
|
-
|
|
56
|
+
if (this.component.dataset.cccError) {
|
|
57
|
+
this.onCccError()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (this.component.dataset.cccReady) {
|
|
61
|
+
this.onCccConnected()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.component.dataset.initialised = 'true'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private mutationCallback(mutationsList: MutationRecord[]): void {
|
|
68
|
+
for (const mutation of mutationsList) {
|
|
69
|
+
if (mutation.attributeName === 'data-ccc-ready') {
|
|
70
|
+
this.onCccConnected()
|
|
71
|
+
}
|
|
72
|
+
if (mutation.attributeName === 'data-ccc-error') {
|
|
73
|
+
this.onCccError()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
48
76
|
}
|
|
49
77
|
|
|
50
78
|
private onCccConnected(): void {
|
|
@@ -52,7 +80,9 @@ class CustomCodeComponentTracker {
|
|
|
52
80
|
}
|
|
53
81
|
|
|
54
82
|
private onCccError(): void {
|
|
55
|
-
this.dispatchEvent('act', {
|
|
83
|
+
this.dispatchEvent('act', {
|
|
84
|
+
trigger_action: `error: ${this.component.dataset.cccError}`,
|
|
85
|
+
})
|
|
56
86
|
}
|
|
57
87
|
|
|
58
88
|
private onView(): void {
|
|
@@ -99,18 +129,14 @@ class CustomCodeComponentTracker {
|
|
|
99
129
|
}
|
|
100
130
|
|
|
101
131
|
destroy(): void {
|
|
102
|
-
if (this.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (this.viewing) {
|
|
111
|
-
this.onExitView()
|
|
112
|
-
}
|
|
113
|
-
}
|
|
132
|
+
if (!this.component) return
|
|
133
|
+
|
|
134
|
+
this.component.removeAttribute('data-initialised')
|
|
135
|
+
this.mutationObserver?.disconnect()
|
|
136
|
+
this.intersectionObserver?.unobserve(this.component)
|
|
137
|
+
this.intersectionObserver?.disconnect()
|
|
138
|
+
|
|
139
|
+
this.viewing && this.onExitView()
|
|
114
140
|
}
|
|
115
141
|
}
|
|
116
142
|
|