diff --git a/dist/player.es.js b/dist/player.es.js index 5defa04c4..854e0dabc 100644 --- a/dist/player.es.js +++ b/dist/player.es.js @@ -1,4 +1,4 @@ -/*! @vimeo/player v2.7.0 | (c) 2019 Vimeo | MIT License | https://github.com/vimeo/player.js */ +/*! @vimeo/player v2.8.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"); @@ -1883,6 +1883,24 @@ function () { 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. * diff --git a/dist/player.js b/dist/player.js index 9fd4543d1..9bfa20574 100644 --- a/dist/player.js +++ b/dist/player.js @@ -1,9 +1,9 @@ -/*! @vimeo/player v2.7.0 | (c) 2019 Vimeo | MIT License | https://github.com/vimeo/player.js */ +/*! @vimeo/player v2.8.0 | (c) 2019 Vimeo | MIT License | https://github.com/vimeo/player.js */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : - (global.Vimeo = global.Vimeo || {}, global.Vimeo.Player = factory()); -}(this, (function () { 'use strict'; + (global = global || self, (global.Vimeo = global.Vimeo || {}, global.Vimeo.Player = factory())); +}(this, function () { 'use strict'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { @@ -1889,6 +1889,24 @@ 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. * @@ -2077,6 +2095,6 @@ return Player; -}))); +})); //# sourceMappingURL=player.js.map \ No newline at end of file diff --git a/dist/player.js.map b/dist/player.js.map index 755a633ea..f236fdb61 100644 --- a/dist/player.js.map +++ b/dist/player.js.map @@ -1 +1 @@ -{"version":3,"file":"player.js","sources":["src/lib/functions.js","src/lib/compatibility-check.js","node_modules/weakmap-polyfill/weakmap-polyfill.js","node_modules/native-promise-only/lib/npo.src.js","src/lib/callbacks.js","src/lib/embed.js","src/lib/postmessage.js","src/player.js"],"sourcesContent":["/**\n * @module lib/functions\n */\n\n/**\n * Check to see this is a node environment.\n * @type {Boolean}\n */\n/* global global */\nexport const isNode = typeof global !== 'undefined' &&\n ({}).toString.call(global) === '[object global]';\n\n/**\n * Get the name of the method for a given getter or setter.\n *\n * @param {string} prop The name of the property.\n * @param {string} type Either “get” or “set”.\n * @return {string}\n */\nexport function getMethodName(prop, type) {\n if (prop.indexOf(type.toLowerCase()) === 0) {\n return prop;\n }\n\n return `${type.toLowerCase()}${prop.substr(0, 1).toUpperCase()}${prop.substr(1)}`;\n}\n\n/**\n * Check to see if the object is a DOM Element.\n *\n * @param {*} element The object to check.\n * @return {boolean}\n */\nexport function isDomElement(element) {\n return Boolean(\n element && element.nodeType === 1 && 'nodeName' in element &&\n element.ownerDocument && element.ownerDocument.defaultView\n );\n}\n\n/**\n * Check to see whether the value is a number.\n *\n * @see http://dl.dropboxusercontent.com/u/35146/js/tests/isNumber.html\n * @param {*} value The value to check.\n * @param {boolean} integer Check if the value is an integer.\n * @return {boolean}\n */\nexport function isInteger(value) {\n // eslint-disable-next-line eqeqeq\n return !isNaN(parseFloat(value)) && isFinite(value) && Math.floor(value) == value;\n}\n\n/**\n * Check to see if the URL is a Vimeo url.\n *\n * @param {string} url The url string.\n * @return {boolean}\n */\nexport function isVimeoUrl(url) {\n return (/^(https?:)?\\/\\/((player|www)\\.)?vimeo\\.com(?=$|\\/)/).test(url);\n}\n\n/**\n * Get the Vimeo URL from an element.\n * The element must have either a data-vimeo-id or data-vimeo-url attribute.\n *\n * @param {object} oEmbedParameters The oEmbed parameters.\n * @return {string}\n */\nexport function getVimeoUrl(oEmbedParameters = {}) {\n const id = oEmbedParameters.id;\n const url = oEmbedParameters.url;\n const idOrUrl = id || url;\n\n if (!idOrUrl) {\n 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.');\n }\n\n if (isInteger(idOrUrl)) {\n return `https://vimeo.com/${idOrUrl}`;\n }\n\n if (isVimeoUrl(idOrUrl)) {\n return idOrUrl.replace('http:', 'https:');\n }\n\n if (id) {\n throw new TypeError(`“${id}” is not a valid video id.`);\n }\n\n throw new TypeError(`“${idOrUrl}” is not a vimeo.com url.`);\n}\n","import { isNode } from './functions';\n\nconst arrayIndexOfSupport = typeof Array.prototype.indexOf !== 'undefined';\nconst postMessageSupport = typeof window !== 'undefined' && typeof window.postMessage !== 'undefined';\n\nif (!isNode && (!arrayIndexOfSupport || !postMessageSupport)) {\n throw new Error('Sorry, the Vimeo Player API is not available in this browser.');\n}\n","/*!\n * weakmap-polyfill v2.0.0 - ECMAScript6 WeakMap polyfill\n * https://github.com/polygonplanet/weakmap-polyfill\n * Copyright (c) 2015-2016 polygon planet \n * @license MIT\n */\n\n(function(self) {\n 'use strict';\n\n if (self.WeakMap) {\n return;\n }\n\n var hasOwnProperty = Object.prototype.hasOwnProperty;\n var defineProperty = function(object, name, value) {\n if (Object.defineProperty) {\n Object.defineProperty(object, name, {\n configurable: true,\n writable: true,\n value: value\n });\n } else {\n object[name] = value;\n }\n };\n\n self.WeakMap = (function() {\n\n // ECMA-262 23.3 WeakMap Objects\n function WeakMap() {\n if (this === void 0) {\n throw new TypeError(\"Constructor WeakMap requires 'new'\");\n }\n\n defineProperty(this, '_id', genId('_WeakMap'));\n\n // ECMA-262 23.3.1.1 WeakMap([iterable])\n if (arguments.length > 0) {\n // Currently, WeakMap `iterable` argument is not supported\n throw new TypeError('WeakMap iterable is not supported');\n }\n }\n\n // ECMA-262 23.3.3.2 WeakMap.prototype.delete(key)\n defineProperty(WeakMap.prototype, 'delete', function(key) {\n checkInstance(this, 'delete');\n\n if (!isObject(key)) {\n return false;\n }\n\n var entry = key[this._id];\n if (entry && entry[0] === key) {\n delete key[this._id];\n return true;\n }\n\n return false;\n });\n\n // ECMA-262 23.3.3.3 WeakMap.prototype.get(key)\n defineProperty(WeakMap.prototype, 'get', function(key) {\n checkInstance(this, 'get');\n\n if (!isObject(key)) {\n return void 0;\n }\n\n var entry = key[this._id];\n if (entry && entry[0] === key) {\n return entry[1];\n }\n\n return void 0;\n });\n\n // ECMA-262 23.3.3.4 WeakMap.prototype.has(key)\n defineProperty(WeakMap.prototype, 'has', function(key) {\n checkInstance(this, 'has');\n\n if (!isObject(key)) {\n return false;\n }\n\n var entry = key[this._id];\n if (entry && entry[0] === key) {\n return true;\n }\n\n return false;\n });\n\n // ECMA-262 23.3.3.5 WeakMap.prototype.set(key, value)\n defineProperty(WeakMap.prototype, 'set', function(key, value) {\n checkInstance(this, 'set');\n\n if (!isObject(key)) {\n throw new TypeError('Invalid value used as weak map key');\n }\n\n var entry = key[this._id];\n if (entry && entry[0] === key) {\n entry[1] = value;\n return this;\n }\n\n defineProperty(key, this._id, [key, value]);\n return this;\n });\n\n\n function checkInstance(x, methodName) {\n if (!isObject(x) || !hasOwnProperty.call(x, '_id')) {\n throw new TypeError(\n methodName + ' method called on incompatible receiver ' +\n typeof x\n );\n }\n }\n\n function genId(prefix) {\n return prefix + '_' + rand() + '.' + rand();\n }\n\n function rand() {\n return Math.random().toString().substring(2);\n }\n\n\n defineProperty(WeakMap, '_polyfill', true);\n return WeakMap;\n })();\n\n\n function isObject(x) {\n return Object(x) === x;\n }\n\n})(\n typeof self !== 'undefined' ? self :\n typeof window !== 'undefined' ? window :\n typeof global !== 'undefined' ? global : this\n);\n","/*! Native Promise Only\n v0.8.1 (c) Kyle Simpson\n MIT License: http://getify.mit-license.org\n*/\n\n(function UMD(name,context,definition){\n\t// special form of UMD for polyfilling across evironments\n\tcontext[name] = context[name] || definition();\n\tif (typeof module != \"undefined\" && module.exports) { module.exports = context[name]; }\n\telse if (typeof define == \"function\" && define.amd) { define(function $AMD$(){ return context[name]; }); }\n})(\"Promise\",typeof global != \"undefined\" ? global : this,function DEF(){\n\t/*jshint validthis:true */\n\t\"use strict\";\n\n\tvar builtInProp, cycle, scheduling_queue,\n\t\tToString = Object.prototype.toString,\n\t\ttimer = (typeof setImmediate != \"undefined\") ?\n\t\t\tfunction timer(fn) { return setImmediate(fn); } :\n\t\t\tsetTimeout\n\t;\n\n\t// dammit, IE8.\n\ttry {\n\t\tObject.defineProperty({},\"x\",{});\n\t\tbuiltInProp = function builtInProp(obj,name,val,config) {\n\t\t\treturn Object.defineProperty(obj,name,{\n\t\t\t\tvalue: val,\n\t\t\t\twritable: true,\n\t\t\t\tconfigurable: config !== false\n\t\t\t});\n\t\t};\n\t}\n\tcatch (err) {\n\t\tbuiltInProp = function builtInProp(obj,name,val) {\n\t\t\tobj[name] = val;\n\t\t\treturn obj;\n\t\t};\n\t}\n\n\t// Note: using a queue instead of array for efficiency\n\tscheduling_queue = (function Queue() {\n\t\tvar first, last, item;\n\n\t\tfunction Item(fn,self) {\n\t\t\tthis.fn = fn;\n\t\t\tthis.self = self;\n\t\t\tthis.next = void 0;\n\t\t}\n\n\t\treturn {\n\t\t\tadd: function add(fn,self) {\n\t\t\t\titem = new Item(fn,self);\n\t\t\t\tif (last) {\n\t\t\t\t\tlast.next = item;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfirst = item;\n\t\t\t\t}\n\t\t\t\tlast = item;\n\t\t\t\titem = void 0;\n\t\t\t},\n\t\t\tdrain: function drain() {\n\t\t\t\tvar f = first;\n\t\t\t\tfirst = last = cycle = void 0;\n\n\t\t\t\twhile (f) {\n\t\t\t\t\tf.fn.call(f.self);\n\t\t\t\t\tf = f.next;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t})();\n\n\tfunction schedule(fn,self) {\n\t\tscheduling_queue.add(fn,self);\n\t\tif (!cycle) {\n\t\t\tcycle = timer(scheduling_queue.drain);\n\t\t}\n\t}\n\n\t// promise duck typing\n\tfunction isThenable(o) {\n\t\tvar _then, o_type = typeof o;\n\n\t\tif (o != null &&\n\t\t\t(\n\t\t\t\to_type == \"object\" || o_type == \"function\"\n\t\t\t)\n\t\t) {\n\t\t\t_then = o.then;\n\t\t}\n\t\treturn typeof _then == \"function\" ? _then : false;\n\t}\n\n\tfunction notify() {\n\t\tfor (var i=0; i 0) {\n\t\t\t\t\tschedule(notify,self);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (err) {\n\t\t\treject.call(new MakeDefWrapper(self),err);\n\t\t}\n\t}\n\n\tfunction reject(msg) {\n\t\tvar self = this;\n\n\t\t// already triggered?\n\t\tif (self.triggered) { return; }\n\n\t\tself.triggered = true;\n\n\t\t// unwrap\n\t\tif (self.def) {\n\t\t\tself = self.def;\n\t\t}\n\n\t\tself.msg = msg;\n\t\tself.state = 2;\n\t\tif (self.chain.length > 0) {\n\t\t\tschedule(notify,self);\n\t\t}\n\t}\n\n\tfunction iteratePromises(Constructor,arr,resolver,rejecter) {\n\t\tfor (var idx=0; idx}\n */\nexport function getOEmbedParameters(element, defaults = {}) {\n return oEmbedParameters.reduce((params, param) => {\n const value = element.getAttribute(`data-vimeo-${param}`);\n\n if (value || value === '') {\n params[param] = value === '' ? 1 : value;\n }\n\n return params;\n }, defaults);\n}\n\n/**\n * Create an embed from oEmbed data inside an element.\n *\n * @param {object} data The oEmbed data.\n * @param {HTMLElement} element The element to put the iframe in.\n * @return {HTMLIFrameElement} The iframe embed.\n */\nexport function createEmbed({ html }, element) {\n if (!element) {\n throw new TypeError('An element must be provided');\n }\n\n if (element.getAttribute('data-vimeo-initialized') !== null) {\n return element.querySelector('iframe');\n }\n\n const div = document.createElement('div');\n div.innerHTML = html;\n\n element.appendChild(div.firstChild);\n element.setAttribute('data-vimeo-initialized', 'true');\n\n return element.querySelector('iframe');\n}\n\n/**\n * Make an oEmbed call for the specified URL.\n *\n * @param {string} videoUrl The vimeo.com url for the video.\n * @param {Object} [params] Parameters to pass to oEmbed.\n * @param {HTMLElement} element The element.\n * @return {Promise}\n */\nexport function getOEmbedData(videoUrl, params = {}, element) {\n return new Promise((resolve, reject) => {\n if (!isVimeoUrl(videoUrl)) {\n throw new TypeError(`“${videoUrl}” is not a vimeo.com url.`);\n }\n\n let url = `https://vimeo.com/api/oembed.json?url=${encodeURIComponent(videoUrl)}&domain=${window.location.hostname}`;\n\n for (const param in params) {\n if (params.hasOwnProperty(param)) {\n url += `&${param}=${encodeURIComponent(params[param])}`;\n }\n }\n\n const xhr = 'XDomainRequest' in window ? new XDomainRequest() : new XMLHttpRequest();\n xhr.open('GET', url, true);\n\n xhr.onload = function() {\n if (xhr.status === 404) {\n reject(new Error(`“${videoUrl}” was not found.`));\n return;\n }\n\n if (xhr.status === 403) {\n reject(new Error(`“${videoUrl}” is not embeddable.`));\n return;\n }\n\n try {\n const json = JSON.parse(xhr.responseText);\n // Check api response for 403 on oembed\n if (json.domain_status_code === 403) {\n // We still want to create the embed to give users visual feedback\n createEmbed(json, element);\n reject(new Error(`“${videoUrl}” is not embeddable.`));\n return;\n }\n\n resolve(json);\n }\n catch (error) {\n reject(error);\n }\n };\n\n xhr.onerror = function() {\n const status = xhr.status ? ` (${xhr.status})` : '';\n reject(new Error(`There was an error fetching the embed code from Vimeo${status}.`));\n };\n\n xhr.send();\n });\n}\n\n/**\n * Initialize all embeds within a specific element\n *\n * @param {HTMLElement} [parent=document] The parent element.\n * @return {void}\n */\nexport function initializeEmbeds(parent = document) {\n const elements = [].slice.call(parent.querySelectorAll('[data-vimeo-id], [data-vimeo-url]'));\n\n const handleError = (error) => {\n if ('console' in window && console.error) {\n console.error(`There was an error creating an embed: ${error}`);\n }\n };\n\n elements.forEach((element) => {\n try {\n // Skip any that have data-vimeo-defer\n if (element.getAttribute('data-vimeo-defer') !== null) {\n return;\n }\n\n const params = getOEmbedParameters(element);\n const url = getVimeoUrl(params);\n\n getOEmbedData(url, params, element).then((data) => {\n return createEmbed(data, element);\n }).catch(handleError);\n }\n catch (error) {\n handleError(error);\n }\n });\n}\n\n/**\n * Resize embeds when messaged by the player.\n *\n * @param {HTMLElement} [parent=document] The parent element.\n * @return {void}\n */\nexport function resizeEmbeds(parent = document) {\n // Prevent execution if users include the player.js script multiple times.\n if (window.VimeoPlayerResizeEmbeds_) {\n return;\n }\n window.VimeoPlayerResizeEmbeds_ = true;\n\n const onMessage = (event) => {\n if (!isVimeoUrl(event.origin)) {\n return;\n }\n\n // 'spacechange' is fired only on embeds with cards\n if (!event.data || event.data.event !== 'spacechange') {\n return;\n }\n\n const iframes = parent.querySelectorAll('iframe');\n\n for (let i = 0; i < iframes.length; i++) {\n if (iframes[i].contentWindow !== event.source) {\n continue;\n }\n\n // Change padding-bottom of the enclosing div to accommodate\n // card carousel without distorting aspect ratio\n const space = iframes[i].parentElement;\n space.style.paddingBottom = `${event.data.data[0].bottom}px`;\n\n break;\n }\n };\n\n if (window.addEventListener) {\n window.addEventListener('message', onMessage, false);\n }\n else if (window.attachEvent) {\n window.attachEvent('onmessage', onMessage);\n }\n}\n","/**\n * @module lib/postmessage\n */\n\nimport { getCallbacks, removeCallback, shiftCallbacks } from './callbacks';\n\n/**\n * Parse a message received from postMessage.\n *\n * @param {*} data The data received from postMessage.\n * @return {object}\n */\nexport function parseMessageData(data) {\n if (typeof data === 'string') {\n data = JSON.parse(data);\n }\n\n return data;\n}\n\n/**\n * Post a message to the specified target.\n *\n * @param {Player} player The player object to use.\n * @param {string} method The API method to call.\n * @param {object} params The parameters to send to the player.\n * @return {void}\n */\nexport function postMessage(player, method, params) {\n if (!player.element.contentWindow || !player.element.contentWindow.postMessage) {\n return;\n }\n\n let message = {\n method\n };\n\n if (params !== undefined) {\n message.value = params;\n }\n\n // IE 8 and 9 do not support passing messages, so stringify them\n const ieVersion = parseFloat(navigator.userAgent.toLowerCase().replace(/^.*msie (\\d+).*$/, '$1'));\n if (ieVersion >= 8 && ieVersion < 10) {\n message = JSON.stringify(message);\n }\n\n player.element.contentWindow.postMessage(message, player.origin);\n}\n\n/**\n * Parse the data received from a message event.\n *\n * @param {Player} player The player that received the message.\n * @param {(Object|string)} data The message data. Strings will be parsed into JSON.\n * @return {void}\n */\nexport function processData(player, data) {\n data = parseMessageData(data);\n let callbacks = [];\n let param;\n\n if (data.event) {\n if (data.event === 'error') {\n const promises = getCallbacks(player, data.data.method);\n\n promises.forEach((promise) => {\n const error = new Error(data.data.message);\n error.name = data.data.name;\n\n promise.reject(error);\n removeCallback(player, data.data.method, promise);\n });\n }\n\n callbacks = getCallbacks(player, `event:${data.event}`);\n param = data.data;\n }\n else if (data.method) {\n const callback = shiftCallbacks(player, data.method);\n\n if (callback) {\n callbacks.push(callback);\n param = data.value;\n }\n }\n\n callbacks.forEach((callback) => {\n try {\n if (typeof callback === 'function') {\n callback.call(player, param);\n return;\n }\n\n callback.resolve(param);\n }\n catch (e) {\n // empty\n }\n });\n}\n","import './lib/compatibility-check';\n\nimport 'weakmap-polyfill';\nimport Promise from 'native-promise-only';\n\nimport { storeCallback, getCallbacks, removeCallback, swapCallbacks } from './lib/callbacks';\nimport { getMethodName, isDomElement, isVimeoUrl, getVimeoUrl, isNode } from './lib/functions';\nimport { getOEmbedParameters, getOEmbedData, createEmbed, initializeEmbeds, resizeEmbeds } from './lib/embed';\nimport { parseMessageData, postMessage, processData } from './lib/postmessage';\n\nconst playerMap = new WeakMap();\nconst readyMap = new WeakMap();\n\nclass Player {\n /**\n * Create a Player.\n *\n * @param {(HTMLIFrameElement|HTMLElement|string|jQuery)} element A reference to the Vimeo\n * player iframe, and id, or a jQuery object.\n * @param {object} [options] oEmbed parameters to use when creating an embed in the element.\n * @return {Player}\n */\n constructor(element, options = {}) {\n /* global jQuery */\n if (window.jQuery && element instanceof jQuery) {\n if (element.length > 1 && window.console && console.warn) {\n console.warn('A jQuery object with multiple elements was passed, using the first element.');\n }\n\n element = element[0];\n }\n\n // Find an element by ID\n if (typeof document !== 'undefined' && typeof element === 'string') {\n element = document.getElementById(element);\n }\n\n // Not an element!\n if (!isDomElement(element)) {\n throw new TypeError('You must pass either a valid element or a valid id.');\n }\n\n const win = element.ownerDocument.defaultView;\n\n // Already initialized an embed in this div, so grab the iframe\n if (element.nodeName !== 'IFRAME') {\n const iframe = element.querySelector('iframe');\n\n if (iframe) {\n element = iframe;\n }\n }\n\n // iframe url is not a Vimeo url\n if (element.nodeName === 'IFRAME' && !isVimeoUrl(element.getAttribute('src') || '')) {\n throw new Error('The player element passed isn’t a Vimeo embed.');\n }\n\n // If there is already a player object in the map, return that\n if (playerMap.has(element)) {\n return playerMap.get(element);\n }\n\n this.element = element;\n this.origin = '*';\n\n const readyPromise = new Promise((resolve, reject) => {\n const onMessage = (event) => {\n if (!isVimeoUrl(event.origin) || this.element.contentWindow !== event.source) {\n return;\n }\n\n if (this.origin === '*') {\n this.origin = event.origin;\n }\n\n const data = parseMessageData(event.data);\n const isError = data && data.event === 'error';\n const isReadyError = isError && data.data && data.data.method === 'ready';\n\n if (isReadyError) {\n const error = new Error(data.data.message);\n error.name = data.data.name;\n reject(error);\n return;\n }\n\n const isReadyEvent = data && data.event === 'ready';\n const isPingResponse = data && data.method === 'ping';\n\n if (isReadyEvent || isPingResponse) {\n this.element.setAttribute('data-ready', 'true');\n resolve();\n return;\n }\n\n processData(this, data);\n };\n\n if (win.addEventListener) {\n win.addEventListener('message', onMessage, false);\n }\n else if (win.attachEvent) {\n win.attachEvent('onmessage', onMessage);\n }\n\n if (this.element.nodeName !== 'IFRAME') {\n const params = getOEmbedParameters(element, options);\n const url = getVimeoUrl(params);\n\n getOEmbedData(url, params, element).then((data) => {\n const iframe = createEmbed(data, element);\n // Overwrite element with the new iframe,\n // but store reference to the original element\n this.element = iframe;\n this._originalElement = element;\n\n swapCallbacks(element, iframe);\n playerMap.set(this.element, this);\n\n return data;\n }).catch(reject);\n }\n });\n\n // Store a copy of this Player in the map\n readyMap.set(this, readyPromise);\n playerMap.set(this.element, this);\n\n // Send a ping to the iframe so the ready promise will be resolved if\n // the player is already ready.\n if (this.element.nodeName === 'IFRAME') {\n postMessage(this, 'ping');\n }\n\n return this;\n }\n\n /**\n * Get a promise for a method.\n *\n * @param {string} name The API method to call.\n * @param {Object} [args={}] Arguments to send via postMessage.\n * @return {Promise}\n */\n callMethod(name, args = {}) {\n return new Promise((resolve, reject) => {\n // We are storing the resolve/reject handlers to call later, so we\n // can’t return here.\n // eslint-disable-next-line promise/always-return\n return this.ready().then(() => {\n storeCallback(this, name, {\n resolve,\n reject\n });\n\n postMessage(this, name, args);\n }).catch(reject);\n });\n }\n\n /**\n * Get a promise for the value of a player property.\n *\n * @param {string} name The property name\n * @return {Promise}\n */\n get(name) {\n return new Promise((resolve, reject) => {\n name = getMethodName(name, 'get');\n\n // We are storing the resolve/reject handlers to call later, so we\n // can’t return here.\n // eslint-disable-next-line promise/always-return\n return this.ready().then(() => {\n storeCallback(this, name, {\n resolve,\n reject\n });\n\n postMessage(this, name);\n }).catch(reject);\n });\n }\n\n /**\n * Get a promise for setting the value of a player property.\n *\n * @param {string} name The API method to call.\n * @param {mixed} value The value to set.\n * @return {Promise}\n */\n set(name, value) {\n return new Promise((resolve, reject) => {\n name = getMethodName(name, 'set');\n\n if (value === undefined || value === null) {\n throw new TypeError('There must be a value to set.');\n }\n\n // We are storing the resolve/reject handlers to call later, so we\n // can’t return here.\n // eslint-disable-next-line promise/always-return\n return this.ready().then(() => {\n storeCallback(this, name, {\n resolve,\n reject\n });\n\n postMessage(this, name, value);\n }).catch(reject);\n });\n }\n\n /**\n * Add an event listener for the specified event. Will call the\n * callback with a single parameter, `data`, that contains the data for\n * that event.\n *\n * @param {string} eventName The name of the event.\n * @param {function(*)} callback The function to call when the event fires.\n * @return {void}\n */\n on(eventName, callback) {\n if (!eventName) {\n throw new TypeError('You must pass an event name.');\n }\n\n if (!callback) {\n throw new TypeError('You must pass a callback function.');\n }\n\n if (typeof callback !== 'function') {\n throw new TypeError('The callback must be a function.');\n }\n\n const callbacks = getCallbacks(this, `event:${eventName}`);\n if (callbacks.length === 0) {\n this.callMethod('addEventListener', eventName).catch(() => {\n // Ignore the error. There will be an error event fired that\n // will trigger the error callback if they are listening.\n });\n }\n\n storeCallback(this, `event:${eventName}`, callback);\n }\n\n /**\n * Remove an event listener for the specified event. Will remove all\n * listeners for that event if a `callback` isn’t passed, or only that\n * specific callback if it is passed.\n *\n * @param {string} eventName The name of the event.\n * @param {function} [callback] The specific callback to remove.\n * @return {void}\n */\n off(eventName, callback) {\n if (!eventName) {\n throw new TypeError('You must pass an event name.');\n }\n\n if (callback && typeof callback !== 'function') {\n throw new TypeError('The callback must be a function.');\n }\n\n const lastCallback = removeCallback(this, `event:${eventName}`, callback);\n\n // If there are no callbacks left, remove the listener\n if (lastCallback) {\n this.callMethod('removeEventListener', eventName).catch((e) => {\n // Ignore the error. There will be an error event fired that\n // will trigger the error callback if they are listening.\n });\n }\n }\n\n /**\n * A promise to load a new video.\n *\n * @promise LoadVideoPromise\n * @fulfill {number} The video with this id successfully loaded.\n * @reject {TypeError} The id was not a number.\n */\n /**\n * Load a new video into this embed. The promise will be resolved if\n * the video is successfully loaded, or it will be rejected if it could\n * not be loaded.\n *\n * @param {number|object} options The id of the video or an object with embed options.\n * @return {LoadVideoPromise}\n */\n loadVideo(options) {\n return this.callMethod('loadVideo', options);\n }\n\n /**\n * A promise to perform an action when the Player is ready.\n *\n * @todo document errors\n * @promise LoadVideoPromise\n * @fulfill {void}\n */\n /**\n * Trigger a function when the player iframe has initialized. You do not\n * need to wait for `ready` to trigger to begin adding event listeners\n * or calling other methods.\n *\n * @return {ReadyPromise}\n */\n ready() {\n const readyPromise = readyMap.get(this) || new Promise((resolve, reject) => {\n reject(new Error('Unknown player. Probably unloaded.'));\n });\n return Promise.resolve(readyPromise);\n }\n\n /**\n * A promise to add a cue point to the player.\n *\n * @promise AddCuePointPromise\n * @fulfill {string} The id of the cue point to use for removeCuePoint.\n * @reject {RangeError} the time was less than 0 or greater than the\n * video’s duration.\n * @reject {UnsupportedError} Cue points are not supported with the current\n * player or browser.\n */\n /**\n * Add a cue point to the player.\n *\n * @param {number} time The time for the cue point.\n * @param {object} [data] Arbitrary data to be returned with the cue point.\n * @return {AddCuePointPromise}\n */\n addCuePoint(time, data = {}) {\n return this.callMethod('addCuePoint', { time, data });\n }\n\n /**\n * A promise to remove a cue point from the player.\n *\n * @promise AddCuePointPromise\n * @fulfill {string} The id of the cue point that was removed.\n * @reject {InvalidCuePoint} The cue point with the specified id was not\n * found.\n * @reject {UnsupportedError} Cue points are not supported with the current\n * player or browser.\n */\n /**\n * Remove a cue point from the video.\n *\n * @param {string} id The id of the cue point to remove.\n * @return {RemoveCuePointPromise}\n */\n removeCuePoint(id) {\n return this.callMethod('removeCuePoint', id);\n }\n\n /**\n * A representation of a text track on a video.\n *\n * @typedef {Object} VimeoTextTrack\n * @property {string} language The ISO language code.\n * @property {string} kind The kind of track it is (captions or subtitles).\n * @property {string} label The human‐readable label for the track.\n */\n /**\n * A promise to enable a text track.\n *\n * @promise EnableTextTrackPromise\n * @fulfill {VimeoTextTrack} The text track that was enabled.\n * @reject {InvalidTrackLanguageError} No track was available with the\n * specified language.\n * @reject {InvalidTrackError} No track was available with the specified\n * language and kind.\n */\n /**\n * Enable the text track with the specified language, and optionally the\n * specified kind (captions or subtitles).\n *\n * When set via the API, the track language will not change the viewer’s\n * stored preference.\n *\n * @param {string} language The two‐letter language code.\n * @param {string} [kind] The kind of track to enable (captions or subtitles).\n * @return {EnableTextTrackPromise}\n */\n enableTextTrack(language, kind) {\n if (!language) {\n throw new TypeError('You must pass a language.');\n }\n\n return this.callMethod('enableTextTrack', {\n language,\n kind\n });\n }\n\n /**\n * A promise to disable the active text track.\n *\n * @promise DisableTextTrackPromise\n * @fulfill {void} The track was disabled.\n */\n /**\n * Disable the currently-active text track.\n *\n * @return {DisableTextTrackPromise}\n */\n disableTextTrack() {\n return this.callMethod('disableTextTrack');\n }\n\n /**\n * A promise to pause the video.\n *\n * @promise PausePromise\n * @fulfill {void} The video was paused.\n */\n /**\n * Pause the video if it’s playing.\n *\n * @return {PausePromise}\n */\n pause() {\n return this.callMethod('pause');\n }\n\n /**\n * A promise to play the video.\n *\n * @promise PlayPromise\n * @fulfill {void} The video was played.\n */\n /**\n * Play the video if it’s paused. **Note:** on iOS and some other\n * mobile devices, you cannot programmatically trigger play. Once the\n * viewer has tapped on the play button in the player, however, you\n * will be able to use this function.\n *\n * @return {PlayPromise}\n */\n play() {\n return this.callMethod('play');\n }\n\n /**\n * A promise to unload the video.\n *\n * @promise UnloadPromise\n * @fulfill {void} The video was unloaded.\n */\n /**\n * Return the player to its initial state.\n *\n * @return {UnloadPromise}\n */\n unload() {\n return this.callMethod('unload');\n }\n\n /**\n * Cleanup the player and remove it from the DOM\n *\n * It won't be usable and a new one should be constructed\n * in order to do any operations.\n *\n * @return {Promise}\n */\n destroy() {\n return new Promise((resolve) => {\n readyMap.delete(this);\n playerMap.delete(this.element);\n if (this._originalElement) {\n playerMap.delete(this._originalElement);\n this._originalElement.removeAttribute('data-vimeo-initialized');\n }\n if (this.element && this.element.nodeName === 'IFRAME' && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n resolve();\n });\n }\n\n /**\n * A promise to get the autopause behavior of the video.\n *\n * @promise GetAutopausePromise\n * @fulfill {boolean} Whether autopause is turned on or off.\n * @reject {UnsupportedError} Autopause is not supported with the current\n * player or browser.\n */\n /**\n * Get the autopause behavior for this player.\n *\n * @return {GetAutopausePromise}\n */\n getAutopause() {\n return this.get('autopause');\n }\n\n /**\n * A promise to set the autopause behavior of the video.\n *\n * @promise SetAutopausePromise\n * @fulfill {boolean} Whether autopause is turned on or off.\n * @reject {UnsupportedError} Autopause is not supported with the current\n * player or browser.\n */\n /**\n * Enable or disable the autopause behavior of this player.\n *\n * By default, when another video is played in the same browser, this\n * player will automatically pause. Unless you have a specific reason\n * for doing so, we recommend that you leave autopause set to the\n * default (`true`).\n *\n * @param {boolean} autopause\n * @return {SetAutopausePromise}\n */\n setAutopause(autopause) {\n return this.set('autopause', autopause);\n }\n\n /**\n * A promise to get the buffered property of the video.\n *\n * @promise GetBufferedPromise\n * @fulfill {Array} Buffered Timeranges converted to an Array.\n */\n /**\n * Get the buffered property of the video.\n *\n * @return {GetBufferedPromise}\n */\n getBuffered() {\n return this.get('buffered');\n }\n\n /**\n * A promise to get the color of the player.\n *\n * @promise GetColorPromise\n * @fulfill {string} The hex color of the player.\n */\n /**\n * Get the color for this player.\n *\n * @return {GetColorPromise}\n */\n getColor() {\n return this.get('color');\n }\n\n /**\n * A promise to set the color of the player.\n *\n * @promise SetColorPromise\n * @fulfill {string} The color was successfully set.\n * @reject {TypeError} The string was not a valid hex or rgb color.\n * @reject {ContrastError} The color was set, but the contrast is\n * outside of the acceptable range.\n * @reject {EmbedSettingsError} The owner of the player has chosen to\n * use a specific color.\n */\n /**\n * Set the color of this player to a hex or rgb string. Setting the\n * color may fail if the owner of the video has set their embed\n * preferences to force a specific color.\n *\n * @param {string} color The hex or rgb color string to set.\n * @return {SetColorPromise}\n */\n setColor(color) {\n return this.set('color', color);\n }\n\n /**\n * A representation of a cue point.\n *\n * @typedef {Object} VimeoCuePoint\n * @property {number} time The time of the cue point.\n * @property {object} data The data passed when adding the cue point.\n * @property {string} id The unique id for use with removeCuePoint.\n */\n /**\n * A promise to get the cue points of a video.\n *\n * @promise GetCuePointsPromise\n * @fulfill {VimeoCuePoint[]} The cue points added to the video.\n * @reject {UnsupportedError} Cue points are not supported with the current\n * player or browser.\n */\n /**\n * Get an array of the cue points added to the video.\n *\n * @return {GetCuePointsPromise}\n */\n getCuePoints() {\n return this.get('cuePoints');\n }\n\n /**\n * A promise to get the current time of the video.\n *\n * @promise GetCurrentTimePromise\n * @fulfill {number} The current time in seconds.\n */\n /**\n * Get the current playback position in seconds.\n *\n * @return {GetCurrentTimePromise}\n */\n getCurrentTime() {\n return this.get('currentTime');\n }\n\n /**\n * A promise to set the current time of the video.\n *\n * @promise SetCurrentTimePromise\n * @fulfill {number} The actual current time that was set.\n * @reject {RangeError} the time was less than 0 or greater than the\n * video’s duration.\n */\n /**\n * Set the current playback position in seconds. If the player was\n * paused, it will remain paused. Likewise, if the player was playing,\n * it will resume playing once the video has buffered.\n *\n * You can provide an accurate time and the player will attempt to seek\n * to as close to that time as possible. The exact time will be the\n * fulfilled value of the promise.\n *\n * @param {number} currentTime\n * @return {SetCurrentTimePromise}\n */\n setCurrentTime(currentTime) {\n return this.set('currentTime', currentTime);\n }\n\n /**\n * A promise to get the duration of the video.\n *\n * @promise GetDurationPromise\n * @fulfill {number} The duration in seconds.\n */\n /**\n * Get the duration of the video in seconds. It will be rounded to the\n * nearest second before playback begins, and to the nearest thousandth\n * of a second after playback begins.\n *\n * @return {GetDurationPromise}\n */\n getDuration() {\n return this.get('duration');\n }\n\n /**\n * A promise to get the ended state of the video.\n *\n * @promise GetEndedPromise\n * @fulfill {boolean} Whether or not the video has ended.\n */\n /**\n * Get the ended state of the video. The video has ended if\n * `currentTime === duration`.\n *\n * @return {GetEndedPromise}\n */\n getEnded() {\n return this.get('ended');\n }\n\n /**\n * A promise to get the loop state of the player.\n *\n * @promise GetLoopPromise\n * @fulfill {boolean} Whether or not the player is set to loop.\n */\n /**\n * Get the loop state of the player.\n *\n * @return {GetLoopPromise}\n */\n getLoop() {\n return this.get('loop');\n }\n\n /**\n * A promise to set the loop state of the player.\n *\n * @promise SetLoopPromise\n * @fulfill {boolean} The loop state that was set.\n */\n /**\n * Set the loop state of the player. When set to `true`, the player\n * will start over immediately once playback ends.\n *\n * @param {boolean} loop\n * @return {SetLoopPromise}\n */\n setLoop(loop) {\n return this.set('loop', loop);\n }\n\n /**\n * A promise to get the paused state of the player.\n *\n * @promise GetLoopPromise\n * @fulfill {boolean} Whether or not the video is paused.\n */\n /**\n * Get the paused state of the player.\n *\n * @return {GetLoopPromise}\n */\n getPaused() {\n return this.get('paused');\n }\n\n /**\n * A promise to get the playback rate of the player.\n *\n * @promise GetPlaybackRatePromise\n * @fulfill {number} The playback rate of the player on a scale from 0.5 to 2.\n */\n /**\n * Get the playback rate of the player on a scale from `0.5` to `2`.\n *\n * @return {GetPlaybackRatePromise}\n */\n getPlaybackRate() {\n return this.get('playbackRate');\n }\n\n /**\n * A promise to set the playbackrate of the player.\n *\n * @promise SetPlaybackRatePromise\n * @fulfill {number} The playback rate was set.\n * @reject {RangeError} The playback rate was less than 0.5 or greater than 2.\n */\n /**\n * Set the playback rate of the player on a scale from `0.5` to `2`. When set\n * via the API, the playback rate will not be synchronized to other\n * players or stored as the viewer's preference.\n *\n * @param {number} playbackRate\n * @return {SetPlaybackRatePromise}\n */\n setPlaybackRate(playbackRate) {\n return this.set('playbackRate', playbackRate);\n }\n\n /**\n * A promise to get the played property of the video.\n *\n * @promise GetPlayedPromise\n * @fulfill {Array} Played Timeranges converted to an Array.\n */\n /**\n * Get the played property of the video.\n *\n * @return {GetPlayedPromise}\n */\n getPlayed() {\n return this.get('played');\n }\n\n /**\n * A promise to get the seekable property of the video.\n *\n * @promise GetSeekablePromise\n * @fulfill {Array} Seekable Timeranges converted to an Array.\n */\n /**\n * Get the seekable property of the video.\n *\n * @return {GetSeekablePromise}\n */\n getSeekable() {\n return this.get('seekable');\n }\n\n /**\n * A promise to get the text tracks of a video.\n *\n * @promise GetTextTracksPromise\n * @fulfill {VimeoTextTrack[]} The text tracks associated with the video.\n */\n /**\n * Get an array of the text tracks that exist for the video.\n *\n * @return {GetTextTracksPromise}\n */\n getTextTracks() {\n return this.get('textTracks');\n }\n\n /**\n * A promise to get the embed code for the video.\n *\n * @promise GetVideoEmbedCodePromise\n * @fulfill {string} The `