From c9ad5306eadec615bd02c8df5991edb41db6959d Mon Sep 17 00:00:00 2001 From: Antonio Laguna Date: Mon, 20 Mar 2017 07:57:49 +0100 Subject: [PATCH] Youtube first punch Defeated by postMessage --- demos/keynote.html | 4 +- src/js/modules/webslides.js | 5 +- src/js/plugins/plugins.js | 4 +- src/js/plugins/youtube.js | 149 ++++++++++++++++++++++++++++++++++++ 4 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 src/js/plugins/youtube.js diff --git a/demos/keynote.html b/demos/keynote.html index 0837a2e..36f515f 100644 --- a/demos/keynote.html +++ b/demos/keynote.html @@ -748,7 +748,7 @@
- +
@@ -759,7 +759,7 @@
- +
diff --git a/src/js/modules/webslides.js b/src/js/modules/webslides.js index 78fdcdb..24b6cf8 100644 --- a/src/js/modules/webslides.js +++ b/src/js/modules/webslides.js @@ -18,7 +18,8 @@ const PLUGINS = { 'nav': Plugins.Navigation, 'scroll': Plugins.Scroll, 'touch': Plugins.Touch, - 'video': Plugins.Video + 'video': Plugins.Video, + 'youtube': Plugins.YouTube }; @@ -29,7 +30,7 @@ export default class WebSlides { /** * Options for WebSlides * @param {number|boolean} autoslide If a number is provided, it will allow - * autosliding by said amount of miliseconds. + * autosliding by said amount of milliseconds. * @param {boolean} changeOnClick If true, it will allow * clicking on any place to change the slide. * @param {boolean} loop Whether to go to first slide from last one or not. diff --git a/src/js/plugins/plugins.js b/src/js/plugins/plugins.js index 3589c6c..0f8a234 100644 --- a/src/js/plugins/plugins.js +++ b/src/js/plugins/plugins.js @@ -7,6 +7,7 @@ import Navigation from './navigation'; import Scroll from './scroll'; import Touch from './touch'; import Video from './video'; +import YouTube from './youtube'; export default { AutoSlide, @@ -17,5 +18,6 @@ export default { Navigation, Scroll, Touch, - Video + Video, + YouTube }; diff --git a/src/js/plugins/youtube.js b/src/js/plugins/youtube.js new file mode 100644 index 0000000..b6aff60 --- /dev/null +++ b/src/js/plugins/youtube.js @@ -0,0 +1,149 @@ +/* global YT */ + +import DOM from '../utils/dom'; +import Slide from '../modules/slide'; + +/** + * Player wrapper around the YT player. This is mostly to get around the event + * in which we need to play a video which player isn't ready yet. + */ +class Player { + /** + * @param {Element} el + */ + constructor(el) { + this.ready = false; + this.onReadyC = null; + this.slide = Slide.getSectionFromEl(el).section; + + const playerVars = this.getPlayerVars(el); + + this.player = new YT.Player(el, { + videoId: el.dataset.youtubeId, + playerVars, + events: { + onReady: () => { + this.ready = true; + + if (this.onReadyC) { + this.onReadyC(); + this.onReadyC = null; + } + } + } + }); + this.el = this.player.getIframe(); + } + + /** + * + */ + play() { + if (this.ready) { + this.player.playVideo(); + } else { + this.onReadyC = this.play; + } + } + + /** + * + */ + pause() { + this.player.pauseVideo(); + } + + /** + * Get player vars by element. + * @return {{modestbranding: number}} + */ + getPlayerVars() { + const vars = { + modestbranding: 1, + rel: 0, + origin: window.location.origin + }; + + if (this.slide.classList.contains('fullscreen')) { + // Disabling keyboard interaction for fullscreenvideos + vars.disablekb = 1; + vars.showinfo = 0; + } + + return vars; + } +} + +/** + * Video plugin. + */ +export default class YouTube { + /** + * Grid plugin that shows a grid on top of the WebSlides for easy prototyping. + * @param {WebSlides} wsInstance The WebSlides instance + */ + constructor(wsInstance) { + /** + * @type {WebSlides} + * @private + */ + this.ws_ = wsInstance; + + this.videos = DOM.toArray(this.ws_.el.querySelectorAll('[data-youtube')); + + if (this.videos.length) { + this.inject(); + } + } + + /** + * Once the YouTube API is ready this gets called so we can start the videos. + */ + onYTReady() { + this.videos.forEach(video => { + const player = new Player(video); + + if (typeof video.dataset.autoplay !== 'undefined') { + const {i} = Slide.getSectionFromEl(player.el); + const slide = this.ws_.slides[i - 1]; + + slide.player = player; + slide.onEnable(YouTube.onSectionEnabled); + slide.onDisable(YouTube.onSectionDisabled); + + if (this.ws_.currentSlide_ === slide) { + YouTube.onSectionEnabled(slide); + } + } + }); + } + + /** + * Injects the YouTube iFrame API into the page. + */ + inject() { + window.onYouTubeIframeAPIReady = this.onYTReady.bind(this); + const tag = document.createElement('script'); + tag.src = `https://www.youtube.com/iframe_api`; + const firstScriptTag = document.getElementsByTagName('script')[0]; + firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); + } + + /** + * On Section enable hook. Will play the video. + * @param {Slide} slide + */ + static onSectionEnabled(slide) { + console.log('enabling', slide); // eslint-disable-line no-console + slide.player.play(); + } + + /** + * On Section enable hook. Will pause the video. + * @param {Slide} slide + */ + static onSectionDisabled(slide) { + console.log('disabling', slide); // eslint-disable-line no-console + slide.player.pause(); + } +}