@vouchfor/embeds 0.0.0-experiment.af36011 → 0.0.0-experiment.b393461
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/dist/es/browser-e4ee4939.js +433 -0
- package/dist/es/browser-e4ee4939.js.map +1 -0
- package/dist/es/embeds.js +7 -1521
- package/dist/es/embeds.js.map +1 -1
- package/dist/es/index-358857aa.js +9952 -0
- package/dist/es/index-358857aa.js.map +1 -0
- package/dist/es/{components → src/components}/Embed/controllers/fetcher.d.ts +1 -0
- package/dist/es/{components → src/components}/Embed/controllers/tracking.d.ts +6 -3
- package/dist/es/{components → src/components}/Embed/index.d.ts +5 -1
- package/dist/iife/embeds.iife.js +437 -309
- package/dist/iife/embeds.iife.js.map +1 -1
- package/package.json +5 -3
- package/src/components/Embed/Embed.spec.ts +17 -0
- package/src/components/Embed/Embed.stories.ts +14 -1
- package/src/components/Embed/controllers/fetcher.ts +27 -8
- package/src/components/Embed/controllers/tracking.ts +90 -101
- package/src/components/Embed/index.ts +21 -6
- /package/dist/es/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/es/{utils → src/utils}/env.d.ts +0 -0
- /package/dist/es/{utils → src/utils}/events.d.ts +0 -0
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vouchfor/embeds",
|
3
|
-
"version": "0.0.0-experiment.
|
3
|
+
"version": "0.0.0-experiment.b393461",
|
4
4
|
"license": "MIT",
|
5
5
|
"author": "Aaron Williams",
|
6
6
|
"main": "dist/es/embeds.js",
|
@@ -28,7 +28,8 @@
|
|
28
28
|
"size": "size-limit",
|
29
29
|
"storybook": "yarn prebuild && storybook dev -p 6007",
|
30
30
|
"prebuild": "yarn build:deps && yarn generate:manifest",
|
31
|
-
"test": "
|
31
|
+
"test": "rm -rf test/lib && yarn prebuild && vite build --mode test && web-test-runner",
|
32
|
+
"test:ci": "yarn test"
|
32
33
|
},
|
33
34
|
"lint-staged": {
|
34
35
|
"**/*.{ts,tsx,js}": "eslint --fix --quiet",
|
@@ -36,7 +37,7 @@
|
|
36
37
|
},
|
37
38
|
"dependencies": {
|
38
39
|
"@lit/task": "^1.0.0",
|
39
|
-
"@vouchfor/media-player": "0.0.0-experiment.
|
40
|
+
"@vouchfor/media-player": "0.0.0-experiment.b393461",
|
40
41
|
"uuid": "^9.0.1"
|
41
42
|
},
|
42
43
|
"peerDependencies": {
|
@@ -69,6 +70,7 @@
|
|
69
70
|
"storybook": "^7.4.5",
|
70
71
|
"typescript": "^5.1.3",
|
71
72
|
"vite": "^4.4.9",
|
73
|
+
"vite-plugin-commonjs": "^0.10.0",
|
72
74
|
"vite-plugin-dts": "^3.6.0",
|
73
75
|
"web-component-analyzer": "^1.1.7"
|
74
76
|
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { expect } from '@esm-bundle/chai';
|
2
|
+
// import { fixture } from '@open-wc/testing';
|
3
|
+
// import { html } from 'lit';
|
4
|
+
|
5
|
+
// import type { Embed } from './index.js';
|
6
|
+
|
7
|
+
// Can't use typescript aliases with esbuild file transforms apparently
|
8
|
+
// No idea what a good way to actually build before testing is, the examples give nothing
|
9
|
+
// https://modern-web.dev/guides/test-runner/typescript/
|
10
|
+
import '../../test/lib/embeds.js';
|
11
|
+
|
12
|
+
describe('Embeds', () => {
|
13
|
+
it('passes', async () => {
|
14
|
+
expect(true).to.be.true;
|
15
|
+
// const player = await fixture<Embed>(html`<vouch-embed aspectratio=${1}></vouch-embed>`);
|
16
|
+
});
|
17
|
+
});
|
@@ -10,7 +10,17 @@ type EmbedArgs = EmbedProps & {
|
|
10
10
|
showVouch?: boolean;
|
11
11
|
};
|
12
12
|
|
13
|
-
const _Embed = ({
|
13
|
+
const _Embed = ({
|
14
|
+
vouchId,
|
15
|
+
templateId,
|
16
|
+
questions,
|
17
|
+
preload,
|
18
|
+
autoplay,
|
19
|
+
env,
|
20
|
+
apiKey,
|
21
|
+
controls,
|
22
|
+
aspectRatio
|
23
|
+
}: EmbedArgs) => {
|
14
24
|
return html`
|
15
25
|
<div style="height: 100vh">
|
16
26
|
<vouch-embed
|
@@ -18,10 +28,12 @@ const _Embed = ({ vouchId, templateId, preload, autoplay, env, apiKey, controls,
|
|
18
28
|
apiKey=${ifDefined(apiKey)}
|
19
29
|
vouchId=${ifDefined(vouchId)}
|
20
30
|
templateId=${ifDefined(templateId)}
|
31
|
+
.questions=${questions}
|
21
32
|
.controls=${controls}
|
22
33
|
?autoplay=${autoplay}
|
23
34
|
preload=${ifDefined(preload)}
|
24
35
|
aspectRatio=${ifDefined(aspectRatio)}
|
36
|
+
@error=${console.log}
|
25
37
|
></vouch-embed>
|
26
38
|
</div>
|
27
39
|
`;
|
@@ -43,6 +55,7 @@ const Embed: Story = {
|
|
43
55
|
apiKey: 'TVik9uTMgE-PD25UTHIS6gyl0hMBWC7AT4dkpdlLBT4VIfDWZJrQiCk6Ak7m1',
|
44
56
|
vouchId: '6JQEIPeStt',
|
45
57
|
templateId: '357fc118-e179-4171-9446-ff2b8e9d1b29',
|
58
|
+
questions: [],
|
46
59
|
aspectRatio: 0,
|
47
60
|
preload: 'none',
|
48
61
|
autoplay: false
|
@@ -9,7 +9,7 @@ import { getEnvUrls } from '~/utils/env';
|
|
9
9
|
|
10
10
|
type EmbedHost = ReactiveControllerHost & Embed;
|
11
11
|
|
12
|
-
type
|
12
|
+
type FetchTaskDeps = [
|
13
13
|
EmbedProps['env'],
|
14
14
|
EmbedProps['apiKey'],
|
15
15
|
EmbedProps['data'],
|
@@ -17,10 +17,13 @@ type TaskDeps = [
|
|
17
17
|
EmbedProps['templateId']
|
18
18
|
];
|
19
19
|
|
20
|
+
type FilterTaskDeps = [EmbedProps['data'], EmbedProps['questions']];
|
21
|
+
|
20
22
|
class FetcherController {
|
21
23
|
host: EmbedHost;
|
22
24
|
|
23
25
|
private _fetching = false;
|
26
|
+
private _vouch: EmbedProps['data'];
|
24
27
|
|
25
28
|
set fetching(value) {
|
26
29
|
if (this._fetching !== value) {
|
@@ -45,13 +48,13 @@ class FetcherController {
|
|
45
48
|
});
|
46
49
|
|
47
50
|
const vouch = await res.json();
|
48
|
-
this.host.dispatchEvent(new CustomEvent('vouch:loaded', { detail:
|
51
|
+
this.host.dispatchEvent(new CustomEvent('vouch:loaded', { detail: vouch?.id }));
|
49
52
|
|
50
53
|
// HACK: we're currently using API Gateway caching on the embed API without any invalidation logic,
|
51
54
|
// so to ensure that the cache stays up to date, whenever we detect a cache hit we trigger another
|
52
55
|
// API call with the `Cache-Control` header which will re-fill the cache
|
53
56
|
const resCacheCheck = res?.headers?.get('X-Cache-Check');
|
54
|
-
if (resCacheCheck
|
57
|
+
if (resCacheCheck !== cacheCheck) {
|
55
58
|
fetch(`${embedApiUrl}/vouches/${vouchId}`, {
|
56
59
|
method: 'GET',
|
57
60
|
headers: [
|
@@ -81,7 +84,7 @@ class FetcherController {
|
|
81
84
|
// so to ensure that the cache stays up to date, whenever we detect a cache hit we trigger another
|
82
85
|
// API call with the `Cache-Control` header which will re-fill the cache
|
83
86
|
const resCacheCheck = res?.headers?.get('X-Cache-Check');
|
84
|
-
if (resCacheCheck
|
87
|
+
if (resCacheCheck !== cacheCheck) {
|
85
88
|
fetch(`${embedApiUrl}/templates/${templateId}`, {
|
86
89
|
method: 'GET',
|
87
90
|
headers: [
|
@@ -96,9 +99,9 @@ class FetcherController {
|
|
96
99
|
|
97
100
|
constructor(host: EmbedHost) {
|
98
101
|
this.host = host;
|
99
|
-
new Task<
|
102
|
+
new Task<FetchTaskDeps, void>(
|
100
103
|
this.host,
|
101
|
-
async ([env, apiKey, data, vouchId, templateId]:
|
104
|
+
async ([env, apiKey, data, vouchId, templateId]: FetchTaskDeps) => {
|
102
105
|
try {
|
103
106
|
host.vouch = undefined;
|
104
107
|
host.template = undefined;
|
@@ -109,7 +112,7 @@ class FetcherController {
|
|
109
112
|
this.fetching = true;
|
110
113
|
template = await this.getTemplate(env, apiKey, templateId);
|
111
114
|
}
|
112
|
-
|
115
|
+
this._vouch = data;
|
113
116
|
host.template = template ?? data?.settings?.template?.instance;
|
114
117
|
} else if (vouchId) {
|
115
118
|
this.fetching = true;
|
@@ -118,7 +121,7 @@ class FetcherController {
|
|
118
121
|
this.getVouch(env, apiKey, vouchId),
|
119
122
|
templateId ? this.getTemplate(env, apiKey, templateId) : null
|
120
123
|
]);
|
121
|
-
|
124
|
+
this._vouch = vouch;
|
122
125
|
host.template = template ?? vouch?.settings?.template?.instance;
|
123
126
|
}
|
124
127
|
} finally {
|
@@ -127,6 +130,22 @@ class FetcherController {
|
|
127
130
|
},
|
128
131
|
() => [host.env, host.apiKey, host.data, host.vouchId, host.templateId]
|
129
132
|
);
|
133
|
+
|
134
|
+
// This second task is to be able to filter the vouch without fetching it again if only the questions changed
|
135
|
+
new Task<FilterTaskDeps, void>(
|
136
|
+
this.host,
|
137
|
+
([vouch, questions]: FilterTaskDeps) => {
|
138
|
+
host.vouch = vouch
|
139
|
+
? {
|
140
|
+
...vouch,
|
141
|
+
questions: {
|
142
|
+
items: vouch?.questions.items.filter((_, index) => !questions?.length || questions?.includes(index + 1))
|
143
|
+
}
|
144
|
+
}
|
145
|
+
: undefined;
|
146
|
+
},
|
147
|
+
() => [this._vouch, host.questions]
|
148
|
+
);
|
130
149
|
}
|
131
150
|
}
|
132
151
|
|
@@ -1,19 +1,20 @@
|
|
1
|
-
|
1
|
+
import { TEMPLATE_VERSION } from '@vouchfor/canvas-video';
|
2
2
|
import { v4 as uuidv4 } from 'uuid';
|
3
3
|
|
4
4
|
import type { Embed } from '..';
|
5
5
|
import type { VideoEventDetail } from '@vouchfor/media-player';
|
6
6
|
import type { ReactiveController, ReactiveControllerHost } from 'lit';
|
7
7
|
|
8
|
+
import packageJson from '../../../../package.json';
|
8
9
|
import { getEnvUrls } from '~/utils/env';
|
9
10
|
|
10
|
-
const
|
11
|
+
const MINIMUM_SEND_THRESHOLD = 1;
|
11
12
|
|
12
13
|
type EmbedHost = ReactiveControllerHost & Embed;
|
13
14
|
|
14
15
|
type TrackingEvent = 'VOUCH_LOADED' | 'VOUCH_RESPONSE_VIEWED' | 'VIDEO_PLAYED' | 'VIDEO_STREAMED';
|
15
16
|
type TrackingPayload = {
|
16
|
-
vouchId
|
17
|
+
vouchId?: string;
|
17
18
|
answerId?: string;
|
18
19
|
streamStart?: number;
|
19
20
|
streamEnd?: number;
|
@@ -37,22 +38,23 @@ class TrackingController implements ReactiveController {
|
|
37
38
|
private _hasPlayed = false;
|
38
39
|
private _hasLoaded: BooleanMap = {};
|
39
40
|
private _answersViewed: BooleanMap = {};
|
40
|
-
private
|
41
|
+
private _streamStartTime: TimeMap = {};
|
41
42
|
private _streamLatestTime: TimeMap = {};
|
42
|
-
private
|
43
|
+
private _currentlyPlayingVideo: VideoEventDetail | null = null;
|
43
44
|
|
44
45
|
constructor(host: EmbedHost) {
|
45
46
|
this.host = host;
|
46
47
|
host.addController(this);
|
47
48
|
}
|
48
49
|
|
49
|
-
private _findVouchId() {
|
50
|
+
private _findVouchId(payload?: TrackingPayload) {
|
51
|
+
if (payload && 'vouchId' in payload) {
|
52
|
+
return payload.vouchId;
|
53
|
+
}
|
50
54
|
if (this.host.vouch) {
|
51
|
-
if ('uuid' in this.host.vouch) {
|
52
|
-
return this.host.vouch.uuid;
|
53
|
-
}
|
54
55
|
return this.host.vouch.id;
|
55
56
|
}
|
57
|
+
return null;
|
56
58
|
}
|
57
59
|
|
58
60
|
private _createVisitor = (visitorId: string) => {
|
@@ -126,23 +128,31 @@ class TrackingController implements ReactiveController {
|
|
126
128
|
screenWidth: window.screen.width,
|
127
129
|
referrer: document.referrer,
|
128
130
|
currentUrl: location.href,
|
131
|
+
embedType: 'media-player-embed',
|
132
|
+
embedVersion: packageJson.version,
|
133
|
+
templateVersion: TEMPLATE_VERSION,
|
129
134
|
...utmParams
|
130
135
|
};
|
131
136
|
};
|
132
137
|
|
133
|
-
private _sendTrackingEvent = (event: TrackingEvent, payload
|
134
|
-
const
|
135
|
-
const { client, tab, request, visitor } = this._getUids();
|
138
|
+
private _sendTrackingEvent = (event: TrackingEvent, payload?: TrackingPayload) => {
|
139
|
+
const vouchId = this._findVouchId(payload);
|
136
140
|
|
137
|
-
if (this.host.disableTracking) {
|
141
|
+
if (!vouchId || this.host.disableTracking) {
|
138
142
|
return;
|
139
143
|
}
|
140
144
|
|
145
|
+
const { publicApiUrl } = getEnvUrls(this.host.env);
|
146
|
+
const { client, tab, request, visitor } = this._getUids();
|
147
|
+
|
141
148
|
navigator.sendBeacon(
|
142
|
-
`${publicApiUrl}/api/events`,
|
149
|
+
`${publicApiUrl}/api/v2/events`,
|
143
150
|
JSON.stringify({
|
144
151
|
event,
|
145
|
-
payload
|
152
|
+
payload: {
|
153
|
+
...payload,
|
154
|
+
vouchId
|
155
|
+
},
|
146
156
|
context: {
|
147
157
|
'x-uid-client': client,
|
148
158
|
'x-uid-tab': tab,
|
@@ -154,6 +164,26 @@ class TrackingController implements ReactiveController {
|
|
154
164
|
);
|
155
165
|
};
|
156
166
|
|
167
|
+
private _streamEnded = () => {
|
168
|
+
if (this._currentlyPlayingVideo) {
|
169
|
+
const { id, key } = this._currentlyPlayingVideo;
|
170
|
+
// Don't send a tracking event when seeking backwards
|
171
|
+
if (this._streamLatestTime[key] > this._streamStartTime[key] + MINIMUM_SEND_THRESHOLD) {
|
172
|
+
// Send a video streamed event any time the stream ends to capture the time between starting
|
173
|
+
// the video and the video stopping for any reason (pausing, deleting the embed node or closing the browser)
|
174
|
+
this._sendTrackingEvent('VIDEO_STREAMED', {
|
175
|
+
answerId: id,
|
176
|
+
streamStart: this._streamStartTime[key],
|
177
|
+
streamEnd: this._streamLatestTime[key]
|
178
|
+
});
|
179
|
+
}
|
180
|
+
|
181
|
+
// Make sure these events are only sent once by deleting the start and latest times
|
182
|
+
delete this._streamStartTime[key];
|
183
|
+
delete this._streamLatestTime[key];
|
184
|
+
}
|
185
|
+
};
|
186
|
+
|
157
187
|
private _handleVouchLoaded = ({ detail: vouchId }: CustomEvent<string>) => {
|
158
188
|
if (!vouchId) {
|
159
189
|
return;
|
@@ -161,143 +191,102 @@ class TrackingController implements ReactiveController {
|
|
161
191
|
|
162
192
|
// Only send loaded event once per session
|
163
193
|
if (!this._hasLoaded[vouchId]) {
|
164
|
-
this._sendTrackingEvent('VOUCH_LOADED', {
|
165
|
-
vouchId
|
166
|
-
});
|
194
|
+
this._sendTrackingEvent('VOUCH_LOADED', { vouchId });
|
167
195
|
this._hasLoaded[vouchId] = true;
|
168
196
|
}
|
169
197
|
};
|
170
198
|
|
171
199
|
private _handlePlay = () => {
|
172
|
-
const vouchId = this._findVouchId();
|
173
|
-
|
174
|
-
if (!vouchId) {
|
175
|
-
return;
|
176
|
-
}
|
177
|
-
|
178
200
|
// Only send the video played event once per session
|
179
201
|
if (!this._hasPlayed) {
|
180
202
|
this._sendTrackingEvent('VIDEO_PLAYED', {
|
181
|
-
vouchId,
|
182
203
|
streamStart: this.host.currentTime
|
183
204
|
});
|
184
205
|
this._hasPlayed = true;
|
185
206
|
}
|
186
207
|
};
|
187
208
|
|
188
|
-
private _handleVideoPlay = ({ detail: { id, node } }: CustomEvent<VideoEventDetail>) => {
|
189
|
-
const vouchId = this._findVouchId();
|
190
|
-
|
191
|
-
if (!vouchId) {
|
192
|
-
return;
|
193
|
-
}
|
194
|
-
|
209
|
+
private _handleVideoPlay = ({ detail: { id, key, node } }: CustomEvent<VideoEventDetail>) => {
|
195
210
|
// Only increment play count once per session
|
196
|
-
if (!this._answersViewed[
|
211
|
+
if (!this._answersViewed[key]) {
|
197
212
|
this._sendTrackingEvent('VOUCH_RESPONSE_VIEWED', {
|
198
|
-
vouchId,
|
199
213
|
answerId: id
|
200
214
|
});
|
201
|
-
this._answersViewed[
|
202
|
-
}
|
203
|
-
|
204
|
-
this._streamedTime[id] = node.currentTime;
|
205
|
-
this._streamLatestTime[id] = node.currentTime;
|
206
|
-
this._streamedPrevTimestamp[id] = Date.now();
|
207
|
-
};
|
208
|
-
|
209
|
-
private _handleVideoSeeking = ({ detail: { id } }: CustomEvent<VideoEventDetail>) => {
|
210
|
-
const vouchId = this._findVouchId();
|
211
|
-
|
212
|
-
if (!vouchId) {
|
213
|
-
return;
|
215
|
+
this._answersViewed[key] = true;
|
214
216
|
}
|
215
217
|
|
216
|
-
if (this.
|
217
|
-
this.
|
218
|
-
|
219
|
-
answerId: id,
|
220
|
-
streamStart: this._streamedTime[id],
|
221
|
-
streamEnd: this._streamLatestTime[id]
|
222
|
-
});
|
218
|
+
if (!this._streamStartTime[key]) {
|
219
|
+
this._streamStartTime[key] = node.currentTime;
|
220
|
+
this._streamLatestTime[key] = node.currentTime;
|
223
221
|
}
|
224
|
-
|
225
|
-
delete this._streamedTime[id];
|
226
|
-
delete this._streamLatestTime[id];
|
227
|
-
delete this._streamedPrevTimestamp[id];
|
228
222
|
};
|
229
223
|
|
230
|
-
private _handleVideoTimeUpdate = ({ detail: { id, node } }: CustomEvent<VideoEventDetail>) => {
|
231
|
-
const vouchId = this._findVouchId();
|
232
|
-
|
233
|
-
if (!vouchId) {
|
234
|
-
return;
|
235
|
-
}
|
236
|
-
|
237
|
-
const currentTimestamp = Date.now();
|
224
|
+
private _handleVideoTimeUpdate = ({ detail: { id, key, node } }: CustomEvent<VideoEventDetail>) => {
|
238
225
|
if (
|
239
|
-
|
240
|
-
!node.paused &&
|
226
|
+
// We only want to count any time that the video is actually playing
|
241
227
|
!this.host.paused &&
|
242
|
-
// Only
|
243
|
-
id === this.host.scene?.video?.id
|
244
|
-
// Throttle the frequency that we send streamed events while playing
|
245
|
-
currentTimestamp - this._streamedPrevTimestamp[id] > STREAMED_THROTTLE
|
228
|
+
// Only update the latest time if this event fires for the currently active video
|
229
|
+
id === this.host.scene?.video?.id
|
246
230
|
) {
|
231
|
+
this._currentlyPlayingVideo = { id, key, node };
|
232
|
+
this._streamLatestTime[key] = node.currentTime;
|
233
|
+
}
|
234
|
+
};
|
235
|
+
|
236
|
+
private _handleVideoPause = ({ detail: { id, key } }: CustomEvent<VideoEventDetail>) => {
|
237
|
+
if (this._streamLatestTime[key] > this._streamStartTime[key] + MINIMUM_SEND_THRESHOLD) {
|
247
238
|
this._sendTrackingEvent('VIDEO_STREAMED', {
|
248
|
-
vouchId,
|
249
239
|
answerId: id,
|
250
|
-
streamStart: this.
|
251
|
-
streamEnd:
|
240
|
+
streamStart: this._streamStartTime[key],
|
241
|
+
streamEnd: this._streamLatestTime[key]
|
252
242
|
});
|
253
|
-
this._streamedTime[id] = node.currentTime;
|
254
|
-
this._streamedPrevTimestamp[id] = currentTimestamp;
|
255
243
|
}
|
256
|
-
|
257
|
-
this._streamLatestTime[
|
244
|
+
delete this._streamStartTime[key];
|
245
|
+
delete this._streamLatestTime[key];
|
258
246
|
};
|
259
247
|
|
260
|
-
private
|
261
|
-
|
248
|
+
private _pageUnloading = () => {
|
249
|
+
this._streamEnded();
|
250
|
+
// This will try to send the same stream event again so we delete the start and latest
|
251
|
+
// time in stream ended so that there is no times to send and the pause event does nothing
|
252
|
+
this.host.pause();
|
253
|
+
};
|
262
254
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
// Don't send a tracking event if the video pauses when seeking backwards
|
268
|
-
if (node.currentTime > this._streamedTime[id]) {
|
269
|
-
// Send a video streamed event any time the video pauses then reset the streamed state
|
270
|
-
// We do this to capture the last bit of time that the video was played between the previous
|
271
|
-
// stream event and the video being paused manually or stopping because it ended
|
272
|
-
this._sendTrackingEvent('VIDEO_STREAMED', {
|
273
|
-
vouchId,
|
274
|
-
answerId: id,
|
275
|
-
streamStart: this._streamedTime[id],
|
276
|
-
streamEnd: node.currentTime
|
277
|
-
});
|
255
|
+
private _handleVisibilityChange = () => {
|
256
|
+
if (document.visibilityState === 'hidden') {
|
257
|
+
this._pageUnloading();
|
278
258
|
}
|
259
|
+
};
|
279
260
|
|
280
|
-
|
281
|
-
|
282
|
-
delete this._streamedPrevTimestamp[id];
|
261
|
+
private _handlePageHide = () => {
|
262
|
+
this._pageUnloading();
|
283
263
|
};
|
284
264
|
|
285
265
|
hostConnected() {
|
286
266
|
requestAnimationFrame(() => {
|
267
|
+
if ('onvisibilitychange' in document) {
|
268
|
+
document.addEventListener('visibilitychange', this._handleVisibilityChange);
|
269
|
+
} else {
|
270
|
+
window.addEventListener('pagehide', this._handlePageHide);
|
271
|
+
}
|
287
272
|
this.host.addEventListener('vouch:loaded', this._handleVouchLoaded);
|
288
273
|
this.host.mediaPlayer?.addEventListener('play', this._handlePlay);
|
289
274
|
this.host.mediaPlayer?.addEventListener('video:play', this._handleVideoPlay);
|
290
|
-
this.host.mediaPlayer?.addEventListener('video:seeking', this._handleVideoSeeking);
|
291
275
|
this.host.mediaPlayer?.addEventListener('video:pause', this._handleVideoPause);
|
292
276
|
this.host.mediaPlayer?.addEventListener('video:timeupdate', this._handleVideoTimeUpdate);
|
293
277
|
});
|
294
278
|
}
|
295
279
|
|
296
280
|
hostDisconnected() {
|
281
|
+
this._streamEnded();
|
282
|
+
if ('onvisibilitychange' in document) {
|
283
|
+
document.removeEventListener('visibilitychange', this._handleVisibilityChange);
|
284
|
+
} else {
|
285
|
+
window.removeEventListener('pagehide', this._handlePageHide);
|
286
|
+
}
|
297
287
|
this.host.removeEventListener('vouch:loaded', this._handleVouchLoaded);
|
298
288
|
this.host.mediaPlayer?.removeEventListener('play', this._handlePlay);
|
299
289
|
this.host.mediaPlayer?.removeEventListener('video:play', this._handleVideoPlay);
|
300
|
-
this.host.mediaPlayer?.removeEventListener('video:seeking', this._handleVideoSeeking);
|
301
290
|
this.host.mediaPlayer?.removeEventListener('video:pause', this._handleVideoPause);
|
302
291
|
this.host.mediaPlayer?.removeEventListener('video:timeupdate', this._handleVideoTimeUpdate);
|
303
292
|
}
|
@@ -1,9 +1,9 @@
|
|
1
|
-
import { html, LitElement } from 'lit';
|
1
|
+
import { css, html, LitElement } from 'lit';
|
2
2
|
import { customElement, property, state } from 'lit/decorators.js';
|
3
3
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
4
4
|
import { createRef, ref } from 'lit/directives/ref.js';
|
5
5
|
|
6
|
-
import type { Scene, TemplateInstance } from '@vouchfor/canvas-video';
|
6
|
+
import type { Scene, Scenes, TemplateInstance } from '@vouchfor/canvas-video';
|
7
7
|
import type { MediaPlayer, MediaPlayerProps } from '@vouchfor/media-player';
|
8
8
|
import type { Ref } from 'lit/directives/ref.js';
|
9
9
|
import type { Environment } from '~/utils/env';
|
@@ -21,20 +21,31 @@ type EmbedProps = Pick<MediaPlayerProps, 'data' | 'aspectRatio' | 'preload' | 'a
|
|
21
21
|
trackingSource?: string;
|
22
22
|
vouchId?: string;
|
23
23
|
templateId?: string;
|
24
|
+
// Index of the questions to include starting from 1
|
25
|
+
questions?: number[];
|
24
26
|
};
|
25
27
|
|
26
28
|
@customElement('vouch-embed')
|
27
29
|
class Embed extends LitElement {
|
30
|
+
static styles = [
|
31
|
+
css`
|
32
|
+
:host {
|
33
|
+
display: flex;
|
34
|
+
}
|
35
|
+
`
|
36
|
+
];
|
37
|
+
|
28
38
|
private _mediaPlayerRef: Ref<MediaPlayer> = createRef();
|
29
39
|
|
30
|
-
@property({ type: Object
|
40
|
+
@property({ type: Object }) data: EmbedProps['data'];
|
31
41
|
@property({ type: String }) vouchId: EmbedProps['vouchId'];
|
32
42
|
@property({ type: String }) templateId: EmbedProps['templateId'];
|
43
|
+
@property({ type: Array }) questions: EmbedProps['questions'];
|
33
44
|
|
34
45
|
@property({ type: String }) env: EmbedProps['env'] = 'prod';
|
35
46
|
@property({ type: String }) apiKey: EmbedProps['apiKey'] = '';
|
36
47
|
@property({ type: Boolean }) disableTracking: EmbedProps['disableTracking'] = false;
|
37
|
-
@property({ type: String }) trackingSource: EmbedProps['trackingSource'] = '
|
48
|
+
@property({ type: String }) trackingSource: EmbedProps['trackingSource'] = 'embedded_player';
|
38
49
|
|
39
50
|
@property({ type: Array }) controls: EmbedProps['controls'];
|
40
51
|
@property({ type: String }) preload: EmbedProps['preload'] = 'auto';
|
@@ -149,6 +160,10 @@ class Embed extends LitElement {
|
|
149
160
|
return this._mediaPlayerRef.value?.scenes ?? [];
|
150
161
|
}
|
151
162
|
|
163
|
+
get sceneConfig(): Scenes | null {
|
164
|
+
return this._mediaPlayerRef.value?.sceneConfig ?? null;
|
165
|
+
}
|
166
|
+
|
152
167
|
get videoState() {
|
153
168
|
return this._mediaPlayerRef.value?.videoState;
|
154
169
|
}
|
@@ -171,7 +186,7 @@ class Embed extends LitElement {
|
|
171
186
|
|
172
187
|
render() {
|
173
188
|
return html`
|
174
|
-
<vmp-
|
189
|
+
<vmp-media-player
|
175
190
|
${ref(this._mediaPlayerRef)}
|
176
191
|
${this.eventController.register()}
|
177
192
|
?autoplay=${this.autoplay}
|
@@ -181,7 +196,7 @@ class Embed extends LitElement {
|
|
181
196
|
aspectRatio=${ifDefined(this.aspectRatio)}
|
182
197
|
preload=${ifDefined(this.preload)}
|
183
198
|
.controls=${this.controls}
|
184
|
-
></vmp-
|
199
|
+
></vmp-media-player>
|
185
200
|
`;
|
186
201
|
}
|
187
202
|
}
|
File without changes
|
File without changes
|
File without changes
|