Skip to content

Commit 57e6f8d

Browse files
committed
Enhance amp-slikeplayer with event handling and iframe source improvements
- Added event listeners for 'cplPlayerReady', 'cplVideoTimeUpdate', and 'cplAdProgress' in the Slike Player example. - Refactored amp-slikeplayer.js to streamline iframe source building and improve message handling. - Introduced methods for validating messages and parsing viewport thresholds for better performance and reliability.
1 parent 964c93c commit 57e6f8d

2 files changed

Lines changed: 145 additions & 98 deletions

File tree

examples/slikeplayer.amp.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,5 +457,16 @@ <h3>🎉 Demo Complete!</h3>
457457
</div>
458458
</div>
459459
</div>
460+
461+
<script>
462+
events = ['cplPlayerReady', 'cplVideoTimeUpdate', 'cplAdProgress'];
463+
events.forEach((event) => {
464+
document
465+
.getElementById('main-player')
466+
.addEventListener(event, (details) => {
467+
console.log(event, details.data);
468+
});
469+
});
470+
</script>
460471
</body>
461472
</html>

extensions/amp-slikeplayer/0.1/amp-slikeplayer.js

Lines changed: 134 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import {
1616
createFrameFor,
1717
isJsonOrObj,
1818
objOrParseJson,
19-
redispatch,
2019
} from '../../../src/iframe-video';
2120
import {VideoEvents_Enum} from '../../../src/video-interface';
2221

@@ -27,30 +26,10 @@ const TAG = 'amp-slikeplayer';
2726
*/
2827

2928
/**
30-
@enum {string}
29+
* @enum {string}
3130
* @private
3231
*/
3332

