From: Vincent Vanwaelscappel Date: Fri, 23 Jun 2023 12:05:53 +0000 (+0200) Subject: wait #6015 @2 X-Git-Url: http://git.cubedesigners.com/?a=commitdiff_plain;h=ec2522fc68ffb11854696ce1883b62fd8f8667fb;p=fluidbook-html5.git wait #6015 @2 --- diff --git a/js/libs/fluidbook/fluidbook.menu.js b/js/libs/fluidbook/fluidbook.menu.js index 9b9c1e60..bd2a2a47 100644 --- a/js/libs/fluidbook/fluidbook.menu.js +++ b/js/libs/fluidbook/fluidbook.menu.js @@ -337,7 +337,6 @@ FluidbookMenu.prototype = { view += ''; this.viewWrap(view, 'video', '', '', false, hash); - this.fluidbook.stats.track(11); this.fluidbook.initVideos(); var $this = this; var times = [250, 500, 750, 1000, 1250]; @@ -370,9 +369,6 @@ FluidbookMenu.prototype = { view += ''; this.viewWrap(view, 'slideshow', '', '', false, hash); - // TODO: check which type should be passed to fluidbook.stats.track() ??? - // this.fluidbook.stats.track(11); - this.fluidbook.slideshow.initPopupSlideshow($(".fb-slideshow").eq(0)); // var $this = this; @@ -408,7 +404,6 @@ FluidbookMenu.prototype = { view += markup; view += ''; this.viewWrap(view, 'audio', '', '', false, hash); - this.fluidbook.stats.track(11); var $this = this; var times = [250, 500, 750, 1000, 1250]; $.each(times, function (k, v) { @@ -431,7 +426,6 @@ FluidbookMenu.prototype = { view += ''; this.viewWrap(view, 'webvideo', '', '', false, hash); this.fluidbook.initVideos(); - this.fluidbook.stats.track(11); if (callback != undefined) { callback(); diff --git a/js/libs/fluidbook/fluidbook.stats.js b/js/libs/fluidbook/fluidbook.stats.js index 5221580d..a81077f3 100644 --- a/js/libs/fluidbook/fluidbook.stats.js +++ b/js/libs/fluidbook/fluidbook.stats.js @@ -285,9 +285,6 @@ FluidbookStats.prototype = { case 2:// Zoom window._paq.push(['trackEvent', 'zoom', 'page', page]); break; - case 11:// Video - window._paq.push(['trackEvent', 'video', 'view', extra]); - break; case 15:// window._paq.push(['trackEvent', 'cart', 'addproduct', extra]); } @@ -349,14 +346,29 @@ FluidbookStats.prototype = { case 2:// Zoom this._ga('event', 'zoom', 'page', page); break; - case 11:// Video - this._ga('event', 'video', 'view', extra); - break; case 15:// this._ga('event', 'cart', 'addproduct', extra); } }, + trackEvent: function (category, action, name) { + if (!this.fluidbook.support.hasNetwork() || this.fluidbook.nointerface) { + return; + } + if (this.fluidbook.settings.statsMatomo) { + try { + window._paq.push(['trackEvent', category, action, name + '|:|' + this.fluidbook.currentPage]); + } catch (e) { + + } + } + try { + this._ga('event', category, action, name); + } catch (e) { + + } + }, + _ga: function (a0, a1, a2, a3, a4) { var args = Array.prototype.slice.call(arguments); if (this.ga === 'gtm') { @@ -412,8 +424,6 @@ FluidbookStats.prototype = { } var $this = this; - - var data = { id: $this.id, vid: $this.vid, type: type, page: page, str: extra, time: new Date().getTime() }; diff --git a/js/libs/fluidbook/fluidbook.video.js b/js/libs/fluidbook/fluidbook.video.js index 9a1a011f..ed511d02 100644 --- a/js/libs/fluidbook/fluidbook.video.js +++ b/js/libs/fluidbook/fluidbook.video.js @@ -108,6 +108,8 @@ FluidbookVideo.prototype = { sound = parseInt($(e).data('sound')) == 1, autoplay = parseInt($(e).data('autoplay')) == 1, nativeAutoplay = !autoplay && parseInt($(e).data('nativeautoplay')) == 1, + statsName = $(e).data('stats-name'), + statsType = $(e).data('stats-type'), setup = $(e).data('setup'), linkid = $(e).data('link-id'), url = $(e).data('url'), @@ -117,7 +119,7 @@ FluidbookVideo.prototype = { player; var hidelinksonplay = $(e).data('hidelinksonplay') == undefined || $(e).data('hidelinksonplay') === '' ? [] : $(e).data('hidelinksonplay').split(','); - //console.log('Initialising video ID: ' + id); + // console.log('Initialising video ID: ' + id, statsType, statsName); // Player might be active but not visible so we need to dispose of it before re-initialising the element if (videojs.players[id]) { @@ -212,11 +214,22 @@ FluidbookVideo.prototype = { $(e).html(html); + let playEventSent = false; + + function sendPlayEvent() { + if (!playEventSent) { + $this.fluidbook.stats.trackEvent(statsType, 'play', statsName); + playEventSent = true; + } + } player = videojs(id, setup); player.ready(function () { //console.log(id + ' player is ready'); + + $this.fluidbook.stats.trackEvent(statsType, 'show', statsName); + $this.resizeControls(); // Make sure player controls are the right size if (autoplay) { @@ -224,10 +237,12 @@ FluidbookVideo.prototype = { if (promise !== undefined) { promise.then(function () { - console.log('autoplay ok'); + sendPlayEvent(); // Autoplay started! }).catch(function (error) { - console.log('autoplay nok'); + player.one('play', function () { + sendPlayEvent(); + }); // Autoplay was prevented. }); } else { @@ -238,7 +253,6 @@ FluidbookVideo.prototype = { if (fluidbook.video.players[id]) { //console.log('found saved settings for player ID ' + id); var settings = fluidbook.video.players[id]; - //console.log(settings); // In the case of autoplay videos, we don't want the autoplay to fire // more than once (ie. never after we have these settings reccorded) @@ -256,13 +270,16 @@ FluidbookVideo.prototype = { }, 50); player.one('play', function () { - //console.log('Player has started playing... ID: ' + id); - // Handle pause in here if needed.. Better than using the timeout... + // Handle pause in here if needed. if (settings.paused) { + player.one('play', function () { + sendPlayEvent(); + }); setTimeout(function () { player.pause(); }, 100); } else { + sendPlayEvent(); $.each(hidelinksonplay, function (k, id) { $this.fluidbook.links.hideLinkById(id); }); @@ -273,6 +290,11 @@ FluidbookVideo.prototype = { player.play(); // Start player to go to current position - necessary even if it will be paused immediately if (settings.paused) { player.pause(); + player.one('play', function () { + sendPlayEvent(); + }); + } else { + sendPlayEvent(); } setTimeout(function () { @@ -281,6 +303,7 @@ FluidbookVideo.prototype = { } }); + player.on('play', function () { $.each(hidelinksonplay, function (k, id) { $this.fluidbook.links.hideLinkById(id); @@ -288,8 +311,6 @@ FluidbookVideo.prototype = { }); player.on('pause', function () { - // console.log(id + ' player paused'); - // Show play button (ref: http://stackoverflow.com/a/25296575) if (controls) { this.bigPlayButton.show(); @@ -307,12 +328,6 @@ FluidbookVideo.prototype = { }); }); - // player.on('fullscreenchange', function() { - // console.log('Entering or exiting fullscreen... resetting control sizes #' + player.id()); - // Note: this doesn't work because the fluidbookresize gets called multiple times after this fires and that overrides this change - // $('#' + player.id()).attr('style', ''); // Reset inline styles - // }); - player.on('fullscreenchange', function () { if (player.isFullscreen()) { $(window).trigger('videoFullscreenEntered'); @@ -342,8 +357,6 @@ FluidbookVideo.prototype = { path, poster; - //console.info(width, height, name, loop); - if (fluidbook.settings.mobileVideosPath == '') { path = "data/links/" + name; } else { diff --git a/js/libs/fluidbook/slideshow/fluidbook.slideshow.js b/js/libs/fluidbook/slideshow/fluidbook.slideshow.js index ee2cad37..ea22a6bc 100644 --- a/js/libs/fluidbook/slideshow/fluidbook.slideshow.js +++ b/js/libs/fluidbook/slideshow/fluidbook.slideshow.js @@ -57,6 +57,7 @@ FluidbookSlideshow.prototype = { initPopupSlideshow: function (s) { s = this.normalizeSlideshowElement(s); + this.fluidbook.stats.trackEvent('slideshow', 'show', $(s).data('name')); this.popupInstance.initSlideshow(s); }, diff --git a/js/libs/videojs/Dailymotion.js b/js/libs/videojs/Dailymotion.js new file mode 100644 index 00000000..36220852 --- /dev/null +++ b/js/libs/videojs/Dailymotion.js @@ -0,0 +1,556 @@ +/*global define, DM*/ +(function (root, factory) { + if (typeof window !== 'undefined' && window.videojs) { + factory(window.videojs); + } else if (typeof exports==='object' && typeof module!=='undefined') { + var videojs = require('video.js'); + module.exports = factory(videojs.default || videojs); + } else if (typeof define === 'function' && define.amd) { + define(['videojs'], function(videojs){ + return (root.Dailymotion = factory(videojs)); + }); + } else { + root.Dailymotion = factory(root.videojs); + } +}(this, function(videojs) { + 'use strict'; + + var _isOnMobile = videojs.browser.IS_IOS || videojs.browser.IS_NATIVE_ANDROID; + var Tech = videojs.getTech('Tech'); + + var Dailymotion = videojs.extend(Tech, { + + constructor: function(options, ready) { + Tech.call(this, options, ready); + + this.setSrc(this.options_.source); + + // Set the vjs-dailymotion class to the player + // Parent is not set yet so we have to wait a tick + var vm = this; + setTimeout(function() { + if (this.el_) { + this.el_.parentNode.className += ' vjs-dailymotion'; + + if (_isOnMobile) { + this.el_.parentNode.className += ' vjs-dailymotion-mobile'; + } + + if (Dailymotion.isSdkReady) { + vm.initDMPlayer(); + } else { + Dailymotion.sdkReadyQueue.push(vm); + } + } + }.bind(this)); + }, + + _getPlayerParams: function() { + var playerParams = { + autoplay: false, + mute: false, + controls: false, + 'queue-autoplay-next': false, + 'queue-enable': false + }; + // Let the user set any Dailymotion parameter + // https://developer.dailymotion.com/player/#player-parameters + // To use Dailymotion controls, you must use dmControls instead + + var params = ['api', 'autoplay', 'autoplay-mute', 'id', 'mute', 'origin', 'quality', 'queue-autoplay-next', + 'queue-enable', 'sharing-enable', 'start', 'subtitles-default', 'syndication', 'ui-highlight', 'ui-logo', + 'ui-start-screen-info', 'ui-theme', 'apimode', 'playlist']; + var options = this.options_; + params.forEach(function(param) { + if (typeof options[param] === 'undefined') { + return; + } + playerParams[param] = options[param]; + }); + + if (typeof this.options_.dmControls !== 'undefined') { + playerParams.controls = this.options_.dmControls; + } + + // Overwriting playlist if it is included in url + if (this.url && typeof this.url.playlist !== 'undefined') { + playerParams.playlist = this.url.playlist; + } + + // Allow undocumented options to be passed along via customVars + if (typeof this.options_.customVars !== 'undefined') { + var customVars = this.options_.customVars; + Object.keys(customVars).forEach(function(key) { + playerParams[key] = customVars[key]; + }); + } + + return playerParams; + }, + + _getPlayerConfig: function() { + var playerConfig = { + width: '100%', + height: '100%', + params: this._getPlayerParams() + }; + + if (this.url && typeof this.url.video !== 'undefined') { + playerConfig.video = this.url.video; + } else if (typeof this.options_.video !== 'undefined') { + playerConfig.video = this.options_.video; + } + + return playerConfig; + }, + + initDMPlayer: function() { + if (this.dmPlayer) { + return; + } + this.dmPlayer = new DM.player( + document.getElementById(this.options_.techId), + this._getPlayerConfig() + ); + var vm = this; + this.isApiReady = false; + this.dmPlayer.addEventListener('apiready', function() { + vm.triggerReady(); + vm.isApiReady = true; + }); + this.dmPlayer.addEventListener('durationchange', function() { + vm.trigger('durationchange'); + }); + this.dmPlayer.addEventListener('end', function() { + vm.trigger('ended'); + }); + this.dmPlayer.addEventListener('error', function() { + vm.trigger('error'); + }); + this.dmPlayer.addEventListener('loadedmetadata', function() { + vm.trigger('loadeddata'); + vm.trigger('loadedmetadata'); + }); + this.dmPlayer.addEventListener('pause', function() { + vm.trigger('pause'); + }); + this.dmPlayer.addEventListener('play', function() { + vm.trigger('loadStart'); + vm.trigger('play'); + vm.trigger('playing'); + vm.trigger('waiting'); + }); + this.dmPlayer.addEventListener('playback_ready', function() { + vm.trigger('loadeddata'); + }); + this.dmPlayer.addEventListener('timeupdate', function() { + vm.trigger('timeupdate'); + }); + this.dmPlayer.addEventListener('volumechange', function() { + vm.trigger('volumechange'); + }); + }, + + autoplay: function(autoplay) { + if (typeof autoplay !== 'undefined') { + return this.setAutoplay(autoplay); + } + + return this.options_.autoplay; + }, + + setAutoplay: function(val) { + return this.options_.autoplay = val; + }, + + buffered: function() { + if(!this.dmPlayer || !this.dmPlayer.bufferedTime) { + return videojs.createTimeRange(); + } + + return videojs.createTimeRange(0, this.dmPlayer.bufferedTime); + }, + + createEl: function() { + var div = document.createElement('div'); + div.setAttribute('id', this.options_.techId); + div.setAttribute('style', 'width:100%;height:100%;top:0;left:0;position:absolute'); + div.setAttribute('class', 'vjs-tech'); + + var divWrapper = document.createElement('div'); + divWrapper.appendChild(div); + + if (!_isOnMobile && !this.options_.dmControls) { + // var divBlocker = document.createElement('div'); + // divBlocker.setAttribute('class', 'vjs-iframe-blocker'); + // divBlocker.setAttribute('style', 'position:absolute;top:0;left:0;width:100%;height:100%'); + // + // // In case the blocker is still there and we want to pause + // divBlocker.onclick = function() { + // this.pause(); + // }.bind(this); + // + // divWrapper.appendChild(divBlocker); + } + + return divWrapper; + }, + + currentSrc: function() { + return this.source && this.source.src; + }, + + currentTime: function(seconds) { + if (typeof seconds !== 'undefined') { + return this.setCurrentTime(seconds); + } + return this.dmPlayer && this.dmPlayer.currentTime; + }, + + setCurrentTime: function(seconds) { + if (!this.dmPlayer || !this.dmPlayer.seek) { + return; + } + + return this.dmPlayer.seek(seconds); + }, + + dispose: function() { + if (DM && DM.destroy) { + //Destroy the Dailymotion Player + DM.destroy(this.options_.techId); + } else { + //Dailymotion API hasn't finished loading or the player is already disposed + var index = Dailymotion.sdkReadyQueue.indexOf(this); + if (index !== -1) { + Dailymotion.sdkReadyQueue.splice(index, 1); + } + } + this.dmPlayer = undefined; + + this.el_.parentNode.className = this.el_.parentNode.className + .replace(' vjs-dailymotion', '') + .replace(' vjs-dailymotion-mobile', ''); + this.el_.parentNode.removeChild(this.el_); + + // Needs to be called after the Dailymotion player is destroyed, + // otherwise there will be a undefined reference exception + Tech.prototype.dispose.call(this); + }, + + duration: function(seconds) { + if (typeof seconds !== 'undefined') { + return this.setDuration(seconds); + } + return this.dmPlayer ? this.dmPlayer.duration : 0; + }, + + setDuration: function(seconds) { + if (!this.dmPlayer || !this.dmPlayer.seek) { + return; + } + return this.dmPlayer.seek(seconds); + }, + + ended: function() { + return this.dmPlayer && this.dmPlayer.ended; + }, + + enterFullWindow: function() { + if (!this.dmPlayer || !this.dmPlayer.setFullscreen) { + return; + } + return this.dmPlayer.setFullscreen(true); + }, + + error: function() { + return this.dmPlayer && this.dmPlayer.error; + }, + + exitFullscreen: function() { + if (!this.dmPlayer || !this.dmPlayer.setFullscreen) { + return; + } + return this.dmPlayer.setFullscreen(false); + }, + + isFullscreen: function() { + return this.dmPlayer && this.dmPlayer.fullscreen; + }, + + // Not supported by Dailymotion + language: function() { + return undefined; + }, + + // Not supported by Dailymotion + languages: function() { + return undefined; + }, + + load: function() { + if (!this.dmPlayer || !this.dmPlayer.load) { + return; + } + return this.dmPlayer.load(this._getPlayerConfig()); + }, + + // Not supported by Dailymotion + loop: function() { + return undefined; + }, + + muted: function(muted) { + if (typeof muted !== undefined) { + return this.setMuted(muted); + } + return this.dmPlayer && this.dmPlayer.mute; + }, + + setMuted: function(mute) { + if (typeof mute === 'undefined' || !this.dmPlayer || !this.dmPlayer.setMuted) { + return; + } + + if (mute) { + this.volumeBeforeMute = this.volume(); + this.setVolume(0); + } else { + this.setVolume(this.volumeBeforeMute); + } + this.dmPlayer.setMuted(mute); + // var vm = this; + // setTimeout( function(){ + // vm.trigger('volumechange'); + // }, 50); + }, + + networkState: function () { + if (!this.dmPlayer || this.dmPlayer.error) { + return 0; //NETWORK_EMPTY + } + + if (this.dmPlayer.seeking) { + return 2; //NETWORK_LOADING + } + }, + + pause: function() { + if (!this.dmPlayer || !this.dmPlayer.pause) { + return; + } + + return this.dmPlayer.pause(); + }, + + paused: function() { + return this.dmPlayer && this.dmPlayer.paused; + }, + + play: function() { + if (!this.isApiReady || !this.dmPlayer || !this.dmPlayer.play) { + return; + } + + this.trigger('loadStart'); + this.trigger('waiting'); + return this.dmPlayer.play(); + }, + + // Playback rate is not support by Dailymotion + playbackRate: function() { + return 1; + }, + + // Not supported by Dailymotion + poster: function() { + return undefined; + }, + + // Not supported by Dailymotion + preload: function() { + return undefined; + }, + + // TODO: Confirm if it can be more detail + readyState: function() { + if (!this.dmPlayer || this.dmPlayer.error) { + return 0; //NETWORK_EMPTY + } + + if (this.dmPlayer.seeking) { + return 1; //HAVE_METADATA + } + return 4; //HAVE_ENOUGH_DATA + }, + + remainingTime: function() { + return this.dmPlayer && (this.dmPlayer.duration - this.dmPlayer.currentTime); + }, + + requestFullscreen: function() { + return this.enterFullWindow(); + }, + + enterFullScreen: function() { + return this.enterFullWindow(); + }, + + reset: function() { + this.load(); + }, + + seekable: function () { + if(!this.dmPlayer) { + return videojs.createTimeRange(); + } + + return videojs.createTimeRange(0, this.dmPlayer.duration); + }, + + seeking: function () { + return this.dmPlayer && this.dmPlayer.seeking; + }, + + src: function(source) { + if (typeof source !== 'undefined') { + return this.setSrc(source); + } + + return this.source; + }, + + setSrc: function(source) { + if (typeof source === 'undefined') { + return; + } + + this.source = source; + this.url = Dailymotion.parseUrl(source.src || source); + + // Load the video if sdk is ready + if (Dailymotion.isSdkReady) { + this.load(); + } + return this.source; + }, + + supportsFullScreen: function() { + return true; + }, + + volume: function() { + return this.dmPlayer ? this.dmPlayer.volume : 1; + }, + + setVolume: function(percentAsDecimal) { + if (!this.dmPlayer || !this.dmPlayer.setMuted || !this.dmPlayer.setVolume) { + return; + } + + this.dmPlayer.setMuted(false); + this.dmPlayer.setVolume(percentAsDecimal); + }, + + }); + + Dailymotion.isSupported = function() { + return true; + }; + + Dailymotion.canPlaySource = function(e) { + return Dailymotion.canPlayType(e.type); + }; + + Dailymotion.canPlayType = function(e) { + return (e === 'video/dailymotion'); + }; + + Dailymotion.parseUrl = function(url) { + var result = {}; + + var regex = /video\/[^?|^\/]*/; + var match = url.match(regex); + + if (match && match[0]) { + result.video = match[0].replace('video/', ''); + } + + var regPlaylist = /playlist(=|\/)[^&]*/; + match = url.match(regPlaylist); + + if(match && match[0]) { + result.playlist = match[0].replace(/playlist(=|\/)/, ''); + } + + return result; + }; + + function apiLoaded() { + Dailymotion.isSdkReady = true; + + for (var i = 0; i < Dailymotion.sdkReadyQueue.length; ++i) { + Dailymotion.sdkReadyQueue[i].initDMPlayer(); + } + } + + function loadScript(src, callback) { + var loaded = false; + var tag = document.createElement('script'); + var firstScriptTag = document.getElementsByTagName('script')[0]; + if (!firstScriptTag) { + // when loaded in jest without jsdom setup it doesn't get any element. + // In jest it doesn't really make sense to do anything, because no one is watching dailymotion in jest + return; + } + firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); + tag.onload = function () { + if (!loaded) { + loaded = true; + callback(); + } + }; + tag.onreadystatechange = function () { + if (!loaded && (this.readyState === 'complete' || this.readyState === 'loaded')) { + loaded = true; + callback(); + } + }; + tag.src = src; + } + + function injectCss() { + var css = // iframe blocker to catch mouse events + '.vjs-dailymotion .vjs-iframe-blocker { display: none; }' + + '.vjs-dailymotion.vjs-user-inactive .vjs-iframe-blocker { display: block; }' + + '.vjs-dailymotion .vjs-poster { background-size: cover; }' + + '.vjs-dailymotion-mobile .vjs-big-play-button { display: none; }'; + + var head = document.head || document.getElementsByTagName('head')[0]; + + var style = document.createElement('style'); + style.setAttribute('type', 'text/css'); + + if (style.styleSheet){ + style.styleSheet.cssText = css; + } else { + style.appendChild(document.createTextNode(css)); + } + + head.appendChild(style); + } + + Dailymotion.sdkReadyQueue = []; + + if (typeof document !== 'undefined'){ + loadScript('https://api.dmcdn.net/all.js', apiLoaded); + injectCss(); + } + + // Older versions of VJS5 doesn't have the registerTech function + if (typeof videojs.registerTech !== 'undefined') { + videojs.registerTech('Dailymotion', Dailymotion); + } else { + videojs.registerComponent('Dailymotion', Dailymotion); + } +})); diff --git a/js/libs/videojs/Vimeo.js b/js/libs/videojs/Vimeo.js new file mode 100644 index 00000000..fc293ea4 --- /dev/null +++ b/js/libs/videojs/Vimeo.js @@ -0,0 +1,2414 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('video.js')) : + typeof define === 'function' && define.amd ? define(['video.js'], factory) : + (global = global || self, global['videojs-vimeo'] = factory(global.videojs)); +}(this, (function (videojs) { 'use strict'; + + videojs = videojs && videojs.hasOwnProperty('default') ? videojs['default'] : videojs; + + /*! @vimeo/player v2.10.0 | (c) 2019 Vimeo | MIT License | https://github.com/vimeo/player.js */ + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; + } + + /** + * @module lib/functions + */ + + /** + * Check to see this is a node environment. + * @type {Boolean} + */ + + /* global global */ + var isNode = typeof global !== 'undefined' && {}.toString.call(global) === '[object global]'; + /** + * Get the name of the method for a given getter or setter. + * + * @param {string} prop The name of the property. + * @param {string} type Either “get” or “set”. + * @return {string} + */ + + function getMethodName(prop, type) { + if (prop.indexOf(type.toLowerCase()) === 0) { + return prop; + } + + return "".concat(type.toLowerCase()).concat(prop.substr(0, 1).toUpperCase()).concat(prop.substr(1)); + } + /** + * Check to see if the object is a DOM Element. + * + * @param {*} element The object to check. + * @return {boolean} + */ + + function isDomElement(element) { + return Boolean(element && element.nodeType === 1 && 'nodeName' in element && element.ownerDocument && element.ownerDocument.defaultView); + } + /** + * Check to see whether the value is a number. + * + * @see http://dl.dropboxusercontent.com/u/35146/js/tests/isNumber.html + * @param {*} value The value to check. + * @param {boolean} integer Check if the value is an integer. + * @return {boolean} + */ + + function isInteger(value) { + // eslint-disable-next-line eqeqeq + return !isNaN(parseFloat(value)) && isFinite(value) && Math.floor(value) == value; + } + /** + * Check to see if the URL is a Vimeo url. + * + * @param {string} url The url string. + * @return {boolean} + */ + + function isVimeoUrl(url) { + return /^(https?:)?\/\/((player|www)\.)?vimeo\.com(?=$|\/)/.test(url); + } + /** + * Get the Vimeo URL from an element. + * The element must have either a data-vimeo-id or data-vimeo-url attribute. + * + * @param {object} oEmbedParameters The oEmbed parameters. + * @return {string} + */ + + function getVimeoUrl() { + var oEmbedParameters = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var id = oEmbedParameters.id; + var url = oEmbedParameters.url; + var idOrUrl = id || url; + + if (!idOrUrl) { + throw new Error('An id or url must be passed, either in an options object or as a data-vimeo-id or data-vimeo-url attribute.'); + } + + if (isInteger(idOrUrl)) { + return "https://vimeo.com/".concat(idOrUrl); + } + + if (isVimeoUrl(idOrUrl)) { + return idOrUrl.replace('http:', 'https:'); + } + + if (id) { + throw new TypeError("\u201C".concat(id, "\u201D is not a valid video id.")); + } + + throw new TypeError("\u201C".concat(idOrUrl, "\u201D is not a vimeo.com url.")); + } + + var arrayIndexOfSupport = typeof Array.prototype.indexOf !== 'undefined'; + var postMessageSupport = typeof window !== 'undefined' && typeof window.postMessage !== 'undefined'; + + if (!isNode && (!arrayIndexOfSupport || !postMessageSupport)) { + throw new Error('Sorry, the Vimeo Player API is not available in this browser.'); + } + + var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; + } + + /*! + * weakmap-polyfill v2.0.0 - ECMAScript6 WeakMap polyfill + * https://github.com/polygonplanet/weakmap-polyfill + * Copyright (c) 2015-2016 polygon planet + * @license MIT + */ + (function (self) { + + if (self.WeakMap) { + return; + } + + var hasOwnProperty = Object.prototype.hasOwnProperty; + + var defineProperty = function (object, name, value) { + if (Object.defineProperty) { + Object.defineProperty(object, name, { + configurable: true, + writable: true, + value: value + }); + } else { + object[name] = value; + } + }; + + self.WeakMap = function () { + // ECMA-262 23.3 WeakMap Objects + function WeakMap() { + if (this === void 0) { + throw new TypeError("Constructor WeakMap requires 'new'"); + } + + defineProperty(this, '_id', genId('_WeakMap')); // ECMA-262 23.3.1.1 WeakMap([iterable]) + + if (arguments.length > 0) { + // Currently, WeakMap `iterable` argument is not supported + throw new TypeError('WeakMap iterable is not supported'); + } + } // ECMA-262 23.3.3.2 WeakMap.prototype.delete(key) + + + defineProperty(WeakMap.prototype, 'delete', function (key) { + checkInstance(this, 'delete'); + + if (!isObject(key)) { + return false; + } + + var entry = key[this._id]; + + if (entry && entry[0] === key) { + delete key[this._id]; + return true; + } + + return false; + }); // ECMA-262 23.3.3.3 WeakMap.prototype.get(key) + + defineProperty(WeakMap.prototype, 'get', function (key) { + checkInstance(this, 'get'); + + if (!isObject(key)) { + return void 0; + } + + var entry = key[this._id]; + + if (entry && entry[0] === key) { + return entry[1]; + } + + return void 0; + }); // ECMA-262 23.3.3.4 WeakMap.prototype.has(key) + + defineProperty(WeakMap.prototype, 'has', function (key) { + checkInstance(this, 'has'); + + if (!isObject(key)) { + return false; + } + + var entry = key[this._id]; + + if (entry && entry[0] === key) { + return true; + } + + return false; + }); // ECMA-262 23.3.3.5 WeakMap.prototype.set(key, value) + + defineProperty(WeakMap.prototype, 'set', function (key, value) { + checkInstance(this, 'set'); + + if (!isObject(key)) { + throw new TypeError('Invalid value used as weak map key'); + } + + var entry = key[this._id]; + + if (entry && entry[0] === key) { + entry[1] = value; + return this; + } + + defineProperty(key, this._id, [key, value]); + return this; + }); + + function checkInstance(x, methodName) { + if (!isObject(x) || !hasOwnProperty.call(x, '_id')) { + throw new TypeError(methodName + ' method called on incompatible receiver ' + typeof x); + } + } + + function genId(prefix) { + return prefix + '_' + rand() + '.' + rand(); + } + + function rand() { + return Math.random().toString().substring(2); + } + + defineProperty(WeakMap, '_polyfill', true); + return WeakMap; + }(); + + function isObject(x) { + return Object(x) === x; + } + })(typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : commonjsGlobal); + + var npo_src = createCommonjsModule(function (module) { + /*! Native Promise Only + v0.8.1 (c) Kyle Simpson + MIT License: http://getify.mit-license.org + */ + (function UMD(name, context, definition) { + // special form of UMD for polyfilling across evironments + context[name] = context[name] || definition(); + + if (module.exports) { + module.exports = context[name]; + } + })("Promise", typeof commonjsGlobal != "undefined" ? commonjsGlobal : commonjsGlobal, function DEF() { + + var builtInProp, + cycle, + scheduling_queue, + ToString = Object.prototype.toString, + timer = typeof setImmediate != "undefined" ? function timer(fn) { + return setImmediate(fn); + } : setTimeout; // dammit, IE8. + + try { + Object.defineProperty({}, "x", {}); + + builtInProp = function builtInProp(obj, name, val, config) { + return Object.defineProperty(obj, name, { + value: val, + writable: true, + configurable: config !== false + }); + }; + } catch (err) { + builtInProp = function builtInProp(obj, name, val) { + obj[name] = val; + return obj; + }; + } // Note: using a queue instead of array for efficiency + + + scheduling_queue = function Queue() { + var first, last, item; + + function Item(fn, self) { + this.fn = fn; + this.self = self; + this.next = void 0; + } + + return { + add: function add(fn, self) { + item = new Item(fn, self); + + if (last) { + last.next = item; + } else { + first = item; + } + + last = item; + item = void 0; + }, + drain: function drain() { + var f = first; + first = last = cycle = void 0; + + while (f) { + f.fn.call(f.self); + f = f.next; + } + } + }; + }(); + + function schedule(fn, self) { + scheduling_queue.add(fn, self); + + if (!cycle) { + cycle = timer(scheduling_queue.drain); + } + } // promise duck typing + + + function isThenable(o) { + var _then, + o_type = typeof o; + + if (o != null && (o_type == "object" || o_type == "function")) { + _then = o.then; + } + + return typeof _then == "function" ? _then : false; + } + + function notify() { + for (var i = 0; i < this.chain.length; i++) { + notifyIsolated(this, this.state === 1 ? this.chain[i].success : this.chain[i].failure, this.chain[i]); + } + + this.chain.length = 0; + } // NOTE: This is a separate function to isolate + // the `try..catch` so that other code can be + // optimized better + + + function notifyIsolated(self, cb, chain) { + var ret, _then; + + try { + if (cb === false) { + chain.reject(self.msg); + } else { + if (cb === true) { + ret = self.msg; + } else { + ret = cb.call(void 0, self.msg); + } + + if (ret === chain.promise) { + chain.reject(TypeError("Promise-chain cycle")); + } else if (_then = isThenable(ret)) { + _then.call(ret, chain.resolve, chain.reject); + } else { + chain.resolve(ret); + } + } + } catch (err) { + chain.reject(err); + } + } + + function resolve(msg) { + var _then, + self = this; // already triggered? + + + if (self.triggered) { + return; + } + + self.triggered = true; // unwrap + + if (self.def) { + self = self.def; + } + + try { + if (_then = isThenable(msg)) { + schedule(function () { + var def_wrapper = new MakeDefWrapper(self); + + try { + _then.call(msg, function $resolve$() { + resolve.apply(def_wrapper, arguments); + }, function $reject$() { + reject.apply(def_wrapper, arguments); + }); + } catch (err) { + reject.call(def_wrapper, err); + } + }); + } else { + self.msg = msg; + self.state = 1; + + if (self.chain.length > 0) { + schedule(notify, self); + } + } + } catch (err) { + reject.call(new MakeDefWrapper(self), err); + } + } + + function reject(msg) { + var self = this; // already triggered? + + if (self.triggered) { + return; + } + + self.triggered = true; // unwrap + + if (self.def) { + self = self.def; + } + + self.msg = msg; + self.state = 2; + + if (self.chain.length > 0) { + schedule(notify, self); + } + } + + function iteratePromises(Constructor, arr, resolver, rejecter) { + for (var idx = 0; idx < arr.length; idx++) { + (function IIFE(idx) { + Constructor.resolve(arr[idx]).then(function $resolver$(msg) { + resolver(idx, msg); + }, rejecter); + })(idx); + } + } + + function MakeDefWrapper(self) { + this.def = self; + this.triggered = false; + } + + function MakeDef(self) { + this.promise = self; + this.state = 0; + this.triggered = false; + this.chain = []; + this.msg = void 0; + } + + function Promise(executor) { + if (typeof executor != "function") { + throw TypeError("Not a function"); + } + + if (this.__NPO__ !== 0) { + throw TypeError("Not a promise"); + } // instance shadowing the inherited "brand" + // to signal an already "initialized" promise + + + this.__NPO__ = 1; + var def = new MakeDef(this); + + this["then"] = function then(success, failure) { + var o = { + success: typeof success == "function" ? success : true, + failure: typeof failure == "function" ? failure : false + }; // Note: `then(..)` itself can be borrowed to be used against + // a different promise constructor for making the chained promise, + // by substituting a different `this` binding. + + o.promise = new this.constructor(function extractChain(resolve, reject) { + if (typeof resolve != "function" || typeof reject != "function") { + throw TypeError("Not a function"); + } + + o.resolve = resolve; + o.reject = reject; + }); + def.chain.push(o); + + if (def.state !== 0) { + schedule(notify, def); + } + + return o.promise; + }; + + this["catch"] = function $catch$(failure) { + return this.then(void 0, failure); + }; + + try { + executor.call(void 0, function publicResolve(msg) { + resolve.call(def, msg); + }, function publicReject(msg) { + reject.call(def, msg); + }); + } catch (err) { + reject.call(def, err); + } + } + + var PromisePrototype = builtInProp({}, "constructor", Promise, + /*configurable=*/ + false); // Note: Android 4 cannot use `Object.defineProperty(..)` here + + Promise.prototype = PromisePrototype; // built-in "brand" to signal an "uninitialized" promise + + builtInProp(PromisePrototype, "__NPO__", 0, + /*configurable=*/ + false); + builtInProp(Promise, "resolve", function Promise$resolve(msg) { + var Constructor = this; // spec mandated checks + // note: best "isPromise" check that's practical for now + + if (msg && typeof msg == "object" && msg.__NPO__ === 1) { + return msg; + } + + return new Constructor(function executor(resolve, reject) { + if (typeof resolve != "function" || typeof reject != "function") { + throw TypeError("Not a function"); + } + + resolve(msg); + }); + }); + builtInProp(Promise, "reject", function Promise$reject(msg) { + return new this(function executor(resolve, reject) { + if (typeof resolve != "function" || typeof reject != "function") { + throw TypeError("Not a function"); + } + + reject(msg); + }); + }); + builtInProp(Promise, "all", function Promise$all(arr) { + var Constructor = this; // spec mandated checks + + if (ToString.call(arr) != "[object Array]") { + return Constructor.reject(TypeError("Not an array")); + } + + if (arr.length === 0) { + return Constructor.resolve([]); + } + + return new Constructor(function executor(resolve, reject) { + if (typeof resolve != "function" || typeof reject != "function") { + throw TypeError("Not a function"); + } + + var len = arr.length, + msgs = Array(len), + count = 0; + iteratePromises(Constructor, arr, function resolver(idx, msg) { + msgs[idx] = msg; + + if (++count === len) { + resolve(msgs); + } + }, reject); + }); + }); + builtInProp(Promise, "race", function Promise$race(arr) { + var Constructor = this; // spec mandated checks + + if (ToString.call(arr) != "[object Array]") { + return Constructor.reject(TypeError("Not an array")); + } + + return new Constructor(function executor(resolve, reject) { + if (typeof resolve != "function" || typeof reject != "function") { + throw TypeError("Not a function"); + } + + iteratePromises(Constructor, arr, function resolver(idx, msg) { + resolve(msg); + }, reject); + }); + }); + return Promise; + }); + }); + + /** + * @module lib/callbacks + */ + var callbackMap = new WeakMap(); + /** + * Store a callback for a method or event for a player. + * + * @param {Player} player The player object. + * @param {string} name The method or event name. + * @param {(function(this:Player, *): void|{resolve: function, reject: function})} callback + * The callback to call or an object with resolve and reject functions for a promise. + * @return {void} + */ + + function storeCallback(player, name, callback) { + var playerCallbacks = callbackMap.get(player.element) || {}; + + if (!(name in playerCallbacks)) { + playerCallbacks[name] = []; + } + + playerCallbacks[name].push(callback); + callbackMap.set(player.element, playerCallbacks); + } + /** + * Get the callbacks for a player and event or method. + * + * @param {Player} player The player object. + * @param {string} name The method or event name + * @return {function[]} + */ + + function getCallbacks(player, name) { + var playerCallbacks = callbackMap.get(player.element) || {}; + return playerCallbacks[name] || []; + } + /** + * Remove a stored callback for a method or event for a player. + * + * @param {Player} player The player object. + * @param {string} name The method or event name + * @param {function} [callback] The specific callback to remove. + * @return {boolean} Was this the last callback? + */ + + function removeCallback(player, name, callback) { + var playerCallbacks = callbackMap.get(player.element) || {}; + + if (!playerCallbacks[name]) { + return true; + } // If no callback is passed, remove all callbacks for the event + + + if (!callback) { + playerCallbacks[name] = []; + callbackMap.set(player.element, playerCallbacks); + return true; + } + + var index = playerCallbacks[name].indexOf(callback); + + if (index !== -1) { + playerCallbacks[name].splice(index, 1); + } + + callbackMap.set(player.element, playerCallbacks); + return playerCallbacks[name] && playerCallbacks[name].length === 0; + } + /** + * Return the first stored callback for a player and event or method. + * + * @param {Player} player The player object. + * @param {string} name The method or event name. + * @return {function} The callback, or false if there were none + */ + + function shiftCallbacks(player, name) { + var playerCallbacks = getCallbacks(player, name); + + if (playerCallbacks.length < 1) { + return false; + } + + var callback = playerCallbacks.shift(); + removeCallback(player, name, callback); + return callback; + } + /** + * Move callbacks associated with an element to another element. + * + * @param {HTMLElement} oldElement The old element. + * @param {HTMLElement} newElement The new element. + * @return {void} + */ + + function swapCallbacks(oldElement, newElement) { + var playerCallbacks = callbackMap.get(oldElement); + callbackMap.set(newElement, playerCallbacks); + callbackMap.delete(oldElement); + } + + /** + * @module lib/embed + */ + var oEmbedParameters = ['autopause', 'autoplay', 'background', 'byline', 'color', 'controls', 'dnt', 'height', 'id', 'loop', 'maxheight', 'maxwidth', 'muted', 'playsinline', 'portrait', 'responsive', 'speed', 'texttrack', 'title', 'transparent', 'url', 'width']; + /** + * Get the 'data-vimeo'-prefixed attributes from an element as an object. + * + * @param {HTMLElement} element The element. + * @param {Object} [defaults={}] The default values to use. + * @return {Object} + */ + + function getOEmbedParameters(element) { + var defaults = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + return oEmbedParameters.reduce(function (params, param) { + var value = element.getAttribute("data-vimeo-".concat(param)); + + if (value || value === '') { + params[param] = value === '' ? 1 : value; + } + + return params; + }, defaults); + } + /** + * Create an embed from oEmbed data inside an element. + * + * @param {object} data The oEmbed data. + * @param {HTMLElement} element The element to put the iframe in. + * @return {HTMLIFrameElement} The iframe embed. + */ + + function createEmbed(_ref, element) { + var html = _ref.html; + + if (!element) { + throw new TypeError('An element must be provided'); + } + + if (element.getAttribute('data-vimeo-initialized') !== null) { + return element.querySelector('iframe'); + } + + var div = document.createElement('div'); + div.innerHTML = html; + element.appendChild(div.firstChild); + element.setAttribute('data-vimeo-initialized', 'true'); + return element.querySelector('iframe'); + } + /** + * Make an oEmbed call for the specified URL. + * + * @param {string} videoUrl The vimeo.com url for the video. + * @param {Object} [params] Parameters to pass to oEmbed. + * @param {HTMLElement} element The element. + * @return {Promise} + */ + + function getOEmbedData(videoUrl) { + var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var element = arguments.length > 2 ? arguments[2] : undefined; + return new Promise(function (resolve, reject) { + if (!isVimeoUrl(videoUrl)) { + throw new TypeError("\u201C".concat(videoUrl, "\u201D is not a vimeo.com url.")); + } + + var url = "https://vimeo.com/api/oembed.json?url=".concat(encodeURIComponent(videoUrl)); + + for (var param in params) { + if (params.hasOwnProperty(param)) { + url += "&".concat(param, "=").concat(encodeURIComponent(params[param])); + } + } + + var xhr = 'XDomainRequest' in window ? new XDomainRequest() : new XMLHttpRequest(); + xhr.open('GET', url, true); + + xhr.onload = function () { + if (xhr.status === 404) { + reject(new Error("\u201C".concat(videoUrl, "\u201D was not found."))); + return; + } + + if (xhr.status === 403) { + reject(new Error("\u201C".concat(videoUrl, "\u201D is not embeddable."))); + return; + } + + try { + var json = JSON.parse(xhr.responseText); // Check api response for 403 on oembed + + if (json.domain_status_code === 403) { + // We still want to create the embed to give users visual feedback + createEmbed(json, element); + reject(new Error("\u201C".concat(videoUrl, "\u201D is not embeddable."))); + return; + } + + resolve(json); + } catch (error) { + reject(error); + } + }; + + xhr.onerror = function () { + var status = xhr.status ? " (".concat(xhr.status, ")") : ''; + reject(new Error("There was an error fetching the embed code from Vimeo".concat(status, "."))); + }; + + xhr.send(); + }); + } + /** + * Initialize all embeds within a specific element + * + * @param {HTMLElement} [parent=document] The parent element. + * @return {void} + */ + + function initializeEmbeds() { + var parent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document; + var elements = [].slice.call(parent.querySelectorAll('[data-vimeo-id], [data-vimeo-url]')); + + var handleError = function handleError(error) { + if ('console' in window && console.error) { + console.error("There was an error creating an embed: ".concat(error)); + } + }; + + elements.forEach(function (element) { + try { + // Skip any that have data-vimeo-defer + if (element.getAttribute('data-vimeo-defer') !== null) { + return; + } + + var params = getOEmbedParameters(element); + var url = getVimeoUrl(params); + getOEmbedData(url, params, element).then(function (data) { + return createEmbed(data, element); + }).catch(handleError); + } catch (error) { + handleError(error); + } + }); + } + /** + * Resize embeds when messaged by the player. + * + * @param {HTMLElement} [parent=document] The parent element. + * @return {void} + */ + + function resizeEmbeds() { + var parent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : document; + + // Prevent execution if users include the player.js script multiple times. + if (window.VimeoPlayerResizeEmbeds_) { + return; + } + + window.VimeoPlayerResizeEmbeds_ = true; + + var onMessage = function onMessage(event) { + if (!isVimeoUrl(event.origin)) { + return; + } // 'spacechange' is fired only on embeds with cards + + + if (!event.data || event.data.event !== 'spacechange') { + return; + } + + var iframes = parent.querySelectorAll('iframe'); + + for (var i = 0; i < iframes.length; i++) { + if (iframes[i].contentWindow !== event.source) { + continue; + } // Change padding-bottom of the enclosing div to accommodate + // card carousel without distorting aspect ratio + + + var space = iframes[i].parentElement; + space.style.paddingBottom = "".concat(event.data.data[0].bottom, "px"); + break; + } + }; + + if (window.addEventListener) { + window.addEventListener('message', onMessage, false); + } else if (window.attachEvent) { + window.attachEvent('onmessage', onMessage); + } + } + + /** + * @module lib/postmessage + */ + /** + * Parse a message received from postMessage. + * + * @param {*} data The data received from postMessage. + * @return {object} + */ + + function parseMessageData(data) { + if (typeof data === 'string') { + try { + data = JSON.parse(data); + } catch (error) { + // If the message cannot be parsed, throw the error as a warning + console.warn(error); + return {}; + } + } + + return data; + } + /** + * Post a message to the specified target. + * + * @param {Player} player The player object to use. + * @param {string} method The API method to call. + * @param {object} params The parameters to send to the player. + * @return {void} + */ + + function postMessage(player, method, params) { + if (!player.element.contentWindow || !player.element.contentWindow.postMessage) { + return; + } + + var message = { + method: method + }; + + if (params !== undefined) { + message.value = params; + } // IE 8 and 9 do not support passing messages, so stringify them + + + var ieVersion = parseFloat(navigator.userAgent.toLowerCase().replace(/^.*msie (\d+).*$/, '$1')); + + if (ieVersion >= 8 && ieVersion < 10) { + message = JSON.stringify(message); + } + + player.element.contentWindow.postMessage(message, player.origin); + } + /** + * Parse the data received from a message event. + * + * @param {Player} player The player that received the message. + * @param {(Object|string)} data The message data. Strings will be parsed into JSON. + * @return {void} + */ + + function processData(player, data) { + data = parseMessageData(data); + var callbacks = []; + var param; + + if (data.event) { + if (data.event === 'error') { + var promises = getCallbacks(player, data.data.method); + promises.forEach(function (promise) { + var error = new Error(data.data.message); + error.name = data.data.name; + promise.reject(error); + removeCallback(player, data.data.method, promise); + }); + } + + callbacks = getCallbacks(player, "event:".concat(data.event)); + param = data.data; + } else if (data.method) { + var callback = shiftCallbacks(player, data.method); + + if (callback) { + callbacks.push(callback); + param = data.value; + } + } + + callbacks.forEach(function (callback) { + try { + if (typeof callback === 'function') { + callback.call(player, param); + return; + } + + callback.resolve(param); + } catch (e) {// empty + } + }); + } + + var playerMap = new WeakMap(); + var readyMap = new WeakMap(); + + var Player = + /*#__PURE__*/ + function () { + /** + * Create a Player. + * + * @param {(HTMLIFrameElement|HTMLElement|string|jQuery)} element A reference to the Vimeo + * player iframe, and id, or a jQuery object. + * @param {object} [options] oEmbed parameters to use when creating an embed in the element. + * @return {Player} + */ + function Player(element) { + var _this = this; + + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, Player); + + /* global jQuery */ + if (window.jQuery && element instanceof jQuery) { + if (element.length > 1 && window.console && console.warn) { + console.warn('A jQuery object with multiple elements was passed, using the first element.'); + } + + element = element[0]; + } // Find an element by ID + + + if (typeof document !== 'undefined' && typeof element === 'string') { + element = document.getElementById(element); + } // Not an element! + + + if (!isDomElement(element)) { + throw new TypeError('You must pass either a valid element or a valid id.'); + } + + var win = element.ownerDocument.defaultView; // Already initialized an embed in this div, so grab the iframe + + if (element.nodeName !== 'IFRAME') { + var iframe = element.querySelector('iframe'); + + if (iframe) { + element = iframe; + } + } // iframe url is not a Vimeo url + + + if (element.nodeName === 'IFRAME' && !isVimeoUrl(element.getAttribute('src') || '')) { + throw new Error('The player element passed isn’t a Vimeo embed.'); + } // If there is already a player object in the map, return that + + + if (playerMap.has(element)) { + return playerMap.get(element); + } + + this.element = element; + this.origin = '*'; + var readyPromise = new npo_src(function (resolve, reject) { + var onMessage = function onMessage(event) { + if (!isVimeoUrl(event.origin) || _this.element.contentWindow !== event.source) { + return; + } + + if (_this.origin === '*') { + _this.origin = event.origin; + } + + var data = parseMessageData(event.data); + var isError = data && data.event === 'error'; + var isReadyError = isError && data.data && data.data.method === 'ready'; + + if (isReadyError) { + var error = new Error(data.data.message); + error.name = data.data.name; + reject(error); + return; + } + + var isReadyEvent = data && data.event === 'ready'; + var isPingResponse = data && data.method === 'ping'; + + if (isReadyEvent || isPingResponse) { + _this.element.setAttribute('data-ready', 'true'); + + resolve(); + return; + } + + processData(_this, data); + }; + + if (win.addEventListener) { + win.addEventListener('message', onMessage, false); + } else if (win.attachEvent) { + win.attachEvent('onmessage', onMessage); + } + + if (_this.element.nodeName !== 'IFRAME') { + var params = getOEmbedParameters(element, options); + var url = getVimeoUrl(params); + getOEmbedData(url, params, element).then(function (data) { + var iframe = createEmbed(data, element); // Overwrite element with the new iframe, + // but store reference to the original element + + _this.element = iframe; + _this._originalElement = element; + swapCallbacks(element, iframe); + playerMap.set(_this.element, _this); + return data; + }).catch(reject); + } + }); // Store a copy of this Player in the map + + readyMap.set(this, readyPromise); + playerMap.set(this.element, this); // Send a ping to the iframe so the ready promise will be resolved if + // the player is already ready. + + if (this.element.nodeName === 'IFRAME') { + postMessage(this, 'ping'); + } + + return this; + } + /** + * Get a promise for a method. + * + * @param {string} name The API method to call. + * @param {Object} [args={}] Arguments to send via postMessage. + * @return {Promise} + */ + + + _createClass(Player, [{ + key: "callMethod", + value: function callMethod(name) { + var _this2 = this; + + var args = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + return new npo_src(function (resolve, reject) { + // We are storing the resolve/reject handlers to call later, so we + // can’t return here. + // eslint-disable-next-line promise/always-return + return _this2.ready().then(function () { + storeCallback(_this2, name, { + resolve: resolve, + reject: reject + }); + postMessage(_this2, name, args); + }).catch(reject); + }); + } + /** + * Get a promise for the value of a player property. + * + * @param {string} name The property name + * @return {Promise} + */ + + }, { + key: "get", + value: function get(name) { + var _this3 = this; + + return new npo_src(function (resolve, reject) { + name = getMethodName(name, 'get'); // We are storing the resolve/reject handlers to call later, so we + // can’t return here. + // eslint-disable-next-line promise/always-return + + return _this3.ready().then(function () { + storeCallback(_this3, name, { + resolve: resolve, + reject: reject + }); + postMessage(_this3, name); + }).catch(reject); + }); + } + /** + * Get a promise for setting the value of a player property. + * + * @param {string} name The API method to call. + * @param {mixed} value The value to set. + * @return {Promise} + */ + + }, { + key: "set", + value: function set(name, value) { + var _this4 = this; + + return new npo_src(function (resolve, reject) { + name = getMethodName(name, 'set'); + + if (value === undefined || value === null) { + throw new TypeError('There must be a value to set.'); + } // We are storing the resolve/reject handlers to call later, so we + // can’t return here. + // eslint-disable-next-line promise/always-return + + + return _this4.ready().then(function () { + storeCallback(_this4, name, { + resolve: resolve, + reject: reject + }); + postMessage(_this4, name, value); + }).catch(reject); + }); + } + /** + * Add an event listener for the specified event. Will call the + * callback with a single parameter, `data`, that contains the data for + * that event. + * + * @param {string} eventName The name of the event. + * @param {function(*)} callback The function to call when the event fires. + * @return {void} + */ + + }, { + key: "on", + value: function on(eventName, callback) { + if (!eventName) { + throw new TypeError('You must pass an event name.'); + } + + if (!callback) { + throw new TypeError('You must pass a callback function.'); + } + + if (typeof callback !== 'function') { + throw new TypeError('The callback must be a function.'); + } + + var callbacks = getCallbacks(this, "event:".concat(eventName)); + + if (callbacks.length === 0) { + this.callMethod('addEventListener', eventName).catch(function () {// Ignore the error. There will be an error event fired that + // will trigger the error callback if they are listening. + }); + } + + storeCallback(this, "event:".concat(eventName), callback); + } + /** + * Remove an event listener for the specified event. Will remove all + * listeners for that event if a `callback` isn’t passed, or only that + * specific callback if it is passed. + * + * @param {string} eventName The name of the event. + * @param {function} [callback] The specific callback to remove. + * @return {void} + */ + + }, { + key: "off", + value: function off(eventName, callback) { + if (!eventName) { + throw new TypeError('You must pass an event name.'); + } + + if (callback && typeof callback !== 'function') { + throw new TypeError('The callback must be a function.'); + } + + var lastCallback = removeCallback(this, "event:".concat(eventName), callback); // If there are no callbacks left, remove the listener + + if (lastCallback) { + this.callMethod('removeEventListener', eventName).catch(function (e) {// Ignore the error. There will be an error event fired that + // will trigger the error callback if they are listening. + }); + } + } + /** + * A promise to load a new video. + * + * @promise LoadVideoPromise + * @fulfill {number} The video with this id successfully loaded. + * @reject {TypeError} The id was not a number. + */ + + /** + * Load a new video into this embed. The promise will be resolved if + * the video is successfully loaded, or it will be rejected if it could + * not be loaded. + * + * @param {number|object} options The id of the video or an object with embed options. + * @return {LoadVideoPromise} + */ + + }, { + key: "loadVideo", + value: function loadVideo(options) { + return this.callMethod('loadVideo', options); + } + /** + * A promise to perform an action when the Player is ready. + * + * @todo document errors + * @promise LoadVideoPromise + * @fulfill {void} + */ + + /** + * Trigger a function when the player iframe has initialized. You do not + * need to wait for `ready` to trigger to begin adding event listeners + * or calling other methods. + * + * @return {ReadyPromise} + */ + + }, { + key: "ready", + value: function ready() { + var readyPromise = readyMap.get(this) || new npo_src(function (resolve, reject) { + reject(new Error('Unknown player. Probably unloaded.')); + }); + return npo_src.resolve(readyPromise); + } + /** + * A promise to add a cue point to the player. + * + * @promise AddCuePointPromise + * @fulfill {string} The id of the cue point to use for removeCuePoint. + * @reject {RangeError} the time was less than 0 or greater than the + * video’s duration. + * @reject {UnsupportedError} Cue points are not supported with the current + * player or browser. + */ + + /** + * Add a cue point to the player. + * + * @param {number} time The time for the cue point. + * @param {object} [data] Arbitrary data to be returned with the cue point. + * @return {AddCuePointPromise} + */ + + }, { + key: "addCuePoint", + value: function addCuePoint(time) { + var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + return this.callMethod('addCuePoint', { + time: time, + data: data + }); + } + /** + * A promise to remove a cue point from the player. + * + * @promise AddCuePointPromise + * @fulfill {string} The id of the cue point that was removed. + * @reject {InvalidCuePoint} The cue point with the specified id was not + * found. + * @reject {UnsupportedError} Cue points are not supported with the current + * player or browser. + */ + + /** + * Remove a cue point from the video. + * + * @param {string} id The id of the cue point to remove. + * @return {RemoveCuePointPromise} + */ + + }, { + key: "removeCuePoint", + value: function removeCuePoint(id) { + return this.callMethod('removeCuePoint', id); + } + /** + * A representation of a text track on a video. + * + * @typedef {Object} VimeoTextTrack + * @property {string} language The ISO language code. + * @property {string} kind The kind of track it is (captions or subtitles). + * @property {string} label The human‐readable label for the track. + */ + + /** + * A promise to enable a text track. + * + * @promise EnableTextTrackPromise + * @fulfill {VimeoTextTrack} The text track that was enabled. + * @reject {InvalidTrackLanguageError} No track was available with the + * specified language. + * @reject {InvalidTrackError} No track was available with the specified + * language and kind. + */ + + /** + * Enable the text track with the specified language, and optionally the + * specified kind (captions or subtitles). + * + * When set via the API, the track language will not change the viewer’s + * stored preference. + * + * @param {string} language The two‐letter language code. + * @param {string} [kind] The kind of track to enable (captions or subtitles). + * @return {EnableTextTrackPromise} + */ + + }, { + key: "enableTextTrack", + value: function enableTextTrack(language, kind) { + if (!language) { + throw new TypeError('You must pass a language.'); + } + + return this.callMethod('enableTextTrack', { + language: language, + kind: kind + }); + } + /** + * A promise to disable the active text track. + * + * @promise DisableTextTrackPromise + * @fulfill {void} The track was disabled. + */ + + /** + * Disable the currently-active text track. + * + * @return {DisableTextTrackPromise} + */ + + }, { + key: "disableTextTrack", + value: function disableTextTrack() { + return this.callMethod('disableTextTrack'); + } + /** + * A promise to pause the video. + * + * @promise PausePromise + * @fulfill {void} The video was paused. + */ + + /** + * Pause the video if it’s playing. + * + * @return {PausePromise} + */ + + }, { + key: "pause", + value: function pause() { + return this.callMethod('pause'); + } + /** + * A promise to play the video. + * + * @promise PlayPromise + * @fulfill {void} The video was played. + */ + + /** + * Play the video if it’s paused. **Note:** on iOS and some other + * mobile devices, you cannot programmatically trigger play. Once the + * viewer has tapped on the play button in the player, however, you + * will be able to use this function. + * + * @return {PlayPromise} + */ + + }, { + key: "play", + value: function play() { + return this.callMethod('play'); + } + /** + * A promise to unload the video. + * + * @promise UnloadPromise + * @fulfill {void} The video was unloaded. + */ + + /** + * Return the player to its initial state. + * + * @return {UnloadPromise} + */ + + }, { + key: "unload", + value: function unload() { + return this.callMethod('unload'); + } + /** + * Cleanup the player and remove it from the DOM + * + * It won't be usable and a new one should be constructed + * in order to do any operations. + * + * @return {Promise} + */ + + }, { + key: "destroy", + value: function destroy() { + var _this5 = this; + + return new npo_src(function (resolve) { + readyMap.delete(_this5); + playerMap.delete(_this5.element); + + if (_this5._originalElement) { + playerMap.delete(_this5._originalElement); + + _this5._originalElement.removeAttribute('data-vimeo-initialized'); + } + + if (_this5.element && _this5.element.nodeName === 'IFRAME' && _this5.element.parentNode) { + _this5.element.parentNode.removeChild(_this5.element); + } + + resolve(); + }); + } + /** + * A promise to get the autopause behavior of the video. + * + * @promise GetAutopausePromise + * @fulfill {boolean} Whether autopause is turned on or off. + * @reject {UnsupportedError} Autopause is not supported with the current + * player or browser. + */ + + /** + * Get the autopause behavior for this player. + * + * @return {GetAutopausePromise} + */ + + }, { + key: "getAutopause", + value: function getAutopause() { + return this.get('autopause'); + } + /** + * A promise to set the autopause behavior of the video. + * + * @promise SetAutopausePromise + * @fulfill {boolean} Whether autopause is turned on or off. + * @reject {UnsupportedError} Autopause is not supported with the current + * player or browser. + */ + + /** + * Enable or disable the autopause behavior of this player. + * + * By default, when another video is played in the same browser, this + * player will automatically pause. Unless you have a specific reason + * for doing so, we recommend that you leave autopause set to the + * default (`true`). + * + * @param {boolean} autopause + * @return {SetAutopausePromise} + */ + + }, { + key: "setAutopause", + value: function setAutopause(autopause) { + return this.set('autopause', autopause); + } + /** + * A promise to get the buffered property of the video. + * + * @promise GetBufferedPromise + * @fulfill {Array} Buffered Timeranges converted to an Array. + */ + + /** + * Get the buffered property of the video. + * + * @return {GetBufferedPromise} + */ + + }, { + key: "getBuffered", + value: function getBuffered() { + return this.get('buffered'); + } + /** + * A promise to get the color of the player. + * + * @promise GetColorPromise + * @fulfill {string} The hex color of the player. + */ + + /** + * Get the color for this player. + * + * @return {GetColorPromise} + */ + + }, { + key: "getColor", + value: function getColor() { + return this.get('color'); + } + /** + * A promise to set the color of the player. + * + * @promise SetColorPromise + * @fulfill {string} The color was successfully set. + * @reject {TypeError} The string was not a valid hex or rgb color. + * @reject {ContrastError} The color was set, but the contrast is + * outside of the acceptable range. + * @reject {EmbedSettingsError} The owner of the player has chosen to + * use a specific color. + */ + + /** + * Set the color of this player to a hex or rgb string. Setting the + * color may fail if the owner of the video has set their embed + * preferences to force a specific color. + * + * @param {string} color The hex or rgb color string to set. + * @return {SetColorPromise} + */ + + }, { + key: "setColor", + value: function setColor(color) { + return this.set('color', color); + } + /** + * A representation of a cue point. + * + * @typedef {Object} VimeoCuePoint + * @property {number} time The time of the cue point. + * @property {object} data The data passed when adding the cue point. + * @property {string} id The unique id for use with removeCuePoint. + */ + + /** + * A promise to get the cue points of a video. + * + * @promise GetCuePointsPromise + * @fulfill {VimeoCuePoint[]} The cue points added to the video. + * @reject {UnsupportedError} Cue points are not supported with the current + * player or browser. + */ + + /** + * Get an array of the cue points added to the video. + * + * @return {GetCuePointsPromise} + */ + + }, { + key: "getCuePoints", + value: function getCuePoints() { + return this.get('cuePoints'); + } + /** + * A promise to get the current time of the video. + * + * @promise GetCurrentTimePromise + * @fulfill {number} The current time in seconds. + */ + + /** + * Get the current playback position in seconds. + * + * @return {GetCurrentTimePromise} + */ + + }, { + key: "getCurrentTime", + value: function getCurrentTime() { + return this.get('currentTime'); + } + /** + * A promise to set the current time of the video. + * + * @promise SetCurrentTimePromise + * @fulfill {number} The actual current time that was set. + * @reject {RangeError} the time was less than 0 or greater than the + * video’s duration. + */ + + /** + * Set the current playback position in seconds. If the player was + * paused, it will remain paused. Likewise, if the player was playing, + * it will resume playing once the video has buffered. + * + * You can provide an accurate time and the player will attempt to seek + * to as close to that time as possible. The exact time will be the + * fulfilled value of the promise. + * + * @param {number} currentTime + * @return {SetCurrentTimePromise} + */ + + }, { + key: "setCurrentTime", + value: function setCurrentTime(currentTime) { + return this.set('currentTime', currentTime); + } + /** + * A promise to get the duration of the video. + * + * @promise GetDurationPromise + * @fulfill {number} The duration in seconds. + */ + + /** + * Get the duration of the video in seconds. It will be rounded to the + * nearest second before playback begins, and to the nearest thousandth + * of a second after playback begins. + * + * @return {GetDurationPromise} + */ + + }, { + key: "getDuration", + value: function getDuration() { + return this.get('duration'); + } + /** + * A promise to get the ended state of the video. + * + * @promise GetEndedPromise + * @fulfill {boolean} Whether or not the video has ended. + */ + + /** + * Get the ended state of the video. The video has ended if + * `currentTime === duration`. + * + * @return {GetEndedPromise} + */ + + }, { + key: "getEnded", + value: function getEnded() { + return this.get('ended'); + } + /** + * A promise to get the loop state of the player. + * + * @promise GetLoopPromise + * @fulfill {boolean} Whether or not the player is set to loop. + */ + + /** + * Get the loop state of the player. + * + * @return {GetLoopPromise} + */ + + }, { + key: "getLoop", + value: function getLoop() { + return this.get('loop'); + } + /** + * A promise to set the loop state of the player. + * + * @promise SetLoopPromise + * @fulfill {boolean} The loop state that was set. + */ + + /** + * Set the loop state of the player. When set to `true`, the player + * will start over immediately once playback ends. + * + * @param {boolean} loop + * @return {SetLoopPromise} + */ + + }, { + key: "setLoop", + value: function setLoop(loop) { + return this.set('loop', loop); + } + /** + * A promise to set the muted state of the player. + * + * @promise SetMutedPromise + * @fulfill {boolean} The muted state that was set. + */ + + /** + * Set the muted state of the player. When set to `true`, the player + * volume will be muted. + * + * @param {boolean} muted + * @return {SetMutedPromise} + */ + + }, { + key: "setMuted", + value: function setMuted(muted) { + return this.set('muted', muted); + } + /** + * A promise to get the muted state of the player. + * + * @promise GetMutedPromise + * @fulfill {boolean} Whether or not the player is muted. + */ + + /** + * Get the muted state of the player. + * + * @return {GetMutedPromise} + */ + + }, { + key: "getMuted", + value: function getMuted() { + return this.get('muted'); + } + /** + * A promise to get the paused state of the player. + * + * @promise GetLoopPromise + * @fulfill {boolean} Whether or not the video is paused. + */ + + /** + * Get the paused state of the player. + * + * @return {GetLoopPromise} + */ + + }, { + key: "getPaused", + value: function getPaused() { + return this.get('paused'); + } + /** + * A promise to get the playback rate of the player. + * + * @promise GetPlaybackRatePromise + * @fulfill {number} The playback rate of the player on a scale from 0.5 to 2. + */ + + /** + * Get the playback rate of the player on a scale from `0.5` to `2`. + * + * @return {GetPlaybackRatePromise} + */ + + }, { + key: "getPlaybackRate", + value: function getPlaybackRate() { + return this.get('playbackRate'); + } + /** + * A promise to set the playbackrate of the player. + * + * @promise SetPlaybackRatePromise + * @fulfill {number} The playback rate was set. + * @reject {RangeError} The playback rate was less than 0.5 or greater than 2. + */ + + /** + * Set the playback rate of the player on a scale from `0.5` to `2`. When set + * via the API, the playback rate will not be synchronized to other + * players or stored as the viewer's preference. + * + * @param {number} playbackRate + * @return {SetPlaybackRatePromise} + */ + + }, { + key: "setPlaybackRate", + value: function setPlaybackRate(playbackRate) { + return this.set('playbackRate', playbackRate); + } + /** + * A promise to get the played property of the video. + * + * @promise GetPlayedPromise + * @fulfill {Array} Played Timeranges converted to an Array. + */ + + /** + * Get the played property of the video. + * + * @return {GetPlayedPromise} + */ + + }, { + key: "getPlayed", + value: function getPlayed() { + return this.get('played'); + } + /** + * A promise to get the seekable property of the video. + * + * @promise GetSeekablePromise + * @fulfill {Array} Seekable Timeranges converted to an Array. + */ + + /** + * Get the seekable property of the video. + * + * @return {GetSeekablePromise} + */ + + }, { + key: "getSeekable", + value: function getSeekable() { + return this.get('seekable'); + } + /** + * A promise to get the seeking property of the player. + * + * @promise GetSeekingPromise + * @fulfill {boolean} Whether or not the player is currently seeking. + */ + + /** + * Get if the player is currently seeking. + * + * @return {GetSeekingPromise} + */ + + }, { + key: "getSeeking", + value: function getSeeking() { + return this.get('seeking'); + } + /** + * A promise to get the text tracks of a video. + * + * @promise GetTextTracksPromise + * @fulfill {VimeoTextTrack[]} The text tracks associated with the video. + */ + + /** + * Get an array of the text tracks that exist for the video. + * + * @return {GetTextTracksPromise} + */ + + }, { + key: "getTextTracks", + value: function getTextTracks() { + return this.get('textTracks'); + } + /** + * A promise to get the embed code for the video. + * + * @promise GetVideoEmbedCodePromise + * @fulfill {string} The `