diff options
Diffstat (limited to 'src/js/plugins/vimeo.js')
-rw-r--r-- | src/js/plugins/vimeo.js | 161 |
1 files changed, 106 insertions, 55 deletions
diff --git a/src/js/plugins/vimeo.js b/src/js/plugins/vimeo.js index 46d4f3f9..2d9ba6e2 100644 --- a/src/js/plugins/vimeo.js +++ b/src/js/plugins/vimeo.js @@ -2,31 +2,60 @@ // Vimeo plugin // ========================================================================== -import captions from './../captions'; -import controls from './../controls'; -import ui from './../ui'; -import utils from './../utils'; +import captions from '../captions'; +import controls from '../controls'; +import ui from '../ui'; +import { createElement, replaceElement, toggleClass } from '../utils/elements'; +import { triggerEvent } from '../utils/events'; +import fetch from '../utils/fetch'; +import is from '../utils/is'; +import loadScript from '../utils/loadScript'; +import { format, stripHTML } from '../utils/strings'; +import { buildUrlParams } from '../utils/urls'; + +// Parse Vimeo ID from URL +function parseId(url) { + if (is.empty(url)) { + return null; + } + + if (is.number(Number(url))) { + return url; + } + + const regex = /^.*(vimeo.com\/|video\/)(\d+).*/; + return url.match(regex) ? RegExp.$2 : url; +} + +// Get aspect ratio for dimensions +function getAspectRatio(width, height) { + const getRatio = (w, h) => (h === 0 ? w : getRatio(h, w % h)); + const ratio = getRatio(width, height); + return `${width / ratio}:${height / ratio}`; +} // Set playback state and trigger change (only on actual change) function assurePlaybackState(play) { + if (play && !this.embed.hasPlayed) { + this.embed.hasPlayed = true; + } if (this.media.paused === play) { this.media.paused = !play; - utils.dispatchEvent.call(this, this.media, play ? 'play' : 'pause'); + triggerEvent.call(this, this.media, play ? 'play' : 'pause'); } } const vimeo = { setup() { // Add embed class for responsive - utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true); + toggleClass(this.elements.wrapper, this.config.classNames.embed, true); // Set intial ratio vimeo.setAspectRatio.call(this); // Load the API if not already - if (!utils.is.object(window.Vimeo)) { - utils - .loadScript(this.config.urls.vimeo.sdk) + if (!is.object(window.Vimeo)) { + loadScript(this.config.urls.vimeo.sdk) .then(() => { vimeo.ready.call(this); }) @@ -41,8 +70,9 @@ const vimeo = { // Set aspect ratio // For Vimeo we have an extra 300% height <div> to hide the standard controls and UI setAspectRatio(input) { - const ratio = utils.is.string(input) ? input.split(':') : this.config.ratio.split(':'); - const padding = 100 / ratio[0] * ratio[1]; + const [x, y] = (is.string(input) ? input : this.config.ratio).split(':').map(Number); + const padding = (100 / x) * y; + vimeo.padding = padding; this.elements.wrapper.style.paddingBottom = `${padding}%`; if (this.supported.ui) { @@ -70,34 +100,37 @@ const vimeo = { gesture: 'media', playsinline: !this.config.fullscreen.iosNative, }; - const params = utils.buildUrlParams(options); + const params = buildUrlParams(options); // Get the source URL or ID let source = player.media.getAttribute('src'); // Get from <div> if needed - if (utils.is.empty(source)) { + if (is.empty(source)) { source = player.media.getAttribute(player.config.attributes.embed.id); } - const id = utils.parseVimeoId(source); + const id = parseId(source); // Build an iframe - const iframe = utils.createElement('iframe'); - const src = utils.format(player.config.urls.vimeo.iframe, id, params); + const iframe = createElement('iframe'); + const src = format(player.config.urls.vimeo.iframe, id, params); iframe.setAttribute('src', src); iframe.setAttribute('allowfullscreen', ''); iframe.setAttribute('allowtransparency', ''); iframe.setAttribute('allow', 'autoplay'); + // Get poster, if already set + const { poster } = player; + // Inject the package - const wrapper = utils.createElement('div', { class: player.config.classNames.embedContainer }); + const wrapper = createElement('div', { poster, class: player.config.classNames.embedContainer }); wrapper.appendChild(iframe); - player.media = utils.replaceElement(wrapper, player.media); + player.media = replaceElement(wrapper, player.media); // Get poster image - utils.fetch(utils.format(player.config.urls.vimeo.api, id), 'json').then(response => { - if (utils.is.empty(response)) { + fetch(format(player.config.urls.vimeo.api, id), 'json').then(response => { + if (is.empty(response)) { return; } @@ -108,7 +141,7 @@ const vimeo = { url.pathname = `${url.pathname.split('_')[0]}.jpg`; // Set and show poster - ui.setPoster.call(player, url.href); + ui.setPoster.call(player, url.href).catch(() => {}); }); // Setup instance @@ -153,19 +186,20 @@ const vimeo = { // Get current paused state and volume etc const { embed, media, paused, volume } = player; + const restorePause = paused && !embed.hasPlayed; // Set seeking state and trigger event media.seeking = true; - utils.dispatchEvent.call(player, media, 'seeking'); + triggerEvent.call(player, media, 'seeking'); // If paused, mute until seek is complete - Promise.resolve(paused && embed.setVolume(0)) + Promise.resolve(restorePause && embed.setVolume(0)) // Seek .then(() => embed.setCurrentTime(time)) // Restore paused - .then(() => paused && embed.pause()) + .then(() => restorePause && embed.pause()) // Restore volume - .then(() => paused && embed.setVolume(volume)) + .then(() => restorePause && embed.setVolume(volume)) .catch(() => { // Do nothing }); @@ -183,7 +217,7 @@ const vimeo = { .setPlaybackRate(input) .then(() => { speed = input; - utils.dispatchEvent.call(player, player.media, 'ratechange'); + triggerEvent.call(player, player.media, 'ratechange'); }) .catch(error => { // Hide menu item (and menu if empty) @@ -203,7 +237,7 @@ const vimeo = { set(input) { player.embed.setVolume(input).then(() => { volume = input; - utils.dispatchEvent.call(player, player.media, 'volumechange'); + triggerEvent.call(player, player.media, 'volumechange'); }); }, }); @@ -215,11 +249,11 @@ const vimeo = { return muted; }, set(input) { - const toggle = utils.is.boolean(input) ? input : false; + const toggle = is.boolean(input) ? input : false; player.embed.setVolume(toggle ? 0 : player.config.volume).then(() => { muted = toggle; - utils.dispatchEvent.call(player, player.media, 'volumechange'); + triggerEvent.call(player, player.media, 'volumechange'); }); }, }); @@ -231,7 +265,7 @@ const vimeo = { return loop; }, set(input) { - const toggle = utils.is.boolean(input) ? input : player.config.loop.active; + const toggle = is.boolean(input) ? input : player.config.loop.active; player.embed.setLoop(toggle).then(() => { loop = toggle; @@ -245,6 +279,7 @@ const vimeo = { .getVideoUrl() .then(value => { currentSrc = value; + controls.setDownloadLink.call(player); }) .catch(error => { this.debug.warn(error); @@ -264,12 +299,9 @@ const vimeo = { }); // Set aspect ratio based on video size - Promise.all([ - player.embed.getVideoWidth(), - player.embed.getVideoHeight(), - ]).then(dimensions => { - const ratio = utils.getAspectRatio(dimensions[0], dimensions[1]); - vimeo.setAspectRatio.call(this, ratio); + Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then(dimensions => { + vimeo.ratio = getAspectRatio(dimensions[0], dimensions[1]); + vimeo.setAspectRatio.call(this, vimeo.ratio); }); // Set autopause @@ -286,13 +318,13 @@ const vimeo = { // Get current time player.embed.getCurrentTime().then(value => { currentTime = value; - utils.dispatchEvent.call(player, player.media, 'timeupdate'); + triggerEvent.call(player, player.media, 'timeupdate'); }); // Get duration player.embed.getDuration().then(value => { player.media.duration = value; - utils.dispatchEvent.call(player, player.media, 'durationchange'); + triggerEvent.call(player, player.media, 'durationchange'); }); // Get captions @@ -301,18 +333,21 @@ const vimeo = { captions.setup.call(player); }); - player.embed.on('cuechange', data => { - let cue = null; - - if (data.cues.length) { - cue = utils.stripHTML(data.cues[0].text); - } - - captions.setText.call(player, cue); + player.embed.on('cuechange', ({ cues = [] }) => { + const strippedCues = cues.map(cue => stripHTML(cue.text)); + captions.updateCues.call(player, strippedCues); }); player.embed.on('loaded', () => { - if (utils.is.element(player.embed.element) && player.supported.ui) { + // Assure state and events are updated on autoplay + player.embed.getPaused().then(paused => { + assurePlaybackState.call(player, !paused); + if (!paused) { + triggerEvent.call(player, player.media, 'playing'); + } + }); + + if (is.element(player.embed.element) && player.supported.ui) { const frame = player.embed.element; // Fix keyboard focus issues @@ -323,7 +358,7 @@ const vimeo = { player.embed.on('play', () => { assurePlaybackState.call(player, true); - utils.dispatchEvent.call(player, player.media, 'playing'); + triggerEvent.call(player, player.media, 'playing'); }); player.embed.on('pause', () => { @@ -333,16 +368,16 @@ const vimeo = { player.embed.on('timeupdate', data => { player.media.seeking = false; currentTime = data.seconds; - utils.dispatchEvent.call(player, player.media, 'timeupdate'); + triggerEvent.call(player, player.media, 'timeupdate'); }); player.embed.on('progress', data => { player.media.buffered = data.percent; - utils.dispatchEvent.call(player, player.media, 'progress'); + triggerEvent.call(player, player.media, 'progress'); // Check all loaded if (parseInt(data.percent, 10) === 1) { - utils.dispatchEvent.call(player, player.media, 'canplaythrough'); + triggerEvent.call(player, player.media, 'canplaythrough'); } // Get duration as if we do it before load, it gives an incorrect value @@ -350,24 +385,40 @@ const vimeo = { player.embed.getDuration().then(value => { if (value !== player.media.duration) { player.media.duration = value; - utils.dispatchEvent.call(player, player.media, 'durationchange'); + triggerEvent.call(player, player.media, 'durationchange'); } }); }); player.embed.on('seeked', () => { player.media.seeking = false; - utils.dispatchEvent.call(player, player.media, 'seeked'); + triggerEvent.call(player, player.media, 'seeked'); }); player.embed.on('ended', () => { player.media.paused = true; - utils.dispatchEvent.call(player, player.media, 'ended'); + triggerEvent.call(player, player.media, 'ended'); }); player.embed.on('error', detail => { player.media.error = detail; - utils.dispatchEvent.call(player, player.media, 'error'); + triggerEvent.call(player, player.media, 'error'); + }); + + // Set height/width on fullscreen + player.on('enterfullscreen exitfullscreen', event => { + const { target } = player.fullscreen; + + // Ignore for iOS native + if (target !== player.elements.container) { + return; + } + + const toggle = event.type === 'enterfullscreen'; + const [x, y] = vimeo.ratio.split(':').map(Number); + const dimension = x > y ? 'width' : 'height'; + + target.style[dimension] = toggle ? `${vimeo.padding}%` : null; }); // Rebuild UI |