34-
const CleoEvent = {
35-
'ready': VideoEvents_Enum.LOAD,
36-
'play': VideoEvents_Enum.PLAYING,
37-
'pause': VideoEvents_Enum.PAUSE,
38-
'complete': VideoEvents_Enum.ENDED,
39-
'visible': VideoEvents_Enum.VISIBILITY,
40-
'seeked': VideoEvents_Enum.SEEKED,
41-
'seeking': VideoEvents_Enum.SEEKING,
42-
'adStart': VideoEvents_Enum.AD_START,
43-
'adEnd': VideoEvents_Enum.AD_END,
44-
'adPlay': VideoEvents_Enum.AD_PLAY,
45-
'adPause': VideoEvents_Enum.AD_PAUSE,
46-
'adSkip': VideoEvents_Enum.AD_SKIP,
47-
'adComplete': VideoEvents_Enum.AD_END,
48-
'adError': VideoEvents_Enum.AD_ERROR,
49-
'adLoaded': VideoEvents_Enum.AD_LOADED,
50-
'adImpression': VideoEvents_Enum.AD_IMPRESSION,
51-
'adClick': VideoEvents_Enum.AD_CLICK,
52-
};
53-
5433
export class AmpSlikeplayer extends AMP.BaseElement {
5534
/** @param {!AmpElement} element */
5635
constructor(element) {
@@ -78,7 +57,7 @@ export class AmpSlikeplayer extends AMP.BaseElement {
7857
this.onReadyOnce_ = once((detail) => this.onReady_(detail));
7958

8059
/** @private {string} */
81-
this.config_ = null;
60+
this.config_ = '';
8261

8362
/** @private {string} */
8463
this.poster_ = '';
@@ -100,6 +79,9 @@ export class AmpSlikeplayer extends AMP.BaseElement {
10079

10180
/** @private {number} 0..1 */
10281
this.viewportVisibleThreshold_ = 0;
82+
83+
/** @private {string} */
84+
this.targetOrigin_ = '*';
10385
}
10486

10587
/** @override */
@@ -127,25 +109,7 @@ export class AmpSlikeplayer extends AMP.BaseElement {
127109
this.poster_ = element.getAttribute('poster') || '';
128110

129111
// Read optional viewport visibility threshold from data-config
130-
if (this.config_) {
131-
try {
132-
const params = new URLSearchParams(this.config_);
133-
if (params.has('viewport')) {
134-
let threshold = parseFloat(
135-
/** @type {string} */ (params.get('viewport'))
136-
);
137-
if (isFinite(threshold)) {
138-
if (threshold > 1) {
139-
threshold = threshold / 100; // percent -> ratio
140-
}
141-
this.viewportVisibleThreshold_ = Math.max(
142-
0,
143-
Math.min(1, threshold)
144-
);
145-
}
146-
}
147-
} catch {}
148-
}
112+
this.parseViewportThreshold_();
149113

150114
installVideoManagerForDoc(element);
151115
const videoManager = Services.videoManagerForDoc(element);
@@ -180,11 +144,7 @@ export class AmpSlikeplayer extends AMP.BaseElement {
180144

181145
/** @override */
182146
layoutCallback() {
183-
let src = `${this.baseUrl_}#apikey=${this.apikey_}&videoid=${this.videoid_}&baseurl=${this.win.location.origin}`;
184-
185-
if (this.config_) {
186-
src = `${this.baseUrl_}#apikey=${this.apikey_}&videoid=${this.videoid_}&${this.config_}&baseurl=${this.win.location.origin}`;
187-
}
147+
const src = this.buildIframeSrc_();
188148

189149
const frame = disableScrollingOnIframe(
190150
createFrameFor(this, src, this.element.id)
@@ -252,11 +212,7 @@ export class AmpSlikeplayer extends AMP.BaseElement {
252212
* @private
253213
*/
254214
onMessage_(messageEvent) {
255-
if (
256-
!this.iframe_ ||
257-
!messageEvent ||
258-
messageEvent.source != this.iframe_.contentWindow
259-
) {
215+
if (!this.isValidMessage_(messageEvent)) {
260216
return;
261217
}
262218

@@ -268,52 +224,14 @@ export class AmpSlikeplayer extends AMP.BaseElement {
268224
const data = objOrParseJson(messageData);
269225
const event = data['event'];
270226
const detail = data['detail'];
227+
271228
if (event === 'ready') {
272229
detail && this.onReadyOnce_(detail);
273230
return;
274231
}
275232
const {element} = this;
276-
if (redispatch(element, event, CleoEvent)) {
277-
return;
278-
}
279-
if (detail && event) {
280-
switch (event) {
281-
case 'fullscreen':
282-
break;
283-
case 'meta':
284-
break;
285-
case 'mute':
286-
break;
287-
case 'playedRanges':
288-
break;
289-
case 'time':
290-
const {currentTime} = detail;
291-
this.currentTime_ = currentTime;
292-
break;
293-
case 'adTime':
294-
const {position} = detail;
295-
this.currentTime_ = position;
296-
break;
297-
case 'seeked':
298-
case 'seeking':
299-
// Seek events are handled by the redispatch above
300-
break;
301-
case 'adStart':
302-
case 'adEnd':
303-
case 'adPlay':
304-
case 'adPause':
305-
case 'adSkip':
306-
case 'adComplete':
307-
case 'adError':
308-
case 'adLoaded':
309-
case 'adImpression':
310-
case 'adClick':
311-
// Ad events are handled by the redispatch above
312-
break;
313-
default:
314-
break;
315-
}
316-
}
233+
this.handleEventDetail_(event, detail);
234+
dispatchCustomEvent(element, event, detail);
317235
}
318236
/**
319237
* @override
@@ -364,13 +282,12 @@ export class AmpSlikeplayer extends AMP.BaseElement {
364282

365283
/** @override */
366284
getCurrentTime() {
367-
// Not supported.
368-
return this.currentTime_ || 0;
285+
return this.currentTime_;
369286
}
370287

371288
/** @override */
372289
getDuration() {
373-
return this.duration_ || 1;
290+
return this.duration_;
374291
}
375292

376293
/** @override */
@@ -384,7 +301,7 @@ export class AmpSlikeplayer extends AMP.BaseElement {
384301
}
385302
/**
386303
* @param {string} method
387-
* @param {string} [optParams]
304+
* @param {*} [optParams]
388305
* @private
389306
*/
390307
postMessage_(method, optParams) {
@@ -397,7 +314,7 @@ export class AmpSlikeplayer extends AMP.BaseElement {
397314
'method': method,
398315
'optParams': optParams,
399316
}),
400-
'*'
317+
this.targetOrigin_
401318
);
402319
});
403320
}
@@ -423,6 +340,125 @@ export class AmpSlikeplayer extends AMP.BaseElement {
423340
pauseCallback() {
424341
this.pause();
425342
}
343+
344+
/**
345+
* @private
346+
* @return {string}
347+
*/
348+
buildIframeSrc_() {
349+
this.setTargetOrigin_();
350+
351+
const params = this.buildUrlParams_();
352+
return `${this.baseUrl_}#${params.join('&')}`;
353+
}
354+
355+
/**
356+
* @private
357+
*/
358+
setTargetOrigin_() {
359+
try {
360+
const url = new URL(this.baseUrl_);
361+
this.targetOrigin_ = url.origin;
362+
} catch {
363+
// Keep default target origin
364+
}
365+
}
366+
367+
/**
368+
* @private
369+
* @return {!Array<string>}
370+
*/
371+
buildUrlParams_() {
372+
const params = [
373+
`apikey=${encodeURIComponent(this.apikey_)}`,
374+
`videoid=${encodeURIComponent(this.videoid_)}`,
375+
];
376+
377+
const extra = this.normalizeConfig_();
378+
if (extra) {
379+
params.push(extra);
380+
}
381+
382+
const origin = this.win.location?.origin;
383+
if (origin) {
384+
params.push(`baseurl=${encodeURIComponent(origin)}`);
385+
}
386+
387+
return params;
388+
}
389+
390+
/**
391+
* @private
392+
* @return {string}
393+
*/
394+
normalizeConfig_() {
395+
return (this.config_ || '').trim().replace(/^[#?&]+/, '');
396+
}
397+
398+
/**
399+
* @private
400+
*/
401+
parseViewportThreshold_() {
402+
if (!this.config_) {
403+
return;
404+
}
405+
406+
try {
407+
const params = new URLSearchParams(this.config_);
408+
if (!params.has('viewport')) {
409+
return;
410+
}
411+
412+
let threshold = parseFloat(params.get('viewport'));
413+
if (!isFinite(threshold)) {
414+
return;
415+
}
416+
417+
// Convert percentage to ratio if needed
418+
if (threshold > 1) {
419+
threshold = threshold / 100;
420+
}
421+
422+
this.viewportVisibleThreshold_ = Math.max(0, Math.min(1, threshold));
423+
} catch {
424+
// Ignore parsing errors
425+
}
426+
}
427+
428+
/**
429+
* @private
430+
* @param {*} messageEvent
431+
* @return {boolean}
432+
*/
433+
isValidMessage_(messageEvent) {
434+
return !!(
435+
this.iframe_ &&
436+
messageEvent &&
437+
messageEvent.source === this.iframe_.contentWindow
438+
);
439+
}
440+
441+
/**
442+
* @private
443+
* @param {string} event
444+
* @param {*} detail
445+
*/
446+
handleEventDetail_(event, detail) {
447+
if (!detail || !event) {
448+
return;
449+
}
450+
451+
switch (event) {
452+
case 'cplVideoTimeUpdate':
453+
this.currentTime_ = detail.currentTime || 0;
454+
break;
455+
case 'cplAdProgress':
456+
this.currentTime_ = detail.position || 0;
457+
break;
458+
default:
459+
break;
460+
}
461+
}
426462
}
427463

428464
AMP.extension(TAG, '0.1', (AMP) => {

0 commit comments

Comments
 (0)