diff options
author | Sam Potts <sam@potts.es> | 2017-11-04 23:18:47 +1100 |
---|---|---|
committer | Sam Potts <sam@potts.es> | 2017-11-04 23:18:47 +1100 |
commit | 3c99357f0619b7b9116a5a14ea4bc571dbbefb8c (patch) | |
tree | 24680afe040060ef412f6baaf19c041e6dd6f0e3 /src | |
parent | a757acad15745edb7c8a10697c58834226f57971 (diff) | |
download | plyr-3c99357f0619b7b9116a5a14ea4bc571dbbefb8c.tar.lz plyr-3c99357f0619b7b9116a5a14ea4bc571dbbefb8c.tar.xz plyr-3c99357f0619b7b9116a5a14ea4bc571dbbefb8c.zip |
Vimeo fixes + small bug fixes
Diffstat (limited to 'src')
-rw-r--r-- | src/js/plyr.js | 1131 | ||||
-rw-r--r-- | src/less/plyr.less | 45 |
2 files changed, 566 insertions, 610 deletions
diff --git a/src/js/plyr.js b/src/js/plyr.js index 6fee2bf0..900281b1 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -1,6 +1,6 @@ -// ========================================================================== +// ========================================================================== // Plyr -// plyr.js v2.0.16 +// plyr.js v2.0.17 // https://github.com/sampotts/plyr // License: The MIT License (MIT) // ========================================================================== @@ -8,13 +8,13 @@ // ========================================================================== (function(root, factory) { - "use strict"; + 'use strict'; /*global define,module*/ - if (typeof module === "object" && typeof module.exports === "object") { + if (typeof module === 'object' && typeof module.exports === 'object') { // Node, CommonJS-like module.exports = factory(root, document); - } else if (typeof define === "function" && define.amd) { + } else if (typeof define === 'function' && define.amd) { // AMD define([], function() { return factory(root, document); @@ -23,8 +23,8 @@ // Browser globals (root is window) root.plyr = factory(root, document); } -})(typeof window !== "undefined" ? window : this, function(window, document) { - "use strict"; +})(typeof window !== 'undefined' ? window : this, function(window, document) { + 'use strict'; // Globals var fullscreen, @@ -43,31 +43,31 @@ duration: null, displayDuration: true, loadSprite: true, - iconPrefix: "plyr", - iconUrl: "https://cdn.plyr.io/2.0.16/plyr.svg", - blankUrl: "https://cdn.plyr.io/static/blank.mp4", + iconPrefix: 'plyr', + iconUrl: 'https://cdn.plyr.io/2.0.17/plyr.svg', + blankUrl: 'https://cdn.plyr.io/static/blank.mp4', clickToPlay: true, hideControls: true, showPosterOnEnd: false, disableContextMenu: true, keyboardShorcuts: { focused: true, - global: false + global: false, }, tooltips: { controls: false, - seek: true + seek: true, }, selectors: { - html5: "video, audio", - embed: "[data-type]", - editable: "input, textarea, select, [contenteditable]", - container: ".plyr", + html5: 'video, audio', + embed: '[data-type]', + editable: 'input, textarea, select, [contenteditable]', + container: '.plyr', controls: { container: null, - wrapper: ".plyr__controls" + wrapper: '.plyr__controls', }, - labels: "[data-plyr]", + labels: '[data-plyr]', buttons: { seek: '[data-plyr="seek"]', play: '[data-plyr="play"]', @@ -77,92 +77,92 @@ forward: '[data-plyr="fast-forward"]', mute: '[data-plyr="mute"]', captions: '[data-plyr="captions"]', - fullscreen: '[data-plyr="fullscreen"]' + fullscreen: '[data-plyr="fullscreen"]', }, volume: { input: '[data-plyr="volume"]', - display: ".plyr__volume--display" + display: '.plyr__volume--display', }, progress: { - container: ".plyr__progress", - buffer: ".plyr__progress--buffer", - played: ".plyr__progress--played" + container: '.plyr__progress', + buffer: '.plyr__progress--buffer', + played: '.plyr__progress--played', }, - captions: ".plyr__captions", - currentTime: ".plyr__time--current", - duration: ".plyr__time--duration" + captions: '.plyr__captions', + currentTime: '.plyr__time--current', + duration: '.plyr__time--duration', }, classes: { - setup: "plyr--setup", - ready: "plyr--ready", - videoWrapper: "plyr__video-wrapper", - embedWrapper: "plyr__video-embed", - type: "plyr--{0}", - stopped: "plyr--stopped", - playing: "plyr--playing", - muted: "plyr--muted", - loading: "plyr--loading", - hover: "plyr--hover", - tooltip: "plyr__tooltip", - hidden: "plyr__sr-only", - hideControls: "plyr--hide-controls", - isIos: "plyr--is-ios", - isTouch: "plyr--is-touch", + setup: 'plyr--setup', + ready: 'plyr--ready', + videoWrapper: 'plyr__video-wrapper', + embedWrapper: 'plyr__video-embed', + type: 'plyr--{0}', + stopped: 'plyr--stopped', + playing: 'plyr--playing', + muted: 'plyr--muted', + loading: 'plyr--loading', + hover: 'plyr--hover', + tooltip: 'plyr__tooltip', + hidden: 'plyr__sr-only', + hideControls: 'plyr--hide-controls', + isIos: 'plyr--is-ios', + isTouch: 'plyr--is-touch', captions: { - enabled: "plyr--captions-enabled", - active: "plyr--captions-active" + enabled: 'plyr--captions-enabled', + active: 'plyr--captions-active', }, fullscreen: { - enabled: "plyr--fullscreen-enabled", - fallback: "plyr--fullscreen-fallback", - active: "plyr--fullscreen-active" + enabled: 'plyr--fullscreen-enabled', + fallback: 'plyr--fullscreen-fallback', + active: 'plyr--fullscreen-active', }, - tabFocus: "tab-focus" + tabFocus: 'tab-focus', }, captions: { - defaultActive: false + defaultActive: false, }, fullscreen: { enabled: true, fallback: true, - allowAudio: false + allowAudio: false, }, storage: { enabled: true, - key: "plyr" + key: 'plyr', }, - controls: ["play-large", "play", "progress", "current-time", "mute", "volume", "captions", "fullscreen"], + controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'captions', 'fullscreen'], i18n: { - restart: "Restart", - rewind: "Rewind {seektime} secs", - play: "Play", - pause: "Pause", - forward: "Forward {seektime} secs", - played: "played", - buffered: "buffered", - currentTime: "Current time", - duration: "Duration", - volume: "Volume", - toggleMute: "Toggle Mute", - toggleCaptions: "Toggle Captions", - toggleFullscreen: "Toggle Fullscreen", - frameTitle: "Player for {title}" + restart: 'Restart', + rewind: 'Rewind {seektime} secs', + play: 'Play', + pause: 'Pause', + forward: 'Forward {seektime} secs', + played: 'played', + buffered: 'buffered', + currentTime: 'Current time', + duration: 'Duration', + volume: 'Volume', + toggleMute: 'Toggle Mute', + toggleCaptions: 'Toggle Captions', + toggleFullscreen: 'Toggle Fullscreen', + frameTitle: 'Player for {title}', }, types: { - embed: ["youtube", "vimeo", "soundcloud"], - html5: ["video", "audio"] + embed: ['youtube', 'vimeo', 'soundcloud'], + html5: ['video', 'audio'], }, // URLs urls: { vimeo: { - api: "https://player.vimeo.com/api/player.js" + api: 'https://player.vimeo.com/api/player.js', }, youtube: { - api: "https://www.youtube.com/iframe_api" + api: 'https://www.youtube.com/iframe_api', }, soundcloud: { - api: "https://w.soundcloud.com/player/api.js" - } + api: 'https://w.soundcloud.com/player/api.js', + }, }, // Custom control listeners listeners: { @@ -175,32 +175,32 @@ mute: null, volume: null, captions: null, - fullscreen: null + fullscreen: null, }, // Events to watch on HTML5 media elements events: [ - "ready", - "ended", - "progress", - "stalled", - "playing", - "waiting", - "canplay", - "canplaythrough", - "loadstart", - "loadeddata", - "loadedmetadata", - "timeupdate", - "volumechange", - "play", - "pause", - "error", - "seeking", - "seeked", - "emptied" + 'ready', + 'ended', + 'progress', + 'stalled', + 'playing', + 'waiting', + 'canplay', + 'canplaythrough', + 'loadstart', + 'loadeddata', + 'loadedmetadata', + 'timeupdate', + 'volumechange', + 'play', + 'pause', + 'error', + 'seeking', + 'seeked', + 'emptied', ], // Logging - logPrefix: "[Plyr]" + logPrefix: '[Plyr]', }; // Credits: http://paypal.github.io/accessible-html5-video-player/ @@ -208,7 +208,7 @@ function _browserSniff() { var ua = navigator.userAgent, name = navigator.appName, - fullVersion = "" + parseFloat(navigator.appVersion), + fullVersion = '' + parseFloat(navigator.appVersion), majorVersion = parseInt(navigator.appVersion, 10), nameOffset, verOffset, @@ -218,35 +218,35 @@ isChrome = false, isSafari = false; - if (navigator.appVersion.indexOf("Windows NT") !== -1 && navigator.appVersion.indexOf("rv:11") !== -1) { + if (navigator.appVersion.indexOf('Windows NT') !== -1 && navigator.appVersion.indexOf('rv:11') !== -1) { // MSIE 11 isIE = true; - name = "IE"; - fullVersion = "11"; - } else if ((verOffset = ua.indexOf("MSIE")) !== -1) { + name = 'IE'; + fullVersion = '11'; + } else if ((verOffset = ua.indexOf('MSIE')) !== -1) { // MSIE isIE = true; - name = "IE"; + name = 'IE'; fullVersion = ua.substring(verOffset + 5); - } else if ((verOffset = ua.indexOf("Chrome")) !== -1) { + } else if ((verOffset = ua.indexOf('Chrome')) !== -1) { // Chrome isChrome = true; - name = "Chrome"; + name = 'Chrome'; fullVersion = ua.substring(verOffset + 7); - } else if ((verOffset = ua.indexOf("Safari")) !== -1) { + } else if ((verOffset = ua.indexOf('Safari')) !== -1) { // Safari isSafari = true; - name = "Safari"; + name = 'Safari'; fullVersion = ua.substring(verOffset + 7); - if ((verOffset = ua.indexOf("Version")) !== -1) { + if ((verOffset = ua.indexOf('Version')) !== -1) { fullVersion = ua.substring(verOffset + 8); } - } else if ((verOffset = ua.indexOf("Firefox")) !== -1) { + } else if ((verOffset = ua.indexOf('Firefox')) !== -1) { // Firefox isFirefox = true; - name = "Firefox"; + name = 'Firefox'; fullVersion = ua.substring(verOffset + 8); - } else if ((nameOffset = ua.lastIndexOf(" ") + 1) < (verOffset = ua.lastIndexOf("/"))) { + } else if ((nameOffset = ua.lastIndexOf(' ') + 1) < (verOffset = ua.lastIndexOf('/'))) { // In most other browsers, 'name/version' is at the end of userAgent name = ua.substring(nameOffset, verOffset); fullVersion = ua.substring(verOffset + 1); @@ -257,17 +257,17 @@ } // Trim the fullVersion string at semicolon/space if present - if ((ix = fullVersion.indexOf(";")) !== -1) { + if ((ix = fullVersion.indexOf(';')) !== -1) { fullVersion = fullVersion.substring(0, ix); } - if ((ix = fullVersion.indexOf(" ")) !== -1) { + if ((ix = fullVersion.indexOf(' ')) !== -1) { fullVersion = fullVersion.substring(0, ix); } // Get major version - majorVersion = parseInt("" + fullVersion, 10); + majorVersion = parseInt('' + fullVersion, 10); if (isNaN(majorVersion)) { - fullVersion = "" + parseFloat(navigator.appVersion); + fullVersion = '' + parseFloat(navigator.appVersion); majorVersion = parseInt(navigator.appVersion, 10); } @@ -281,7 +281,7 @@ isSafari: isSafari, isIos: /(iPad|iPhone|iPod)/g.test(navigator.platform), isIphone: /(iPhone|iPod)/g.test(navigator.userAgent), - isTouch: "ontouchstart" in document.documentElement + isTouch: 'ontouchstart' in document.documentElement, }; } @@ -291,30 +291,25 @@ function _supportMime(plyr, mimeType) { var media = plyr.media; - if (plyr.type === "video") { + if (plyr.type === 'video') { // Check type switch (mimeType) { - case "video/webm": - return !!( - media.canPlayType && media.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/, "") - ); - case "video/mp4": - return !!( - media.canPlayType && - media.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, "") - ); - case "video/ogg": - return !!(media.canPlayType && media.canPlayType('video/ogg; codecs="theora"').replace(/no/, "")); - } - } else if (plyr.type === "audio") { + case 'video/webm': + return !!(media.canPlayType && media.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/, '')); + case 'video/mp4': + return !!(media.canPlayType && media.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, '')); + case 'video/ogg': + return !!(media.canPlayType && media.canPlayType('video/ogg; codecs="theora"').replace(/no/, '')); + } + } else if (plyr.type === 'audio') { // Check type switch (mimeType) { - case "audio/mpeg": - return !!(media.canPlayType && media.canPlayType("audio/mpeg;").replace(/no/, "")); - case "audio/ogg": - return !!(media.canPlayType && media.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, "")); - case "audio/wav": - return !!(media.canPlayType && media.canPlayType('audio/wav; codecs="1"').replace(/no/, "")); + case 'audio/mpeg': + return !!(media.canPlayType && media.canPlayType('audio/mpeg;').replace(/no/, '')); + case 'audio/ogg': + return !!(media.canPlayType && media.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, '')); + case 'audio/wav': + return !!(media.canPlayType && media.canPlayType('audio/wav; codecs="1"').replace(/no/, '')); } } @@ -328,9 +323,9 @@ return; } - var tag = document.createElement("script"); + var tag = document.createElement('script'); tag.src = source; - var firstScriptTag = document.getElementsByTagName("script")[0]; + var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); } @@ -341,7 +336,7 @@ // Replace all function _replaceAll(string, find, replace) { - return string.replace(new RegExp(find.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, "\\$1"), "g"), replace); + return string.replace(new RegExp(find.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, '\\$1'), 'g'), replace); } // Wrap an element @@ -409,7 +404,7 @@ // Set attributes function _setAttributes(element, attributes) { for (var key in attributes) { - element.setAttribute(key, _is.boolean(attributes[key]) && attributes[key] ? "" : attributes[key]); + element.setAttribute(key, _is.boolean(attributes[key]) && attributes[key] ? '' : attributes[key]); } } @@ -427,17 +422,17 @@ // Get a classname from selector function _getClassname(selector) { - return selector.replace(".", ""); + return selector.replace('.', ''); } // Toggle class on an element function _toggleClass(element, className, state) { if (element) { if (element.classList) { - element.classList[state ? "add" : "remove"](className); + element.classList[state ? 'add' : 'remove'](className); } else { - var name = (" " + element.className + " ").replace(/\s+/g, " ").replace(" " + className + " ", ""); - element.className = name + (state ? " " + className : ""); + var name = (' ' + element.className + ' ').replace(/\s+/g, ' ').replace(' ' + className + ' ', ''); + element.className = name + (state ? ' ' + className : ''); } } } @@ -448,7 +443,7 @@ if (element.classList) { return element.classList.contains(className); } else { - return new RegExp("(\\s|^)" + className + "(\\s|$)").test(element.className); + return new RegExp('(\\s|^)' + className + '(\\s|$)').test(element.className); } } return false; @@ -472,7 +467,7 @@ // Bind along with custom handler function _proxyListener(element, eventName, userListener, defaultListener, useCapture) { - if(userListener) { + if (userListener) { // Register this before defaultListener _on( element, @@ -495,7 +490,7 @@ // Toggle event listener function _toggleListener(element, events, callback, toggle, useCapture) { - var eventList = events.split(" "); + var eventList = events.split(' '); // Whether the listener is a capturing listener or not // Default to false @@ -515,7 +510,7 @@ // If a single node is passed, bind the event listener for (var i = 0; i < eventList.length; i++) { - element[toggle ? "addEventListener" : "removeEventListener"](eventList[i], callback, useCapture); + element[toggle ? 'addEventListener' : 'removeEventListener'](eventList[i], callback, useCapture); } } @@ -548,7 +543,7 @@ // Create and dispatch the event var event = new CustomEvent(type, { bubbles: bubbles, - detail: properties + detail: properties, }); // Dispatch the event @@ -564,10 +559,10 @@ } // Get state - state = _is.boolean(state) ? state : !target.getAttribute("aria-pressed"); + state = _is.boolean(state) ? state : !target.getAttribute('aria-pressed'); // Set the attribute on target - target.setAttribute("aria-pressed", state); + target.setAttribute('aria-pressed', state); return state; } @@ -621,26 +616,19 @@ // Check variable types var _is = { object: function(input) { - return input !== null && typeof input === "object"; + return input !== null && typeof input === 'object'; }, array: function(input) { - return input !== null && (typeof input === "object" && input.constructor === Array); + return input !== null && (typeof input === 'object' && input.constructor === Array); }, number: function(input) { - return ( - input !== null && - ((typeof input === "number" && !isNaN(input - 0)) || - (typeof input === "object" && input.constructor === Number)) - ); + return input !== null && ((typeof input === 'number' && !isNaN(input - 0)) || (typeof input === 'object' && input.constructor === Number)); }, string: function(input) { - return ( - input !== null && - (typeof input === "string" || (typeof input === "object" && input.constructor === String)) - ); + return input !== null && (typeof input === 'string' || (typeof input === 'object' && input.constructor === String)); }, boolean: function(input) { - return input !== null && typeof input === "boolean"; + return input !== null && typeof input === 'boolean'; }, nodeList: function(input) { return input !== null && input instanceof NodeList; @@ -649,11 +637,11 @@ return input !== null && input instanceof HTMLElement; }, function: function(input) { - return input !== null && typeof input === "function"; + return input !== null && typeof input === 'function'; }, undefined: function(input) { - return input !== null && typeof input === "undefined"; - } + return input !== null && typeof input === 'undefined'; + }, }; // Parse YouTube ID from url @@ -662,10 +650,10 @@ return url.match(regex) ? RegExp.$2 : url; } - // Is this a Vimeo url link? - function _isVimeoUrl(url) { + // Parse Vimeo ID from url + function _parseVimeoId(url) { var regex = /^.*(vimeo.com\/|video\/)(\d+).*/; - return url.match(regex); + return url.match(regex) ? RegExp.$2 : url; } // Fullscreen API @@ -677,11 +665,11 @@ }, requestFullScreen: function() {}, cancelFullScreen: function() {}, - fullScreenEventName: "", + fullScreenEventName: '', element: null, - prefix: "" + prefix: '', }, - browserPrefixes = "webkit o moz ms khtml".split(" "); + browserPrefixes = 'webkit o moz ms khtml'.split(' '); // Check for native support if (!_is.undefined(document.cancelFullScreen)) { @@ -691,12 +679,12 @@ for (var i = 0, il = browserPrefixes.length; i < il; i++) { fullscreen.prefix = browserPrefixes[i]; - if (!_is.undefined(document[fullscreen.prefix + "CancelFullScreen"])) { + if (!_is.undefined(document[fullscreen.prefix + 'CancelFullScreen'])) { fullscreen.supportsFullScreen = true; break; } else if (!_is.undefined(document.msExitFullscreen) && document.msFullscreenEnabled) { // Special case for MS (when isn't it?) - fullscreen.prefix = "ms"; + fullscreen.prefix = 'ms'; fullscreen.supportsFullScreen = true; break; } @@ -707,37 +695,36 @@ if (fullscreen.supportsFullScreen) { // Yet again Microsoft awesomeness, // Sometimes the prefix is 'ms', sometimes 'MS' to keep you on your toes - fullscreen.fullScreenEventName = - fullscreen.prefix === "ms" ? "MSFullscreenChange" : fullscreen.prefix + "fullscreenchange"; + fullscreen.fullScreenEventName = fullscreen.prefix === 'ms' ? 'MSFullscreenChange' : fullscreen.prefix + 'fullscreenchange'; fullscreen.isFullScreen = function(element) { if (_is.undefined(element)) { element = document.body; } switch (this.prefix) { - case "": + case '': return document.fullscreenElement === element; - case "moz": + case 'moz': return document.mozFullScreenElement === element; default: - return document[this.prefix + "FullscreenElement"] === element; + return document[this.prefix + 'FullscreenElement'] === element; } }; fullscreen.requestFullScreen = function(element) { if (_is.undefined(element)) { element = document.body; } - return this.prefix === "" + return this.prefix === '' ? element.requestFullScreen() - : element[this.prefix + (this.prefix === "ms" ? "RequestFullscreen" : "RequestFullScreen")](); + : element[this.prefix + (this.prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')](); }; fullscreen.cancelFullScreen = function() { - return this.prefix === "" + return this.prefix === '' ? document.cancelFullScreen() - : document[this.prefix + (this.prefix === "ms" ? "ExitFullscreen" : "CancelFullScreen")](); + : document[this.prefix + (this.prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen')](); }; fullscreen.element = function() { - return this.prefix === "" ? document.fullscreenElement : document[this.prefix + "FullscreenElement"]; + return this.prefix === '' ? document.fullscreenElement : document[this.prefix + 'FullscreenElement']; }; } @@ -751,22 +738,22 @@ // see: https://github.com/sampotts/plyr/issues/131 try { // Add test item - window.localStorage.setItem("___test", "OK"); + window.localStorage.setItem('___test', 'OK'); // Get the test item - var result = window.localStorage.getItem("___test"); + var result = window.localStorage.getItem('___test'); // Clean up - window.localStorage.removeItem("___test"); + window.localStorage.removeItem('___test'); // Check if value matches - return result === "OK"; + return result === 'OK'; } catch (e) { return false; } return false; - })() + })(), }; // Player instance @@ -786,7 +773,7 @@ type, bubbles, _extend({}, properties, { - plyr: api + plyr: api, }) ); } @@ -804,21 +791,21 @@ } } var _log = function() { - _console("log", arguments); + _console('log', arguments); }, _warn = function() { - _console("warn", arguments); + _console('warn', arguments); }; // Log config options - _log("Config", config); + _log('Config', config); // Get icon URL function _getIconUrl() { return { - url: config.iconUrl, + url: config.iconUrl, // If you're using svg4everybody you don't need absolute paths - absolute: config.iconUrl.indexOf("http") === 0 || (plyr.browser.isIE && !window.svg4everybody) + absolute: config.iconUrl.indexOf('http') === 0 || (plyr.browser.isIE && !window.svg4everybody), }; } @@ -827,67 +814,67 @@ // Create html array var html = [], iconUrl = _getIconUrl(), - iconPath = (!iconUrl.absolute ? iconUrl.url : "") + "#" + config.iconPrefix; + iconPath = (!iconUrl.absolute ? iconUrl.url : '') + '#' + config.iconPrefix; // Larger overlaid play button - if (_inArray(config.controls, "play-large")) { + if (_inArray(config.controls, 'play-large')) { html.push( '<button type="button" data-plyr="play" class="plyr__play-large">', '<svg><use xlink:href="' + iconPath + '-play" /></svg>', - '<span class="plyr__sr-only">' + config.i18n.play + "</span>", - "</button>" + '<span class="plyr__sr-only">' + config.i18n.play + '</span>', + '</button>' ); } html.push('<div class="plyr__controls">'); // Restart button - if (_inArray(config.controls, "restart")) { + if (_inArray(config.controls, 'restart')) { html.push( '<button type="button" data-plyr="restart">', '<svg><use xlink:href="' + iconPath + '-restart" /></svg>', - '<span class="plyr__sr-only">' + config.i18n.restart + "</span>", - "</button>" + '<span class="plyr__sr-only">' + config.i18n.restart + '</span>', + '</button>' ); } // Rewind button - if (_inArray(config.controls, "rewind")) { + if (_inArray(config.controls, 'rewind')) { html.push( '<button type="button" data-plyr="rewind">', '<svg><use xlink:href="' + iconPath + '-rewind" /></svg>', - '<span class="plyr__sr-only">' + config.i18n.rewind + "</span>", - "</button>" + '<span class="plyr__sr-only">' + config.i18n.rewind + '</span>', + '</button>' ); } // Play Pause button // TODO: This should be a toggle button really? - if (_inArray(config.controls, "play")) { + if (_inArray(config.controls, 'play')) { html.push( '<button type="button" data-plyr="play">', '<svg><use xlink:href="' + iconPath + '-play" /></svg>', - '<span class="plyr__sr-only">' + config.i18n.play + "</span>", - "</button>", + '<span class="plyr__sr-only">' + config.i18n.play + '</span>', + '</button>', '<button type="button" data-plyr="pause">', '<svg><use xlink:href="' + iconPath + '-pause" /></svg>', - '<span class="plyr__sr-only">' + config.i18n.pause + "</span>", - "</button>" + '<span class="plyr__sr-only">' + config.i18n.pause + '</span>', + '</button>' ); } // Fast forward button - if (_inArray(config.controls, "fast-forward")) { + if (_inArray(config.controls, 'fast-forward')) { html.push( '<button type="button" data-plyr="fast-forward">', '<svg><use xlink:href="' + iconPath + '-fast-forward" /></svg>', - '<span class="plyr__sr-only">' + config.i18n.forward + "</span>", - "</button>" + '<span class="plyr__sr-only">' + config.i18n.forward + '</span>', + '</button>' ); } // Progress - if (_inArray(config.controls, "progress")) { + if (_inArray(config.controls, 'progress')) { // Create progress html.push( '<span class="plyr__progress">', @@ -895,8 +882,8 @@ '<input id="seek{id}" class="plyr__progress--seek" type="range" min="0" max="100" step="0.1" value="0" data-plyr="seek">', '<progress class="plyr__progress--played" max="100" value="0" role="presentation"></progress>', '<progress class="plyr__progress--buffer" max="100" value="0">', - "<span>0</span>% " + config.i18n.buffered, - "</progress>" + '<span>0</span>% ' + config.i18n.buffered, + '</progress>' ); // Seek tooltip @@ -905,45 +892,45 @@ } // Close - html.push("</span>"); + html.push('</span>'); } // Media current time display - if (_inArray(config.controls, "current-time")) { + if (_inArray(config.controls, 'current-time')) { html.push( '<span class="plyr__time">', - '<span class="plyr__sr-only">' + config.i18n.currentTime + "</span>", + '<span class="plyr__sr-only">' + config.i18n.currentTime + '</span>', '<span class="plyr__time--current">00:00</span>', - "</span>" + '</span>' ); } // Media duration display - if (_inArray(config.controls, "duration")) { + if (_inArray(config.controls, 'duration')) { html.push( '<span class="plyr__time">', - '<span class="plyr__sr-only">' + config.i18n.duration + "</span>", + '<span class="plyr__sr-only">' + config.i18n.duration + '</span>', '<span class="plyr__time--duration">00:00</span>', - "</span>" + '</span>' ); } // Toggle mute button - if (_inArray(config.controls, "mute")) { + if (_inArray(config.controls, 'mute')) { html.push( '<button type="button" data-plyr="mute">', '<svg class="icon--muted"><use xlink:href="' + iconPath + '-muted" /></svg>', '<svg><use xlink:href="' + iconPath + '-volume" /></svg>', - '<span class="plyr__sr-only">' + config.i18n.toggleMute + "</span>", - "</button>" + '<span class="plyr__sr-only">' + config.i18n.toggleMute + '</span>', + '</button>' ); } // Volume range control - if (_inArray(config.controls, "volume")) { + if (_inArray(config.controls, 'volume')) { html.push( '<span class="plyr__volume">', - '<label for="volume{id}" class="plyr__sr-only">' + config.i18n.volume + "</label>", + '<label for="volume{id}" class="plyr__sr-only">' + config.i18n.volume + '</label>', '<input id="volume{id}" class="plyr__volume--input" type="range" min="' + config.volumeMin + '" max="' + @@ -951,41 +938,37 @@ '" value="' + config.volume + '" data-plyr="volume">', - '<progress class="plyr__volume--display" max="' + - config.volumeMax + - '" value="' + - config.volumeMin + - '" role="presentation"></progress>', - "</span>" + '<progress class="plyr__volume--display" max="' + config.volumeMax + '" value="' + config.volumeMin + '" role="presentation"></progress>', + '</span>' ); } // Toggle captions button - if (_inArray(config.controls, "captions")) { + if (_inArray(config.controls, 'captions')) { html.push( '<button type="button" data-plyr="captions">', '<svg class="icon--captions-on"><use xlink:href="' + iconPath + '-captions-on" /></svg>', '<svg><use xlink:href="' + iconPath + '-captions-off" /></svg>', - '<span class="plyr__sr-only">' + config.i18n.toggleCaptions + "</span>", - "</button>" + '<span class="plyr__sr-only">' + config.i18n.toggleCaptions + '</span>', + '</button>' ); } // Toggle fullscreen button - if (_inArray(config.controls, "fullscreen")) { + if (_inArray(config.controls, 'fullscreen')) { html.push( '<button type="button" data-plyr="fullscreen">', '<svg class="icon--exit-fullscreen"><use xlink:href="' + iconPath + '-exit-fullscreen" /></svg>', '<svg><use xlink:href="' + iconPath + '-enter-fullscreen" /></svg>', - '<span class="plyr__sr-only">' + config.i18n.toggleFullscreen + "</span>", - "</button>" + '<span class="plyr__sr-only">' + config.i18n.toggleFullscreen + '</span>', + '</button>' ); } // Close everything - html.push("</div>"); + html.push('</div>'); - return html.join(""); + return html.join(''); } // Setup fullscreen @@ -994,12 +977,12 @@ return; } - if ((plyr.type !== "audio" || config.fullscreen.allowAudio) && config.fullscreen.enabled) { + if ((plyr.type !== 'audio' || config.fullscreen.allowAudio) && config.fullscreen.enabled) { // Check for native support var nativeSupport = fullscreen.supportsFullScreen; if (nativeSupport || (config.fullscreen.fallback && !_inFrame())) { - _log((nativeSupport ? "Native" : "Fallback") + " fullscreen enabled"); + _log((nativeSupport ? 'Native' : 'Fallback') + ' fullscreen enabled'); // Add styling hook if (!nativeSupport) { @@ -1009,7 +992,7 @@ // Add styling hook _toggleClass(plyr.container, config.classes.fullscreen.enabled, true); } else { - _log("Fullscreen not supported and fallback disabled"); + _log('Fullscreen not supported and fallback disabled'); } // Toggle state @@ -1025,16 +1008,13 @@ // Setup captions function _setupCaptions() { // Bail if not HTML5 video - if (plyr.type !== "video") { + if (plyr.type !== 'video') { return; } // Inject the container if (!_getElement(config.selectors.captions)) { - plyr.videoContainer.insertAdjacentHTML( - "afterbegin", - '<div class="' + _getClassname(config.selectors.captions) + '"></div>' - ); + plyr.videoContainer.insertAdjacentHTML('afterbegin', '<div class="' + _getClassname(config.selectors.captions) + '"></div>'); } // Determine if HTML5 textTracks is supported @@ -1044,26 +1024,26 @@ } // Get URL of caption file if exists - var captionSrc = "", + var captionSrc = '', kind, children = plyr.media.childNodes; for (var i = 0; i < children.length; i++) { - if (children[i].nodeName.toLowerCase() === "track") { + if (children[i].nodeName.toLowerCase() === 'track') { kind = children[i].kind; - if (kind === "captions" || kind === "subtitles") { - captionSrc = children[i].getAttribute("src"); + if (kind === 'captions' || kind === 'subtitles') { + captionSrc = children[i].getAttribute('src'); } } } // Record if caption file exists or not plyr.captionExists = true; - if (captionSrc === "") { + if (captionSrc === '') { plyr.captionExists = false; - _log("No caption track found"); + _log('No caption track found'); } else { - _log("Caption track found; URI: " + captionSrc); + _log('Caption track found; URI: ' + captionSrc); } // If no caption file exists, hide container for caption text @@ -1074,7 +1054,7 @@ // This doesn't seem to work in Safari 7+, so the <track> elements are removed from the dom below var tracks = plyr.media.textTracks; for (var x = 0; x < tracks.length; x++) { - tracks[x].mode = "hidden"; + tracks[x].mode = 'hidden'; } // Enable UI @@ -1082,12 +1062,9 @@ // Disable unsupported browsers than report false positive // Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1033144 - if ( - (plyr.browser.isIE && plyr.browser.version >= 10) || - (plyr.browser.isFirefox && plyr.browser.version >= 31) - ) { + if ((plyr.browser.isIE && plyr.browser.version >= 10) || (plyr.browser.isFirefox && plyr.browser.version >= 31)) { // Debugging - _log("Detected browser with known TextTrack issues - using manual fallback"); + _log('Detected browser with known TextTrack issues - using manual fallback'); // Set to false so skips to 'manual' captioning plyr.usingTextTracks = false; @@ -1096,15 +1073,15 @@ // Rendering caption tracks // Native support required - http://caniuse.com/webvtt if (plyr.usingTextTracks) { - _log("TextTracks supported"); + _log('TextTracks supported'); for (var y = 0; y < tracks.length; y++) { var track = tracks[y]; - if (track.kind === "captions" || track.kind === "subtitles") { - _on(track, "cuechange", function() { + if (track.kind === 'captions' || track.kind === 'subtitles') { + _on(track, 'cuechange', function() { // Display a cue, if there is one - if (this.activeCues[0] && "text" in this.activeCues[0]) { + if (this.activeCues[0] && 'text' in this.activeCues[0]) { _setCaption(this.activeCues[0].getCueAsHTML()); } else { _setCaption(); @@ -1114,13 +1091,13 @@ } } else { // Caption tracks not natively supported - _log("TextTracks not supported so rendering captions manually"); + _log('TextTracks not supported so rendering captions manually'); // Render captions from array at appropriate time - plyr.currentCaption = ""; + plyr.currentCaption = ''; plyr.captions = []; - if (captionSrc !== "") { + if (captionSrc !== '') { // Create XMLHttpRequest Object var xhr = new XMLHttpRequest(); @@ -1133,12 +1110,12 @@ //According to webvtt spec, line terminator consists of one of the following // CRLF (U+000D U+000A), LF (U+000A) or CR (U+000D) - var lineSeparator = "\r\n"; + var lineSeparator = '\r\n'; if (req.indexOf(lineSeparator + lineSeparator) === -1) { - if (req.indexOf("\r\r") !== -1) { - lineSeparator = "\r"; + if (req.indexOf('\r\r') !== -1) { + lineSeparator = '\r'; } else { - lineSeparator = "\n"; + lineSeparator = '\n'; } } @@ -1153,7 +1130,7 @@ index = 0; // Incase caption numbers are added - if (parts[index].indexOf(":") === -1) { + if (parts[index].indexOf(':') === -1) { index = 1; } @@ -1163,14 +1140,14 @@ // Remove first element ('VTT') plyr.captions.shift(); - _log("Successfully loaded the caption file via AJAX"); + _log('Successfully loaded the caption file via AJAX'); } else { - _warn(config.logPrefix + "There was a problem loading the caption file via AJAX"); + _warn(config.logPrefix + 'There was a problem loading the caption file via AJAX'); } } }; - xhr.open("get", captionSrc, true); + xhr.open('get', captionSrc, true); xhr.send(); } @@ -1182,14 +1159,14 @@ function _setCaption(caption) { /* jshint unused:false */ var container = _getElement(config.selectors.captions), - content = document.createElement("span"); + content = document.createElement('span'); // Empty the container - container.innerHTML = ""; + container.innerHTML = ''; // Default to empty if (_is.undefined(caption)) { - caption = ""; + caption = ''; } // Set the span content @@ -1212,11 +1189,11 @@ // Utilities for caption time codes function _timecodeCommon(tc, pos) { var tcpair = []; - tcpair = tc.split(" --> "); + tcpair = tc.split(' --> '); for (var i = 0; i < tcpair.length; i++) { // WebVTT allows for extra meta data after the timestamp line // So get rid of this if it exists - tcpair[i] = tcpair[i].replace(/(\d+:\d+:\d+\.\d+).*/, "$1"); + tcpair[i] = tcpair[i].replace(/(\d+:\d+:\d+\.\d+).*/, '$1'); } return _subTcSecs(tcpair[pos]); } @@ -1233,15 +1210,15 @@ var tc1 = [], tc2 = [], seconds; - tc1 = tc.split(","); - tc2 = tc1[0].split(":"); + tc1 = tc.split(','); + tc2 = tc1[0].split(':'); seconds = Math.floor(tc2[0] * 60 * 60) + Math.floor(tc2[1] * 60) + Math.floor(tc2[2]); return seconds; } } // If it's not video, or we're using textTracks, bail. - if (plyr.usingTextTracks || plyr.type !== "video" || !plyr.supported.full) { + if (plyr.usingTextTracks || plyr.type !== 'video' || !plyr.supported.full) { return; } @@ -1324,7 +1301,7 @@ // Trap focus inside container function _focusTrap() { - var tabbables = _getElements("input:not([disabled]), button:not([disabled])"), + var tabbables = _getElements('input:not([disabled]), button:not([disabled])'), first = tabbables[0], last = tabbables[tabbables.length - 1]; @@ -1344,7 +1321,7 @@ } // Bind the handler - _on(plyr.container, "keydown", _checkFocus); + _on(plyr.container, 'keydown', _checkFocus); } // Add elements to HTML5 media (source, tracks, etc) @@ -1366,10 +1343,10 @@ // Only load external sprite using AJAX if (iconUrl.absolute) { - _log("AJAX loading absolute SVG sprite" + (plyr.browser.isIE ? " (due to IE)" : "")); - loadSprite(iconUrl.url, "sprite-plyr"); + _log('AJAX loading absolute SVG sprite' + (plyr.browser.isIE ? ' (due to IE)' : '')); + loadSprite(iconUrl.url, 'sprite-plyr'); } else { - _log("Sprite will be used as external resource directly"); + _log('Sprite will be used as external resource directly'); } } @@ -1377,7 +1354,7 @@ var html = config.html; // Insert custom video controls - _log("Injecting custom controls"); + _log('Injecting custom controls'); // If no controls are specified, create default if (!html) { @@ -1385,13 +1362,13 @@ } // Replace seek time instances - html = _replaceAll(html, "{seektime}", config.seekTime); + html = _replaceAll(html, '{seektime}', config.seekTime); // Replace all id references with random numbers - html = _replaceAll(html, "{id}", Math.floor(Math.random() * 10000)); + html = _replaceAll(html, '{id}', Math.floor(Math.random() * 10000)); // Replace Title, if it exists - if (config.title){ + if (config.title) { html = _replaceAll(html, '{title}', config.title); } @@ -1409,15 +1386,11 @@ } // Inject controls HTML - target.insertAdjacentHTML("beforeend", html); + target.insertAdjacentHTML('beforeend', html); // Setup tooltips if (config.tooltips.controls) { - var labels = _getElements( - [config.selectors.controls.wrapper, " ", config.selectors.labels, " .", config.classes.hidden].join( - "" - ) - ); + var labels = _getElements([config.selectors.controls.wrapper, ' ', config.selectors.labels, ' .', config.classes.hidden].join('')); for (var i = labels.length - 1; i >= 0; i--) { var label = labels[i]; @@ -1454,15 +1427,13 @@ // Progress - Buffering plyr.progress.buffer = {}; plyr.progress.buffer.bar = _getElement(config.selectors.progress.buffer); - plyr.progress.buffer.text = - plyr.progress.buffer.bar && plyr.progress.buffer.bar.getElementsByTagName("span")[0]; + plyr.progress.buffer.text = plyr.progress.buffer.bar && plyr.progress.buffer.bar.getElementsByTagName('span')[0]; // Progress - Played plyr.progress.played = _getElement(config.selectors.progress.played); // Seek tooltip - plyr.progress.tooltip = - plyr.progress.container && plyr.progress.container.querySelector("." + config.classes.tooltip); + plyr.progress.tooltip = plyr.progress.container && plyr.progress.container.querySelector('.' + config.classes.tooltip); // Volume plyr.volume = {}; @@ -1476,7 +1447,7 @@ return true; } catch (e) { - _warn("It looks like there is a problem with your controls HTML"); + _warn('It looks like there is a problem with your controls HTML'); // Restore native video controls _toggleNativeControls(true); @@ -1487,15 +1458,15 @@ // Toggle style hook function _toggleStyleHook() { - _toggleClass(plyr.container, config.selectors.container.replace(".", ""), plyr.supported.full); + _toggleClass(plyr.container, config.selectors.container.replace('.', ''), plyr.supported.full); } // Toggle native controls function _toggleNativeControls(toggle) { if (toggle && _inArray(config.types.html5, plyr.type)) { - plyr.media.setAttribute("controls", ""); + plyr.media.setAttribute('controls', ''); } else { - plyr.media.removeAttribute("controls"); + plyr.media.removeAttribute('controls'); } } @@ -1506,23 +1477,23 @@ // If there's a media title set, use that for the label if (_is.string(config.title) && config.title.length) { - label += ", " + config.title; + label += ', ' + config.title; // Set container label - plyr.container.setAttribute("aria-label", config.title); + plyr.container.setAttribute('aria-label', config.title); } // If there's a play button, set label if (plyr.supported.full && plyr.buttons.play) { for (var i = plyr.buttons.play.length - 1; i >= 0; i--) { - plyr.buttons.play[i].setAttribute("aria-label", label); + plyr.buttons.play[i].setAttribute('aria-label', label); } } // Set iframe title // https://github.com/sampotts/plyr/issues/124 if (_is.htmlElement(iframe)) { - iframe.setAttribute("title", config.i18n.frameTitle.replace("{title}", config.title)); + iframe.setAttribute('title', config.i18n.frameTitle.replace('{title}', config.title)); } } @@ -1538,7 +1509,7 @@ // Clean up old volume // https://github.com/sampotts/plyr/issues/171 - window.localStorage.removeItem("plyr-volume"); + window.localStorage.removeItem('plyr-volume'); // load value from the current key value = window.localStorage.getItem(config.storage.key); @@ -1575,18 +1546,18 @@ function _setupMedia() { // If there's no media, bail if (!plyr.media) { - _warn("No media element found!"); + _warn('No media element found!'); return; } if (plyr.supported.full) { // Add type class - _toggleClass(plyr.container, config.classes.type.replace("{0}", plyr.type), true); + _toggleClass(plyr.container, config.classes.type.replace('{0}', plyr.type), true); // Add video class for embeds // This will require changes if audio embeds are added if (_inArray(config.types.embed, plyr.type)) { - _toggleClass(plyr.container, config.classes.type.replace("{0}", "video"), true); + _toggleClass(plyr.container, config.classes.type.replace('{0}', 'video'), true); } // If there's no autoplay attribute, assume the video is stopped and add state class @@ -1599,10 +1570,10 @@ _toggleClass(plyr.container, config.classes.isTouch, plyr.browser.isTouch); // Inject the player wrapper - if (plyr.type === "video") { + if (plyr.type === 'video') { // Create the wrapper div - var wrapper = document.createElement("div"); - wrapper.setAttribute("class", config.classes.videoWrapper); + var wrapper = document.createElement('div'); + wrapper.setAttribute('class', config.classes.videoWrapper); // Wrap the video in a container _wrap(plyr.media, wrapper); @@ -1620,26 +1591,19 @@ // Setup YouTube/Vimeo function _setupEmbed() { - var container = document.createElement("div"), + var container = document.createElement('div'), mediaId, mediaUrl, - id = plyr.type + "-" + Math.floor(Math.random() * 10000); + id = plyr.type + '-' + Math.floor(Math.random() * 10000); // Parse IDs from URLs if supplied switch (plyr.type) { - case "youtube": + case 'youtube': mediaId = _parseYouTubeId(plyr.embedId); break; - case "vimeo": - if (_isVimeoUrl(plyr.embedId)) { - mediaId = null; - mediaUrl = plyr.embedId; - } else { - mediaId = parseInt(plyr.embedId); - mediaUrl = null; - } - + case 'vimeo': + mediaId = _parseVimeoId(plyr.embedId); break; default: @@ -1656,12 +1620,12 @@ _toggleClass(plyr.media, config.classes.videoWrapper, true); _toggleClass(plyr.media, config.classes.embedWrapper, true); - if (plyr.type === "youtube") { + if (plyr.type === 'youtube') { // Create the YouTube container plyr.media.appendChild(container); // Set ID - container.setAttribute("id", id); + container.setAttribute('id', id); // Setup API if (_is.object(window.YT)) { @@ -1685,7 +1649,7 @@ }); }; } - } else if (plyr.type === "vimeo") { + } else if (plyr.type === 'vimeo') { // Vimeo needs an extra div to hide controls on desktop (which has full support) if (plyr.supported.full) { plyr.media.appendChild(container); @@ -1694,7 +1658,7 @@ } // Set ID - container.setAttribute("id", id); + container.setAttribute('id', id); // Load the API if not already if (!_is.object(window.Vimeo)) { @@ -1704,26 +1668,26 @@ var vimeoTimer = window.setInterval(function() { if (_is.object(window.Vimeo)) { window.clearInterval(vimeoTimer); - _vimeoReady(mediaId, mediaUrl, container); + _vimeoReady(mediaId, container); } }, 50); } else { - _vimeoReady(mediaId, mediaUrl, container); + _vimeoReady(mediaId, container); } - } else if (plyr.type === "soundcloud") { + } else if (plyr.type === 'soundcloud') { // TODO: Currently unsupported and undocumented // Inject the iframe - var soundCloud = document.createElement("iframe"); + var soundCloud = document.createElement('iframe'); // Watch for iframe load soundCloud.loaded = false; - _on(soundCloud, "load", function() { + _on(soundCloud, 'load', function() { soundCloud.loaded = true; }); _setAttributes(soundCloud, { - src: "https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/" + mediaId, - id: id + src: 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/' + mediaId, + id: id, }); container.appendChild(soundCloud); @@ -1753,7 +1717,7 @@ } // Set title - _setTitle(_getElement("iframe")); + _setTitle(_getElement('iframe')); } // Handle YouTube API ready @@ -1769,17 +1733,17 @@ showinfo: 0, iv_load_policy: 3, cc_load_policy: config.captions.defaultActive ? 1 : 0, - cc_lang_pref: "en", - wmode: "transparent", + cc_lang_pref: 'en', + wmode: 'transparent', modestbranding: 1, disablekb: 1, - origin: "*" // https://code.google.com/p/gdata-issues/issues/detail?id=5788#c45 + origin: '*', // https://code.google.com/p/gdata-issues/issues/detail?id=5788#c45 }, events: { onError: function(event) { - _triggerEvent(plyr.container, "error", true, { + _triggerEvent(plyr.container, 'error', true, { code: event.data, - embed: event.target + embed: event.target, }); }, onReady: function(event) { @@ -1809,17 +1773,17 @@ // Set the tabindex if (plyr.supported.full) { - plyr.media.querySelector("iframe").setAttribute("tabindex", "-1"); + plyr.media.querySelector('iframe').setAttribute('tabindex', '-1'); } // Update UI _embedReady(); // Trigger timeupdate - _triggerEvent(plyr.media, "timeupdate"); + _triggerEvent(plyr.media, 'timeupdate'); // Trigger timeupdate - _triggerEvent(plyr.media, "durationchange"); + _triggerEvent(plyr.media, 'durationchange'); // Reset timer window.clearInterval(timers.buffering); @@ -1831,7 +1795,7 @@ // Trigger progress only when we actually buffer something if (plyr.media.lastBuffered === null || plyr.media.lastBuffered < plyr.media.buffered) { - _triggerEvent(plyr.media, "progress"); + _triggerEvent(plyr.media, 'progress'); } // Set last buffer point @@ -1842,7 +1806,7 @@ window.clearInterval(timers.buffering); // Trigger event - _triggerEvent(plyr.media, "canplaythrough"); + _triggerEvent(plyr.media, 'canplaythrough'); } }, 200); }, @@ -1863,7 +1827,7 @@ switch (event.data) { case 0: plyr.media.paused = true; - _triggerEvent(plyr.media, "ended"); + _triggerEvent(plyr.media, 'ended'); break; case 1: @@ -1871,12 +1835,12 @@ // If we were seeking, fire seeked event if (plyr.media.seeking) { - _triggerEvent(plyr.media, "seeked"); + _triggerEvent(plyr.media, 'seeked'); } plyr.media.seeking = false; - _triggerEvent(plyr.media, "play"); - _triggerEvent(plyr.media, "playing"); + _triggerEvent(plyr.media, 'play'); + _triggerEvent(plyr.media, 'playing'); // Poll to get playback progress timers.playing = window.setInterval(function() { @@ -1884,7 +1848,7 @@ plyr.media.currentTime = instance.getCurrentTime(); // Trigger timeupdate - _triggerEvent(plyr.media, "timeupdate"); + _triggerEvent(plyr.media, 'timeupdate'); }, 100); // Check duration again due to YouTube bug @@ -1892,47 +1856,59 @@ // https://code.google.com/p/gdata-issues/issues/detail?id=8690 if (plyr.media.duration !== instance.getDuration()) { plyr.media.duration = instance.getDuration(); - _triggerEvent(plyr.media, "durationchange"); + _triggerEvent(plyr.media, 'durationchange'); } break; case 2: plyr.media.paused = true; - _triggerEvent(plyr.media, "pause"); + _triggerEvent(plyr.media, 'pause'); break; } - _triggerEvent(plyr.container, "statechange", false, { - code: event.data + _triggerEvent(plyr.container, 'statechange', false, { + code: event.data, }); - } - } + }, + }, }); } // Vimeo ready - function _vimeoReady(mediaId, mediaUrl, container) { + function _vimeoReady(mediaId, container) { // Setup instance // https://github.com/vimeo/player.js - var vimeoOptions = { - loop: config.loop, - autoplay: config.autoplay, - byline: false, - portrait: false, - title: false + var options = { + loop: config.loop, + autoplay: config.autoplay, + byline: false, + portrait: false, + title: false, + transparent: 0, }; - if (mediaId) { - vimeoOptions.id = mediaId; + // Convert options into URL params for iframe + function buildUrlParameters(options) { + return Object.keys(options) + .map(function(key) { + return encodeURIComponent(key) + '=' + encodeURIComponent(options[key]); + }) + .join('&'); } - if (mediaUrl) { - vimeoOptions.url = mediaUrl; - } + // Get Vimeo params for the iframe + var params = buildUrlParameters(options); + + // Build an iframe + var iframe = document.createElement('iframe'); + var src = 'https://player.vimeo.com/video/' + mediaId + '?' + params; + iframe.setAttribute('src', src); + iframe.setAttribute('allowfullscreen', ''); + container.appendChild(iframe); - plyr.embed = new window.Vimeo.Player(container, vimeoOptions); + plyr.embed = new window.Vimeo.Player(iframe); // Create a faux HTML5 API using the Vimeo API plyr.media.play = function() { @@ -1958,14 +1934,14 @@ plyr.media.currentTime = value; // Trigger timeupdate - _triggerEvent(plyr.media, "timeupdate"); + _triggerEvent(plyr.media, 'timeupdate'); }); plyr.embed.getDuration().then(function(value) { plyr.media.duration = value; // Trigger timeupdate - _triggerEvent(plyr.media, "durationchange"); + _triggerEvent(plyr.media, 'durationchange'); }); // TODO: Captions @@ -1973,50 +1949,50 @@ plyr.embed.enableTextTrack('en'); }*/ - plyr.embed.on("loaded", function() { + plyr.embed.on('loaded', function() { // Fix keyboard focus issues // https://github.com/sampotts/plyr/issues/317 if (_is.htmlElement(plyr.embed.element) && plyr.supported.full) { - plyr.embed.element.setAttribute("tabindex", "-1"); + plyr.embed.element.setAttribute('tabindex', '-1'); } }); - plyr.embed.on("play", function() { + plyr.embed.on('play', function() { plyr.media.paused = false; - _triggerEvent(plyr.media, "play"); - _triggerEvent(plyr.media, "playing"); + _triggerEvent(plyr.media, 'play'); + _triggerEvent(plyr.media, 'playing'); }); - plyr.embed.on("pause", function() { + plyr.embed.on('pause', function() { plyr.media.paused = true; - _triggerEvent(plyr.media, "pause"); + _triggerEvent(plyr.media, 'pause'); }); - plyr.embed.on("timeupdate", function(data) { + plyr.embed.on('timeupdate', function(data) { plyr.media.seeking = false; plyr.media.currentTime = data.seconds; - _triggerEvent(plyr.media, "timeupdate"); + _triggerEvent(plyr.media, 'timeupdate'); }); - plyr.embed.on("progress", function(data) { + plyr.embed.on('progress', function(data) { plyr.media.buffered = data.percent; - _triggerEvent(plyr.media, "progress"); + _triggerEvent(plyr.media, 'progress'); if (parseInt(data.percent) === 1) { // Trigger event - _triggerEvent(plyr.media, "canplaythrough"); + _triggerEvent(plyr.media, 'canplaythrough'); } }); - plyr.embed.on("seeked", function() { + plyr.embed.on('seeked', function() { plyr.media.seeking = false; - _triggerEvent(plyr.media, "seeked"); - _triggerEvent(plyr.media, "play"); + _triggerEvent(plyr.media, 'seeked'); + _triggerEvent(plyr.media, 'play'); }); - plyr.embed.on("ended", function() { + plyr.embed.on('ended', function() { plyr.media.paused = true; - _triggerEvent(plyr.media, "ended"); + _triggerEvent(plyr.media, 'ended'); }); } @@ -2056,53 +2032,53 @@ plyr.media.currentTime = value; // Trigger timeupdate - _triggerEvent(plyr.media, "timeupdate"); + _triggerEvent(plyr.media, 'timeupdate'); }); plyr.embed.bind(window.SC.Widget.Events.PLAY, function() { plyr.media.paused = false; - _triggerEvent(plyr.media, "play"); - _triggerEvent(plyr.media, "playing"); + _triggerEvent(plyr.media, 'play'); + _triggerEvent(plyr.media, 'playing'); }); plyr.embed.bind(window.SC.Widget.Events.PAUSE, function() { plyr.media.paused = true; - _triggerEvent(plyr.media, "pause"); + _triggerEvent(plyr.media, 'pause'); }); plyr.embed.bind(window.SC.Widget.Events.PLAY_PROGRESS, function(data) { plyr.media.seeking = false; plyr.media.currentTime = data.currentPosition / 1000; - _triggerEvent(plyr.media, "timeupdate"); + _triggerEvent(plyr.media, 'timeupdate'); }); plyr.embed.bind(window.SC.Widget.Events.LOAD_PROGRESS, function(data) { plyr.media.buffered = data.loadProgress; - _triggerEvent(plyr.media, "progress"); + _triggerEvent(plyr.media, 'progress'); if (parseInt(data.loadProgress) === 1) { // Trigger event - _triggerEvent(plyr.media, "canplaythrough"); + _triggerEvent(plyr.media, 'canplaythrough'); } }); plyr.embed.bind(window.SC.Widget.Events.FINISH, function() { plyr.media.paused = true; - _triggerEvent(plyr.media, "ended"); + _triggerEvent(plyr.media, 'ended'); }); }); } // Play media function _play() { - if ("play" in plyr.media) { + if ('play' in plyr.media) { plyr.media.play(); } } // Pause media function _pause() { - if ("pause" in plyr.media) { + if ('pause' in plyr.media) { plyr.media.pause(); } } @@ -2150,7 +2126,7 @@ if (_is.number(input)) { targetTime = input; - } else if (_is.object(input) && _inArray(["input", "change"], input.type)) { + } else if (_is.object(input) && _inArray(['input', 'change'], input.type)) { // It's the seek slider // Seek to the selected time targetTime = input.target.value / input.target.max * duration; @@ -2175,16 +2151,16 @@ // Embeds if (_inArray(config.types.embed, plyr.type)) { switch (plyr.type) { - case "youtube": + case 'youtube': plyr.embed.seekTo(targetTime); break; - case "vimeo": + case 'vimeo': // Round to nearest second for vimeo plyr.embed.setCurrentTime(targetTime.toFixed(0)); break; - case "soundcloud": + case 'soundcloud': plyr.embed.seekTo(targetTime * 1000); break; } @@ -2194,17 +2170,17 @@ } // Trigger timeupdate - _triggerEvent(plyr.media, "timeupdate"); + _triggerEvent(plyr.media, 'timeupdate'); // Set seeking flag plyr.media.seeking = true; // Trigger seeking - _triggerEvent(plyr.media, "seeking"); + _triggerEvent(plyr.media, 'seeking'); } // Logging - _log("Seeking to " + plyr.media.currentTime + " seconds"); + _log('Seeking to ' + plyr.media.currentTime + ' seconds'); // Special handling for 'manual' captions _seekManualCaptions(targetTime); @@ -2239,7 +2215,7 @@ function _saveScrollPosition() { scroll = { x: window.pageXOffset || 0, - y: window.pageYOffset || 0 + y: window.pageYOffset || 0, }; } @@ -2280,7 +2256,7 @@ plyr.isFullscreen = !plyr.isFullscreen; // Bind/unbind escape key - document.body.style.overflow = plyr.isFullscreen ? "hidden" : ""; + document.body.style.overflow = plyr.isFullscreen ? 'hidden' : ''; } // Set class hook @@ -2295,7 +2271,7 @@ } // Trigger an event - _triggerEvent(plyr.container, plyr.isFullscreen ? "enterfullscreen" : "exitfullscreen", true); + _triggerEvent(plyr.container, plyr.isFullscreen ? 'enterfullscreen' : 'exitfullscreen', true); // Restore scroll position if (!plyr.isFullscreen && nativeSupport) { @@ -2325,18 +2301,18 @@ if (_inArray(config.types.embed, plyr.type)) { // YouTube switch (plyr.type) { - case "youtube": - plyr.embed[plyr.media.muted ? "mute" : "unMute"](); + case 'youtube': + plyr.embed[plyr.media.muted ? 'mute' : 'unMute'](); break; - case "vimeo": - case "soundcloud": + case 'vimeo': + case 'soundcloud': plyr.embed.setVolume(plyr.media.muted ? 0 : parseFloat(config.volume / config.volumeMax)); break; } // Trigger volumechange for embeds - _triggerEvent(plyr.media, "volumechange"); + _triggerEvent(plyr.media, 'volumechange'); } } @@ -2375,18 +2351,18 @@ // Embeds if (_inArray(config.types.embed, plyr.type)) { switch (plyr.type) { - case "youtube": + case 'youtube': plyr.embed.setVolume(plyr.media.volume * 100); break; - case "vimeo": - case "soundcloud": + case 'vimeo': + case 'soundcloud': plyr.embed.setVolume(plyr.media.volume); break; } // Trigger volumechange for embeds - _triggerEvent(plyr.media, "volumechange"); + _triggerEvent(plyr.media, 'volumechange'); } // Toggle muted state @@ -2468,7 +2444,7 @@ _toggleClass(plyr.container, config.classes.captions.active, plyr.captionsEnabled); // Trigger an event - _triggerEvent(plyr.container, plyr.captionsEnabled ? "captionsenabled" : "captionsdisabled", true); + _triggerEvent(plyr.container, plyr.captionsEnabled ? 'captionsenabled' : 'captionsdisabled', true); // Save captions state to localStorage _updateStorage({ captionsEnabled: plyr.captionsEnabled }); @@ -2476,7 +2452,7 @@ // Check if media is loading function _checkLoading(event) { - var loading = event.type === "waiting"; + var loading = event.type === 'waiting'; // Clear timer clearTimeout(timers.loading); @@ -2504,8 +2480,8 @@ if (event) { switch (event.type) { // Video playing - case "timeupdate": - case "seeking": + case 'timeupdate': + case 'seeking': if (plyr.controls.pressed) { return; } @@ -2513,15 +2489,15 @@ value = _getPercentage(plyr.media.currentTime, duration); // Set seek range value only if it's a 'natural' time event - if (event.type === "timeupdate" && plyr.buttons.seek) { + if (event.type === 'timeupdate' && plyr.buttons.seek) { plyr.buttons.seek.value = value; } break; // Check buffer status - case "playing": - case "progress": + case 'playing': + case 'progress': progress = plyr.progress.buffer; value = (function() { var buffered = plyr.media.buffered; @@ -2598,11 +2574,11 @@ var displayHours = parseInt((_getDuration() / 60 / 60) % 60) > 0; // Ensure it's two digits. For example, 03 rather than 3. - plyr.secs = ("0" + plyr.secs).slice(-2); - plyr.mins = ("0" + plyr.mins).slice(-2); + plyr.secs = ('0' + plyr.secs).slice(-2); + plyr.mins = ('0' + plyr.mins).slice(-2); // Render - element.innerHTML = (displayHours ? plyr.hours + ":" : "") + plyr.mins + ":" + plyr.secs; + element.innerHTML = (displayHours ? plyr.hours + ':' : '') + plyr.mins + ':' + plyr.secs; } // Show the duration on metadataloaded @@ -2634,7 +2610,7 @@ _updateTimeDisplay(plyr.media.currentTime, plyr.currentTime); // Ignore updates while seeking - if (event && event.type === "timeupdate" && plyr.media.seeking) { + if (event && event.type === 'timeupdate' && plyr.media.seeking) { return; } @@ -2675,12 +2651,12 @@ // Calculate percentage var clientRect = plyr.progress.container.getBoundingClientRect(), percent = 0, - visible = config.classes.tooltip + "--visible"; + visible = config.classes.tooltip + '--visible'; // Determine percentage, if already visible if (!event) { if (_hasClass(plyr.progress.tooltip, visible)) { - percent = plyr.progress.tooltip.style.left.replace("%", ""); + percent = plyr.progress.tooltip.style.left.replace('%', ''); } else { return; } @@ -2699,19 +2675,19 @@ _updateTimeDisplay(duration / 100 * percent, plyr.progress.tooltip); // Set position - plyr.progress.tooltip.style.left = percent + "%"; + plyr.progress.tooltip.style.left = percent + '%'; // Show/hide the tooltip // If the event is a moues in/out and percentage is inside bounds - if (event && _inArray(["mouseenter", "mouseleave"], event.type)) { - _toggleClass(plyr.progress.tooltip, visible, event.type === "mouseenter"); + if (event && _inArray(['mouseenter', 'mouseleave'], event.type)) { + _toggleClass(plyr.progress.tooltip, visible, event.type === 'mouseenter'); } } // Show the player controls in fullscreen mode function _toggleControls(toggle) { // Don't hide if config says not to, it's audio, or not ready or loading - if (!config.hideControls || plyr.type === "audio") { + if (!config.hideControls || plyr.type === 'audio') { return; } @@ -2724,18 +2700,18 @@ if (!_is.boolean(toggle)) { if (toggle && toggle.type) { // Is the enter fullscreen event - isEnterFullscreen = toggle.type === "enterfullscreen"; + isEnterFullscreen = toggle.type === 'enterfullscreen'; // Whether to show controls - show = _inArray(["mousemove", "touchstart", "mouseenter", "focus"], toggle.type); + show = _inArray(['mousemove', 'touchstart', 'mouseenter', 'focus'], toggle.type); // Delay hiding on move events - if (_inArray(["mousemove", "touchmove"], toggle.type)) { + if (_inArray(['mousemove', 'touchmove'], toggle.type)) { delay = 2000; } // Delay a little more for keyboard users - if (toggle.type === "focus") { + if (toggle.type === 'focus') { delay = 3000; } } else { @@ -2786,17 +2762,17 @@ // Return the current source var url; switch (plyr.type) { - case "youtube": + case 'youtube': url = plyr.embed.getVideoUrl(); break; - case "vimeo": + case 'vimeo': plyr.embed.getVideoUrl.then(function(value) { url = value; }); break; - case "soundcloud": + case 'soundcloud': plyr.embed.getCurrentSound(function(object) { url = object.permalink_url; }); @@ -2807,14 +2783,14 @@ break; } - return url || ""; + return url || ''; } // Update source // Sources are not checked for support so be careful function _updateSource(source) { - if (!_is.object(source) || !("sources" in source) || !source.sources.length) { - _warn("Invalid source format"); + if (!_is.object(source) || !('sources' in source) || !source.sources.length) { + _warn('Invalid source format'); return; } @@ -2842,24 +2818,24 @@ _remove(plyr.media); // Remove video container - if (plyr.type === "video" && plyr.videoContainer) { + if (plyr.type === 'video' && plyr.videoContainer) { _remove(plyr.videoContainer); } // Reset class name if (plyr.container) { - plyr.container.removeAttribute("class"); + plyr.container.removeAttribute('class'); } // Set the type - if ("type" in source) { + if ('type' in source) { plyr.type = source.type; // Get child type for video (it might be an embed) - if (plyr.type === "video") { + if (plyr.type === 'video') { var firstSource = source.sources[0]; - if ("type" in firstSource && _inArray(config.types.embed, firstSource.type)) { + if ('type' in firstSource && _inArray(config.types.embed, firstSource.type)) { plyr.type = firstSource.type; } } @@ -2870,18 +2846,18 @@ // Create new markup switch (plyr.type) { - case "video": - plyr.media = document.createElement("video"); + case 'video': + plyr.media = document.createElement('video'); break; - case "audio": - plyr.media = document.createElement("audio"); + case 'audio': + plyr.media = document.createElement('audio'); break; - case "youtube": - case "vimeo": - case "soundcloud": - plyr.media = document.createElement("div"); + case 'youtube': + case 'vimeo': + case 'soundcloud': + plyr.media = document.createElement('div'); plyr.embedId = source.sources[0].src; break; } @@ -2897,16 +2873,16 @@ // Set attributes for audio and video if (_inArray(config.types.html5, plyr.type)) { if (config.crossorigin) { - plyr.media.setAttribute("crossorigin", ""); + plyr.media.setAttribute('crossorigin', ''); } if (config.autoplay) { - plyr.media.setAttribute("autoplay", ""); + plyr.media.setAttribute('autoplay', ''); } - if ("poster" in source) { - plyr.media.setAttribute("poster", source.poster); + if ('poster' in source) { + plyr.media.setAttribute('poster', source.poster); } if (config.loop) { - plyr.media.setAttribute("loop", ""); + plyr.media.setAttribute('loop', ''); } } @@ -2917,7 +2893,7 @@ // Set new sources for html5 if (_inArray(config.types.html5, plyr.type)) { - _insertChildElements("source", source.sources); + _insertChildElements('source', source.sources); } // Set up from scratch @@ -2926,8 +2902,8 @@ // HTML5 stuff if (_inArray(config.types.html5, plyr.type)) { // Setup captions - if ("tracks" in source) { - _insertChildElements("track", source.tracks); + if ('tracks' in source) { + _insertChildElements('track', source.tracks); } // Load HTML5 sources @@ -2935,10 +2911,7 @@ } // If HTML5 or embed but not fully supported, setupInterface and call ready now - if ( - _inArray(config.types.html5, plyr.type) || - (_inArray(config.types.embed, plyr.type) && !plyr.supported.full) - ) { + if (_inArray(config.types.html5, plyr.type) || (_inArray(config.types.embed, plyr.type) && !plyr.supported.full)) { // Setup interface _setupInterface(); @@ -2958,8 +2931,8 @@ // Update poster function _updatePoster(source) { - if (plyr.type === "video") { - plyr.media.setAttribute("poster", source); + if (plyr.type === 'video') { + plyr.media.setAttribute('poster', source); } } @@ -2970,15 +2943,15 @@ // Listen for control events function _controlListeners() { // IE doesn't support input event, so we fallback to change - var inputEvent = plyr.browser.isIE ? "change" : "input"; + var inputEvent = plyr.browser.isIE ? 'change' : 'input'; // Click play/pause helper function togglePlay() { var play = _togglePlay(); // Determine which buttons - var trigger = plyr.buttons[play ? "play" : "pause"], - target = plyr.buttons[play ? "pause" : "play"]; + var trigger = plyr.buttons[play ? 'play' : 'pause'], + target = plyr.buttons[play ? 'pause' : 'play']; // Get the last play button to account for the large play button if (target) { @@ -3011,7 +2984,7 @@ if (!focused || focused === document.body) { focused = null; } else { - focused = document.querySelector(":focus"); + focused = document.querySelector(':focus'); } return focused; @@ -3043,7 +3016,7 @@ // Handle global presses if (config.keyboardShorcuts.global) { - _on(window, "keydown keyup", function(event) { + _on(window, 'keydown keyup', function(event) { var code = getKeyCode(event), focused = getFocusElement(), allowed = [48, 49, 50, 51, 52, 53, 54, 56, 57, 75, 77, 70, 67], @@ -3053,23 +3026,19 @@ // and the key is in the allowed keys // and if the focused element is not editable (e.g. text input) // and any that accept key input http://webaim.org/techniques/keyboard/ - if ( - count === 1 && - _inArray(allowed, code) && - (!_is.htmlElement(focused) || !_matches(focused, config.selectors.editable)) - ) { + if (count === 1 && _inArray(allowed, code) && (!_is.htmlElement(focused) || !_matches(focused, config.selectors.editable))) { handleKey(event); } }); } // Handle presses on focused - _on(plyr.container, "keydown keyup", handleKey); + _on(plyr.container, 'keydown keyup', handleKey); } function handleKey(event) { var code = getKeyCode(event), - pressed = event.type === "keydown", + pressed = event.type === 'keydown', held = pressed && code === last; // If the event is bubbled from the media element @@ -3175,7 +3144,7 @@ } // Focus/tab management - _on(window, "keyup", function(event) { + _on(window, 'keyup', function(event) { var code = getKeyCode(event), focused = getFocusElement(); @@ -3183,29 +3152,29 @@ checkTabFocus(focused); } }); - _on(document.body, "click", onBodyClick); + _on(document.body, 'click', onBodyClick); for (var button in plyr.buttons) { var element = plyr.buttons[button]; - _on(element, "blur", function() { - _toggleClass(element, "tab-focus", false); + _on(element, 'blur', function() { + _toggleClass(element, 'tab-focus', false); }); } // Play - _proxyListener(plyr.buttons.play, "click", config.listeners.play, togglePlay); + _proxyListener(plyr.buttons.play, 'click', config.listeners.play, togglePlay); // Pause - _proxyListener(plyr.buttons.pause, "click", config.listeners.pause, togglePlay); + _proxyListener(plyr.buttons.pause, 'click', config.listeners.pause, togglePlay); // Restart - _proxyListener(plyr.buttons.restart, "click", config.listeners.restart, _seek); + _proxyListener(plyr.buttons.restart, 'click', config.listeners.restart, _seek); // Rewind - _proxyListener(plyr.buttons.rewind, "click", config.listeners.rewind, _rewind); + _proxyListener(plyr.buttons.rewind, 'click', config.listeners.rewind, _rewind); // Fast forward - _proxyListener(plyr.buttons.forward, "click", config.listeners.forward, _forward); + _proxyListener(plyr.buttons.forward, 'click', config.listeners.forward, _forward); // Seek _proxyListener(plyr.buttons.seek, inputEvent, config.listeners.seek, _seek); @@ -3216,10 +3185,10 @@ }); // Mute - _proxyListener(plyr.buttons.mute, "click", config.listeners.mute, _toggleMute); + _proxyListener(plyr.buttons.mute, 'click', config.listeners.mute, _toggleMute); // Fullscreen - _proxyListener(plyr.buttons.fullscreen, "click", config.listeners.fullscreen, _toggleFullscreen); + _proxyListener(plyr.buttons.fullscreen, 'click', config.listeners.fullscreen, _toggleFullscreen); // Handle user exiting fullscreen by escaping etc if (fullscreen.supportsFullScreen) { @@ -3227,36 +3196,32 @@ } // Captions - _proxyListener(plyr.buttons.captions, "click", config.listeners.captions, _toggleCaptions); + _proxyListener(plyr.buttons.captions, 'click', config.listeners.captions, _toggleCaptions); // Seek tooltip - _on(plyr.progress.container, "mouseenter mouseleave mousemove", _updateSeekTooltip); + _on(plyr.progress.container, 'mouseenter mouseleave mousemove', _updateSeekTooltip); // Toggle controls visibility based on mouse movement if (config.hideControls) { // Toggle controls on mouse events and entering fullscreen - _on( - plyr.container, - "mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen", - _toggleControls - ); + _on(plyr.container, 'mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen', _toggleControls); // Watch for cursor over controls so they don't hide when trying to interact - _on(plyr.controls, "mouseenter mouseleave", function(event) { - plyr.controls.hover = event.type === "mouseenter"; + _on(plyr.controls, 'mouseenter mouseleave', function(event) { + plyr.controls.hover = event.type === 'mouseenter'; }); // Watch for cursor over controls so they don't hide when trying to interact - _on(plyr.controls, "mousedown mouseup touchstart touchend touchcancel", function(event) { - plyr.controls.pressed = _inArray(["mousedown", "touchstart"], event.type); + _on(plyr.controls, 'mousedown mouseup touchstart touchend touchcancel', function(event) { + plyr.controls.pressed = _inArray(['mousedown', 'touchstart'], event.type); }); // Focus in/out on controls - _on(plyr.controls, "focus blur", _toggleControls, true); + _on(plyr.controls, 'focus blur', _toggleControls, true); } // Adjust volume on scroll - _on(plyr.volume.input, "wheel", function(event) { + _on(plyr.volume.input, 'wheel', function(event) { event.preventDefault(); // Detect "natural" scroll - suppored on OS X Safari only @@ -3287,20 +3252,20 @@ // Listen for media events function _mediaListeners() { // Time change on media - _on(plyr.media, "timeupdate seeking", _timeUpdate); + _on(plyr.media, 'timeupdate seeking', _timeUpdate); // Update manual captions - _on(plyr.media, "timeupdate", _seekManualCaptions); + _on(plyr.media, 'timeupdate', _seekManualCaptions); // Display duration - _on(plyr.media, "durationchange loadedmetadata", _displayDuration); + _on(plyr.media, 'durationchange loadedmetadata', _displayDuration); // Handle the media finishing - _on(plyr.media, "ended", function() { + _on(plyr.media, 'ended', function() { // Show poster on end - if (plyr.type === "video" && config.showPosterOnEnd) { + if (plyr.type === 'video' && config.showPosterOnEnd) { // Clear - if (plyr.type === "video") { + if (plyr.type === 'video') { _setCaption(); } @@ -3313,21 +3278,21 @@ }); // Check for buffer progress - _on(plyr.media, "progress playing", _updateProgress); + _on(plyr.media, 'progress playing', _updateProgress); // Handle native mute - _on(plyr.media, "volumechange", _updateVolume); + _on(plyr.media, 'volumechange', _updateVolume); // Handle native play/pause - _on(plyr.media, "play pause ended", _checkPlaying); + _on(plyr.media, 'play pause ended', _checkPlaying); // Loading - _on(plyr.media, "waiting canplay seeked", _checkLoading); + _on(plyr.media, 'waiting canplay seeked', _checkLoading); // Click video - if (config.clickToPlay && plyr.type !== "audio") { + if (config.clickToPlay && plyr.type !== 'audio') { // Re-fetch the wrapper - var wrapper = _getElement("." + config.classes.videoWrapper); + var wrapper = _getElement('.' + config.classes.videoWrapper); // Bail if there's no wrapper (this should never happen) if (!wrapper) { @@ -3335,10 +3300,10 @@ } // Set cursor - wrapper.style.cursor = "pointer"; + wrapper.style.cursor = 'pointer'; // On click play, pause ore restart - _on(wrapper, "click", function() { + _on(wrapper, 'click', function() { // Touch devices will just show controls (if we're hiding controls) if (config.hideControls && plyr.browser.isTouch && !plyr.media.paused) { return; @@ -3357,14 +3322,14 @@ // Disable right click if (config.disableContextMenu) { - _on(plyr.media, "contextmenu", function(event) { + _on(plyr.media, 'contextmenu', function(event) { event.preventDefault(); }); } // Proxy events to container // Bubble up key events for Edge - _on(plyr.media, config.events.concat(["keyup", "keydown"]).join(" "), function(event) { + _on(plyr.media, config.events.concat(['keyup', 'keydown']).join(' '), function(event) { _triggerEvent(plyr.container, event.type, true); }); } @@ -3377,7 +3342,7 @@ } // Remove child sources - var sources = plyr.media.querySelectorAll("source"); + var sources = plyr.media.querySelectorAll('source'); for (var i = 0; i < sources.length; i++) { _remove(sources[i]); } @@ -3385,7 +3350,7 @@ // Set blank video src attribute // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection - plyr.media.setAttribute("src", config.blankUrl); + plyr.media.setAttribute('src', config.blankUrl); // Load the new empty source // This will cancel existing requests @@ -3393,7 +3358,7 @@ plyr.media.load(); // Debugging - _log("Cancelled network requests"); + _log('Cancelled network requests'); } // Destroy an instance @@ -3407,7 +3372,7 @@ // Type specific stuff switch (plyr.type) { - case "youtube": + case 'youtube': // Clear timers window.clearInterval(timers.buffering); window.clearInterval(timers.playing); @@ -3420,7 +3385,7 @@ break; - case "vimeo": + case 'vimeo': // Destroy Vimeo API // then clean up (wait, to prevent postmessage errors) plyr.embed.unload().then(cleanUp); @@ -3430,8 +3395,8 @@ break; - case "video": - case "audio": + case 'video': + case 'audio': // Restore native video controls _toggleNativeControls(true); @@ -3469,13 +3434,13 @@ plyr.container = null; // Allow overflow (set on fullscreen) - document.body.style.overflow = ""; + document.body.style.overflow = ''; //remove events _off(document.body, 'click', onBodyClick); // Event - _triggerEvent(original, "destroyed", true); + _triggerEvent(original, 'destroyed', true); } } @@ -3503,18 +3468,18 @@ // Set media type based on tag or data attribute // Supported: video, audio, vimeo, youtube var tagName = media.tagName.toLowerCase(); - if (tagName === "div") { - plyr.type = media.getAttribute("data-type"); - plyr.embedId = media.getAttribute("data-video-id"); + if (tagName === 'div') { + plyr.type = media.getAttribute('data-type'); + plyr.embedId = media.getAttribute('data-video-id'); // Clean up - media.removeAttribute("data-type"); - media.removeAttribute("data-video-id"); + media.removeAttribute('data-type'); + media.removeAttribute('data-video-id'); } else { plyr.type = tagName; - config.crossorigin = media.getAttribute("crossorigin") !== null; - config.autoplay = config.autoplay || media.getAttribute("autoplay") !== null; - config.loop = config.loop || media.getAttribute("loop") !== null; + config.crossorigin = media.getAttribute('crossorigin') !== null; + config.autoplay = config.autoplay || media.getAttribute('autoplay') !== null; + config.loop = config.loop || media.getAttribute('loop') !== null; } // Check for support @@ -3526,26 +3491,23 @@ } // Wrap media - plyr.container = _wrap(media, document.createElement("div")); + plyr.container = _wrap(media, document.createElement('div')); // Allow focus to be captured - plyr.container.setAttribute("tabindex", 0); + plyr.container.setAttribute('tabindex', 0); // Add style hook _toggleStyleHook(); // Debug info - _log("" + plyr.browser.name + " " + plyr.browser.version); + _log('' + plyr.browser.name + ' ' + plyr.browser.version); // Setup media _setupMedia(); // Setup interface // If embed but not fully supported, setupInterface (to avoid flash of controls) and call ready now - if ( - _inArray(config.types.html5, plyr.type) || - (_inArray(config.types.embed, plyr.type) && !plyr.supported.full) - ) { + if (_inArray(config.types.html5, plyr.type) || (_inArray(config.types.embed, plyr.type) && !plyr.supported.full)) { // Setup UI _setupInterface(); @@ -3564,7 +3526,7 @@ function _setupInterface() { // Don't setup interface if no support if (!plyr.supported.full) { - _warn("Basic support only", plyr.type); + _warn('Basic support only', plyr.type); // Remove controls _remove(_getElement(config.selectors.controls.wrapper)); @@ -3685,14 +3647,14 @@ support: function(mimeType) { return _supportMime(plyr, mimeType); }, - destroy: _destroy + destroy: _destroy, }; // Everything done function _ready() { // Ready event at end of execution stack window.setTimeout(function() { - _triggerEvent(plyr.media, "ready"); + _triggerEvent(plyr.media, 'ready'); }, 0); // Set class hook on media element @@ -3726,21 +3688,21 @@ var x = new XMLHttpRequest(); // If the id is set and sprite exists, bail - if (_is.string(id) && _is.htmlElement(document.querySelector("#" + id))) { + if (_is.string(id) && _is.htmlElement(document.querySelector('#' + id))) { return; } // Create placeholder (to prevent loading twice) - var container = document.createElement("div"); - container.setAttribute("hidden", ""); + var container = document.createElement('div'); + container.setAttribute('hidden', ''); if (_is.string(id)) { - container.setAttribute("id", id); + container.setAttribute('id', id); } document.body.insertBefore(container, document.body.childNodes[0]); // Check for CORS support - if ("withCredentials" in x) { - x.open("GET", url, true); + if ('withCredentials' in x) { + x.open('GET', url, true); } else { return; } @@ -3759,30 +3721,30 @@ isOldIE = browser.isIE && browser.version <= 9, isIos = browser.isIos, isIphone = browser.isIphone, - audioSupport = !!document.createElement("audio").canPlayType, - videoSupport = !!document.createElement("video").canPlayType, + audioSupport = !!document.createElement('audio').canPlayType, + videoSupport = !!document.createElement('video').canPlayType, basic = false, full = false; switch (type) { - case "video": + case 'video': basic = videoSupport; full = basic && (!isOldIE && !isIphone); break; - case "audio": + case 'audio': basic = audioSupport; full = basic && !isOldIE; break; // Vimeo does not seem to be supported on iOS via API // Issue raised https://github.com/vimeo/player.js/issues/87 - case "vimeo": + case 'vimeo': basic = true; full = !isOldIE && !isIos; break; - case "youtube": + case 'youtube': basic = true; full = !isOldIE && !isIos; @@ -3793,7 +3755,7 @@ break; - case "soundcloud": + case 'soundcloud': basic = true; full = !isOldIE && !isIphone; break; @@ -3805,7 +3767,7 @@ return { basic: basic, - full: full + full: full, }; } @@ -3814,7 +3776,7 @@ // Get the players var players = [], instances = [], - selector = [defaults.selectors.html5, defaults.selectors.embed].join(","); + selector = [defaults.selectors.html5, defaults.selectors.embed].join(','); // Select the elements if (_is.string(targets)) { @@ -3854,7 +3816,7 @@ // Could be a container or the media itself target: target, // This should be the <video>, <audio> or <div> (YouTube/Vimeo) - media: media + media: media, }); } } @@ -3894,7 +3856,7 @@ // Try parsing data attribute config try { - data = JSON.parse(element.getAttribute("data-plyr")); + data = JSON.parse(element.getAttribute('data-plyr')); } catch (e) {} var config = _extend({}, defaults, options, data); @@ -3914,23 +3876,16 @@ // Listen for events if debugging if (config.debug) { - var events = config.events.concat([ - "setup", - "statechange", - "enterfullscreen", - "exitfullscreen", - "captionsenabled", - "captionsdisabled" - ]); - - _on(instance.getContainer(), events.join(" "), function(event) { - console.log([config.logPrefix, "event:", event.type].join(" "), event.detail.plyr); + var events = config.events.concat(['setup', 'statechange', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled']); + + _on(instance.getContainer(), events.join(' '), function(event) { + console.log([config.logPrefix, 'event:', event.type].join(' '), event.detail.plyr); }); } // Callback - _event(instance.getContainer(), "setup", true, { - plyr: instance + _event(instance.getContainer(), 'setup', true, { + plyr: instance, }); // Add to return array even if it's already setup @@ -3952,7 +3907,7 @@ // If we have a HTML element if (_is.htmlElement(container)) { - var elements = container.querySelectorAll("." + defaults.classes.setup), + var elements = container.querySelectorAll('.' + defaults.classes.setup), instances = []; Array.prototype.slice.call(elements).forEach(function(element) { @@ -3971,20 +3926,20 @@ setup: setup, supported: supported, loadSprite: loadSprite, - get: get + get: get, }; }); // Custom event polyfill // https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent (function() { - if (typeof window.CustomEvent === "function") { + if (typeof window.CustomEvent === 'function') { return; } function CustomEvent(event, params) { params = params || { bubbles: false, cancelable: false, detail: undefined }; - var evt = document.createEvent("CustomEvent"); + var evt = document.createEvent('CustomEvent'); evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); return evt; } diff --git a/src/less/plyr.less b/src/less/plyr.less index 3b1c21b6..b701a6ce 100644 --- a/src/less/plyr.less +++ b/src/less/plyr.less @@ -3,8 +3,8 @@ // https://github.com/selz/plyr // ========================================================================== -@import "variables"; -@import "mixins"; +@import 'variables'; +@import 'mixins'; // Animation // --------------------------------------- @@ -61,15 +61,15 @@ // Range inputs // Specificity is for bootstrap compatibility - input[type="range"] { + input[type='range'] { display: block; height: (@plyr-range-thumb-height * @plyr-range-thumb-active-scale); width: 100%; margin: 0; padding: 0; - vertical-align: middle; - appearance: none; + -webkit-appearance: none; + -moz-appearance: none; cursor: pointer; border: none; background: transparent; @@ -142,12 +142,12 @@ } // Video range inputs -.plyr--video input[type="range"].tab-focus:focus { +.plyr--video input[type='range'].tab-focus:focus { outline: 1px dotted fade(@plyr-video-control-color, 50%); } // Audio range inputs -.plyr--audio input[type="range"].tab-focus:focus { +.plyr--audio input[type='range'].tab-focus:focus { outline: 1px dotted fade(@plyr-audio-control-color, 50%); } @@ -274,7 +274,7 @@ line-height: 1; text-align: center; pointer-events: none; - + & > * { pointer-events: all; } @@ -292,7 +292,7 @@ .plyr__volume { margin-left: (@plyr-control-spacing / 2); } - [data-plyr="pause"] { + [data-plyr='pause'] { margin-left: 0; } @@ -428,11 +428,11 @@ } // States -.plyr__controls [data-plyr="pause"], -.plyr--playing .plyr__controls [data-plyr="play"] { +.plyr__controls [data-plyr='pause'], +.plyr--playing .plyr__controls [data-plyr='play'] { display: none; } -.plyr--playing .plyr__controls [data-plyr="pause"] { +.plyr--playing .plyr__controls [data-plyr='pause'] { display: inline-block; } @@ -448,12 +448,12 @@ } // Some options are hidden by default -.plyr [data-plyr="captions"], -.plyr [data-plyr="fullscreen"] { +.plyr [data-plyr='captions'], +.plyr [data-plyr='fullscreen'] { display: none; } -.plyr--captions-enabled [data-plyr="captions"], -.plyr--fullscreen-enabled [data-plyr="fullscreen"] { +.plyr--captions-enabled [data-plyr='captions'], +.plyr--fullscreen-enabled [data-plyr='fullscreen'] { display: inline-block; } @@ -481,7 +481,7 @@ &::before { // Arrows - content: ""; + content: ''; position: absolute; width: 0; height: 0; @@ -547,7 +547,7 @@ display: none; flex: 1; - input[type="range"] { + input[type='range'] { position: relative; z-index: 2; @@ -582,7 +582,8 @@ margin: -(@plyr-range-track-height / 2) 0 0; padding: 0; vertical-align: top; - appearance: none; + -webkit-appearance: none; + -moz-appearance: none; border: none; border-radius: 100px; @@ -695,7 +696,7 @@ // Add a slash in before &::before { - content: "\2044"; + content: '\2044'; margin-right: @plyr-control-spacing; } } @@ -709,7 +710,7 @@ flex: 1; position: relative; - input[type="range"] { + input[type='range'] { position: relative; z-index: 2; } @@ -726,7 +727,7 @@ // It's not supported to change volume using JavaScript: // https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html .plyr--is-ios .plyr__volume, -.plyr--is-ios [data-plyr="mute"] { +.plyr--is-ios [data-plyr='mute'] { display: none !important; } |