Compare commits

..

14 Commits

Author SHA1 Message Date
d7cc29f2fb Vimeo keyboard focus fix (Fixes #317), Fix for Vimeo on basic support devices 2016-07-23 11:11:17 +10:00
0505e49038 Vimeo API upgrade, YouTube Bugfix, Array support
- Vimeo API upgrade
- Fix for YouTube bug introduced in v1.8.9 (Fixes #320)
- Added support for passing array to .setup() (Fixes #319)
2016-07-23 10:42:06 +10:00
6ff1e47341 Merge branch 'master' of https://github.com/Selz/plyr 2016-07-21 21:59:26 +10:00
e72a91de6e Fix for seek issues introduced in v1.8.9 2016-07-21 21:59:16 +10:00
52ec4c012d Update readme.md 2016-07-21 21:32:56 +10:00
ae89c92ab6 Update readme.md 2016-07-21 21:31:09 +10:00
57ad124ce8 v1.8.9 2016-07-21 21:25:27 +10:00
a85d45d2e5 Fix for fullscreen not being defined (Fixes #295) 2016-07-21 21:21:10 +10:00
a6f57fc034 Fix for multiline captions (Fixes #314) 2016-07-21 21:15:44 +10:00
04c9653b86 Merge branch 'master' of https://github.com/Selz/plyr 2016-07-21 21:14:29 +10:00
b8cdc71001 Clean up of type checks and fix for _restart() (Fixes #315) 2016-07-21 21:14:22 +10:00
277ebf0fd1 Merge pull request #312 from dpschen/patch-1
Add kirby-plyrtag
2016-07-14 22:03:50 +10:00
7682d998e7 Add kirby-plyrtag
Added a Kirby cms kirbytag https://getkirby.com/
2016-07-14 12:52:28 +02:00
05b9b9a831 Fix for MEDIA_ERR_SRC_NOT_SUPPORTED when calling .source() API method 2016-07-14 17:13:37 +10:00
8 changed files with 221 additions and 170 deletions

View File

@ -1,5 +1,25 @@
# Changelog # Changelog
## v1.8.12
- Vimeo keyboard focus fix (Fixes #317)
- Fix for Vimeo on basic support devices
## v1.8.11
- Fix for keyboard navigation on Vimeo (Fixes #317)
- Fix for bug introduced in v1.8.9 related to additional controls
- Vimeo API upgrade
- Fix for YouTube bug introduced in v1.8.9
- Added support for passing array to .setup() (Fixes #319)
## v1.8.10
- Fix for seek issues introduced in v1.8.9
## v1.8.9
- Fix for fullscreen not being defined (Fixes #295)
- Fix for multiline captions (Fixes #314)
- Clean up of type checks and fix for `restart()` (Fixes #315)
- Fix for `MEDIA_ERR_SRC_NOT_SUPPORTED` when calling `.source()` API method
## v1.8.8 ## v1.8.8
- Added getCurrentTime API method (fixes #292) - Added getCurrentTime API method (fixes #292)
- Fix for !hideControls on touch devices (fixes #303) - Fix for !hideControls on touch devices (fixes #303)

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

4
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "plyr", "name": "plyr",
"version": "1.8.8", "version": "1.8.12",
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player", "description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
"homepage": "http://plyr.io", "homepage": "http://plyr.io",
"main": "src/js/plyr.js", "main": "src/js/plyr.js",

View File

@ -3,7 +3,7 @@ A simple, accessible and customizable HTML5, YouTube and Vimeo media player.
[Checkout the demo](https://plyr.io) [Checkout the demo](https://plyr.io)
[![Image of Plyr](https://cdn.selz.com/plyr/plyr_v1.8.png)](https://plyr.io) [![Image of Plyr](https://cdn.selz.com/plyr/plyr_v1.8.9.png)](https://plyr.io)
## Why? ## Why?
We wanted a lightweight, accessible and customizable media player that supports [*modern*](#browser-support) browsers. Sure, there are many other players out there but we wanted to keep things simple, using the right elements for the job. We wanted a lightweight, accessible and customizable media player that supports [*modern*](#browser-support) browsers. Sure, there are many other players out there but we wanted to keep things simple, using the right elements for the job.
@ -21,8 +21,8 @@ We wanted a lightweight, accessible and customizable media player that supports
- **[Fullscreen](#fullscreen)** - supports native fullscreen with fallback to "full window" modes - **[Fullscreen](#fullscreen)** - supports native fullscreen with fallback to "full window" modes
- **i18n support** - support for internationalization of controls - **i18n support** - support for internationalization of controls
- **No dependencies** - written in "vanilla" JavaScript, no jQuery required - **No dependencies** - written in "vanilla" JavaScript, no jQuery required
- **SASS and LESS provided** - If you like _these_ over plain CSS - **SASS and LESS source** - to include in your build process
- **[Streaming](#streaming)** - Support for hls.js, Shaka and dash.js streaming playback - **[Streaming](#streaming)** - support for hls.js, Shaka and dash.js streaming playback
Oh and yes, it works with Bootstrap. Oh and yes, it works with Bootstrap.
@ -47,6 +47,9 @@ Created and maintained by Ryan Anthony Drake ([@iamryandrake](https://github.com
### [Neos](https://packagist.org/packages/jonnitto/plyr) ### [Neos](https://packagist.org/packages/jonnitto/plyr)
Created and maintained by Jon Uhlmann ([@jonnitto](https://github.com/jonnitto)) Created and maintained by Jon Uhlmann ([@jonnitto](https://github.com/jonnitto))
### [Kirby](https://github.com/dpschen/kirby-plyrtag)
Created and maintained by Dominik Pschenitschni ([@dpschen](https://github.com/dpschen))
## Using package managers ## Using package managers
You can grab the source using one of the following package managers. You can grab the source using one of the following package managers.
@ -118,7 +121,7 @@ Include the `plyr.js` script before the closing `</body>` tag and then call `ply
If you want to use our CDN for the JavaScript, you can use the following: If you want to use our CDN for the JavaScript, you can use the following:
```html ```html
<script src="https://cdn.plyr.io/1.8.8/plyr.js"></script> <script src="https://cdn.plyr.io/1.8.12/plyr.js"></script>
``` ```
### CSS ### CSS
@ -131,11 +134,11 @@ Include the `plyr.css` stylsheet into your `<head>`
If you want to use our CDN for the default CSS, you can use the following: If you want to use our CDN for the default CSS, you can use the following:
```html ```html
<link rel="stylesheet" href="https://cdn.plyr.io/1.8.8/plyr.css"> <link rel="stylesheet" href="https://cdn.plyr.io/1.8.12/plyr.css">
``` ```
### SVG Sprite ### SVG Sprite
The SVG sprite is loaded automatically from our CDN. To change this, see the [#options](Options) below. For reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/1.8.8/plyr.svg`. The SVG sprite is loaded automatically from our CDN. To change this, see the [#options](Options) below. For reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/1.8.12/plyr.svg`.
## Advanced ## Advanced

View File

@ -1,6 +1,6 @@
// ========================================================================== // ==========================================================================
// Plyr // Plyr
// plyr.js v1.8.8 // plyr.js v1.8.12
// https://github.com/selz/plyr // https://github.com/selz/plyr
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================
@ -23,7 +23,6 @@
} }
}(typeof window !== 'undefined' ? window : this, function(window, document) { }(typeof window !== 'undefined' ? window : this, function(window, document) {
'use strict'; 'use strict';
/*global YT,$f*/
// Globals // Globals
var fullscreen, var fullscreen,
@ -44,7 +43,7 @@
displayDuration: true, displayDuration: true,
loadSprite: true, loadSprite: true,
iconPrefix: 'plyr', iconPrefix: 'plyr',
iconUrl: 'https://cdn.plyr.io/1.8.8/plyr.svg', iconUrl: 'https://cdn.plyr.io/1.8.12/plyr.svg',
clickToPlay: true, clickToPlay: true,
hideControls: true, hideControls: true,
showPosterOnEnd: false, showPosterOnEnd: false,
@ -146,7 +145,7 @@
// URLs // URLs
urls: { urls: {
vimeo: { vimeo: {
api: 'https://cdn.plyr.io/froogaloop/1.0.1/plyr.froogaloop.js', api: 'https://player.vimeo.com/api/player.js',
}, },
youtube: { youtube: {
api: 'https://www.youtube.com/iframe_api' api: 'https://www.youtube.com/iframe_api'
@ -376,7 +375,7 @@
// Set attributes // Set attributes
function _setAttributes(element, attributes) { function _setAttributes(element, attributes) {
for (var key in attributes) { for (var key in attributes) {
element.setAttribute(key, (typeof attributes[key] === 'boolean' && attributes[key]) ? '' : attributes[key]); element.setAttribute(key, (_is.boolean(attributes[key]) && attributes[key]) ? '' : attributes[key]);
} }
} }
@ -464,7 +463,7 @@
// Whether the listener is a capturing listener or not // Whether the listener is a capturing listener or not
// Default to false // Default to false
if (typeof useCapture !== 'boolean') { if (!_is.boolean(useCapture)) {
useCapture = false; useCapture = false;
} }
@ -492,7 +491,7 @@
} }
// Default bubbles to false // Default bubbles to false
if (typeof bubbles !== 'boolean') { if (!_is.boolean(bubbles)) {
bubbles = false; bubbles = false;
} }
@ -515,7 +514,7 @@
} }
// Get state // Get state
state = (typeof state === 'boolean' ? state : !target.getAttribute('aria-pressed')); state = (_is.boolean(state) ? state : !target.getAttribute('aria-pressed'));
// Set the attribute on target // Set the attribute on target
target.setAttribute('aria-pressed', state); target.setAttribute('aria-pressed', state);
@ -570,6 +569,34 @@
return destination; return destination;
} }
// Check variable types
var _is = {
object: function(input) {
return input !== null && typeof(input) === 'object';
},
array: function(input) {
return input !== null && typeof(input) === 'object' && input.constructor === Array;
},
number: function(input) {
return typeof(input) === 'number' && !isNaN(input - 0) || (typeof input == 'object' && input.constructor === Number);
},
string: function(input) {
return typeof input === 'string' || (typeof input == 'object' && input.constructor === String);
},
boolean: function(input) {
return typeof input === 'boolean';
},
nodeList: function(input) {
return input instanceof NodeList;
},
htmlElement: function(input) {
return input instanceof HTMLElement;
},
undefined: function(input) {
return typeof input === 'undefined';
}
};
// Fullscreen API // Fullscreen API
function _fullscreen() { function _fullscreen() {
var fullscreen = { var fullscreen = {
@ -584,7 +611,7 @@
browserPrefixes = 'webkit moz o ms khtml'.split(' '); browserPrefixes = 'webkit moz o ms khtml'.split(' ');
// Check for native support // Check for native support
if (typeof document.cancelFullScreen !== 'undefined') { if (!_is.undefined(document.cancelFullScreen)) {
fullscreen.supportsFullScreen = true; fullscreen.supportsFullScreen = true;
} }
else { else {
@ -592,12 +619,12 @@
for (var i = 0, il = browserPrefixes.length; i < il; i++ ) { for (var i = 0, il = browserPrefixes.length; i < il; i++ ) {
fullscreen.prefix = browserPrefixes[i]; fullscreen.prefix = browserPrefixes[i];
if (typeof document[fullscreen.prefix + 'CancelFullScreen'] !== 'undefined') { if (!_is.undefined(document[fullscreen.prefix + 'CancelFullScreen'])) {
fullscreen.supportsFullScreen = true; fullscreen.supportsFullScreen = true;
break; break;
} }
// Special case for MS (when isn't it?) // Special case for MS (when isn't it?)
else if (typeof document.msExitFullscreen !== 'undefined' && document.msFullscreenEnabled) { else if (!_is.undefined(document.msExitFullscreen) && document.msFullscreenEnabled) {
fullscreen.prefix = 'ms'; fullscreen.prefix = 'ms';
fullscreen.supportsFullScreen = true; fullscreen.supportsFullScreen = true;
break; break;
@ -612,7 +639,7 @@
fullscreen.fullScreenEventName = (fullscreen.prefix == 'ms' ? 'MSFullscreenChange' : fullscreen.prefix + 'fullscreenchange'); fullscreen.fullScreenEventName = (fullscreen.prefix == 'ms' ? 'MSFullscreenChange' : fullscreen.prefix + 'fullscreenchange');
fullscreen.isFullScreen = function(element) { fullscreen.isFullScreen = function(element) {
if (typeof element === 'undefined') { if (_is.undefined(element)) {
element = document.body; element = document.body;
} }
switch (this.prefix) { switch (this.prefix) {
@ -625,7 +652,7 @@
} }
}; };
fullscreen.requestFullScreen = function(element) { fullscreen.requestFullScreen = function(element) {
if (typeof element === 'undefined') { if (_is.undefined(element)) {
element = document.body; element = document.body;
} }
return (this.prefix === '') ? element.requestFullScreen() : element[this.prefix + (this.prefix == 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')](); return (this.prefix === '') ? element.requestFullScreen() : element[this.prefix + (this.prefix == 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')]();
@ -878,7 +905,9 @@
} }
// Toggle state // Toggle state
_toggleState(plyr.buttons.fullscreen, false); if (plyr.buttons && plyr.buttons.fullscreen) {
_toggleState(plyr.buttons.fullscreen, false);
}
// Setup focus trap // Setup focus trap
_focusTrap(); _focusTrap();
@ -887,6 +916,7 @@
// Setup captions // Setup captions
function _setupCaptions() { function _setupCaptions() {
// Bail if not HTML5 video
if (plyr.type !== 'video') { if (plyr.type !== 'video') {
return; return;
} }
@ -1041,12 +1071,12 @@
container.innerHTML = ''; container.innerHTML = '';
// Default to empty // Default to empty
if (typeof caption === 'undefined') { if (_is.undefined(caption)) {
caption = ''; caption = '';
} }
// Set the span content // Set the span content
if (typeof caption === 'string') { if (_is.undefined(caption)) {
content.innerHTML = caption.trim(); content.innerHTML = caption.trim();
} }
else { else {
@ -1106,7 +1136,7 @@
// Check time is a number, if not use currentTime // Check time is a number, if not use currentTime
// IE has a bug where currentTime doesn't go to 0 // IE has a bug where currentTime doesn't go to 0
// https://twitter.com/Sam_Potts/status/573715746506731521 // https://twitter.com/Sam_Potts/status/573715746506731521
time = typeof time === 'number' ? time : plyr.media.currentTime; time = _is.number(time) ? time : plyr.media.currentTime;
// If there's no subs available, bail // If there's no subs available, bail
if (!plyr.captions[plyr.subcount]) { if (!plyr.captions[plyr.subcount]) {
@ -1197,7 +1227,7 @@
// Add elements to HTML5 media (source, tracks, etc) // Add elements to HTML5 media (source, tracks, etc)
function _insertChildElements(type, attributes) { function _insertChildElements(type, attributes) {
if (typeof attributes === 'string') { if (_is.string(attributes)) {
_insertElement(type, plyr.media, { src: attributes }); _insertElement(type, plyr.media, { src: attributes });
} }
else if (attributes.constructor === Array) { else if (attributes.constructor === Array) {
@ -1247,13 +1277,13 @@
if (config.selectors.controls.container !== null) { if (config.selectors.controls.container !== null) {
container = config.selectors.controls.container; container = config.selectors.controls.container;
if (typeof selector === 'string') { if (_is.string(container)) {
container = document.querySelector(container); container = document.querySelector(container);
} }
} }
// Inject into the container by default // Inject into the container by default
if (!(container instanceof HTMLElement)) { if (!_is.htmlElement(container)) {
container = plyr.container container = plyr.container
} }
@ -1350,7 +1380,7 @@
var label = config.i18n.play; var label = config.i18n.play;
// If there's a media title set, use that for the label // If there's a media title set, use that for the label
if (typeof(config.title) !== 'undefined' && config.title.length) { if (!_is.undefined(config.title) && config.title.length) {
label += ', ' + config.title; label += ', ' + config.title;
} }
@ -1363,7 +1393,7 @@
// Set iframe title // Set iframe title
// https://github.com/Selz/plyr/issues/124 // https://github.com/Selz/plyr/issues/124
if (iframe instanceof HTMLElement) { if (_is.htmlElement(iframe)) {
iframe.setAttribute('title', config.i18n.frameTitle.replace('{title}', config.title)); iframe.setAttribute('title', config.i18n.frameTitle.replace('{title}', config.title));
} }
} }
@ -1443,7 +1473,7 @@
container.setAttribute('id', id); container.setAttribute('id', id);
// Setup API // Setup API
if (typeof YT === 'object') { if (_is.object(window.YT)) {
_youTubeReady(mediaId, container); _youTubeReady(mediaId, container);
} }
else { else {
@ -1464,43 +1494,35 @@
} }
// Vimeo // Vimeo
else if (plyr.type === 'vimeo') { else if (plyr.type === 'vimeo') {
// Inject the iframe // Vimeo needs an extra div to hide controls on desktop (which has full support)
var vimeo = document.createElement('iframe');
// Watch for iframe load
vimeo.loaded = false;
_on(vimeo, 'load', function() { vimeo.loaded = true; });
_setAttributes(vimeo, {
'src': 'https://player.vimeo.com/video/' + mediaId + '?player_id=' + id + '&api=1&badge=0&byline=0&portrait=0&title=0',
'id': id,
'allowfullscreen': '',
'frameborder': 0
});
// If full support, we can use custom controls (hiding Vimeos), if not, use Vimeo
if (plyr.supported.full) { if (plyr.supported.full) {
container.appendChild(vimeo);
plyr.media.appendChild(container); plyr.media.appendChild(container);
} }
else { else {
plyr.media.appendChild(vimeo); container = plyr.media;
} }
// Set ID
container.setAttribute('id', id);
// Load the API if not already // Load the API if not already
if (!('$f' in window)) { if (!_is.object(window.Vimeo)) {
_injectScript(config.urls.vimeo.api); _injectScript(config.urls.vimeo.api);
}
// Wait for fragaloop load // Wait for fragaloop load
var vimeoTimer = window.setInterval(function() { var vimeoTimer = window.setInterval(function() {
if ('$f' in window && vimeo.loaded) { if (_is.object(window.Vimeo)) {
window.clearInterval(vimeoTimer); window.clearInterval(vimeoTimer);
_vimeoReady.call(vimeo); _vimeoReady(mediaId, container);
} }
}, 50); }, 50);
}
else {
_vimeoReady(mediaId, container);
}
} }
// Soundcloud // Soundcloud
// TODO: Currently unsupported and undocumented
else if (plyr.type === 'soundcloud') { else if (plyr.type === 'soundcloud') {
// Inject the iframe // Inject the iframe
var soundCloud = document.createElement('iframe'); var soundCloud = document.createElement('iframe');
@ -1556,7 +1578,7 @@
// Setup instance // Setup instance
// https://developers.google.com/youtube/iframe_api_reference // https://developers.google.com/youtube/iframe_api_reference
plyr.embed = new YT.Player(container.id, { plyr.embed = new window.YT.Player(container.id, {
videoId: videoId, videoId: videoId,
playerVars: { playerVars: {
autoplay: (config.autoplay ? 1 : 0), autoplay: (config.autoplay ? 1 : 0),
@ -1684,86 +1706,94 @@
} }
// Vimeo ready // Vimeo ready
function _vimeoReady() { function _vimeoReady(mediaId, container) {
/* jshint validthis: true */ // Setup player
plyr.embed = $f(this); plyr.embed = new window.Vimeo.Player(container.id, {
id: mediaId,
loop: config.loop,
autoplay: config.autoplay,
byline: false,
portrait: false,
title: false
});
// Setup on ready // Create a faux HTML5 API using the Vimeo API
plyr.embed.addEvent('ready', function() { plyr.media.play = function() {
plyr.embed.play();
// Create a faux HTML5 API using the Vimeo API plyr.media.paused = false;
plyr.media.play = function() { };
plyr.embed.api('play'); plyr.media.pause = function() {
plyr.media.paused = false; plyr.embed.pause();
};
plyr.media.pause = function() {
plyr.embed.api('pause');
plyr.media.paused = true;
};
plyr.media.stop = function() {
plyr.embed.api('stop');
plyr.media.paused = true;
};
plyr.media.paused = true; plyr.media.paused = true;
plyr.media.currentTime = 0; };
plyr.media.stop = function() {
plyr.embed.stop();
plyr.media.paused = true;
};
plyr.media.paused = true;
plyr.media.currentTime = 0;
// Update UI // Update UI
_embedReady(); _embedReady();
plyr.embed.api('getCurrentTime', function (value) { plyr.embed.getCurrentTime().then(function (value) {
plyr.media.currentTime = value; plyr.media.currentTime = value;
// Trigger timeupdate // Trigger timeupdate
_triggerEvent(plyr.media, 'timeupdate'); _triggerEvent(plyr.media, 'timeupdate');
}); });
plyr.embed.api('getDuration', function(value) { plyr.embed.getDuration().then(function(value) {
plyr.media.duration = value; plyr.media.duration = value;
// Display duration if available // Display duration if available
_displayDuration(); _displayDuration();
}); });
plyr.embed.addEvent('play', function() { // TODO: Captions
plyr.media.paused = false; /*if (config.captions.defaultActive) {
_triggerEvent(plyr.media, 'play'); plyr.embed.enableTextTrack('en');
_triggerEvent(plyr.media, 'playing'); }*/
});
plyr.embed.addEvent('pause', function() { // Fix keyboard focus issues
plyr.media.paused = true; // https://github.com/Selz/plyr/issues/317
_triggerEvent(plyr.media, 'pause'); plyr.embed.on('loaded', function() {
}); if(_is.htmlElement(plyr.embed.element)) {
plyr.embed.element.setAttribute('tabindex', '-1');
plyr.embed.addEvent('playProgress', function(data) {
plyr.media.seeking = false;
plyr.media.currentTime = data.seconds;
_triggerEvent(plyr.media, 'timeupdate');
});
plyr.embed.addEvent('loadProgress', function(data) {
plyr.media.buffered = data.percent;
_triggerEvent(plyr.media, 'progress');
if (parseInt(data.percent) === 1) {
// Trigger event
_triggerEvent(plyr.media, 'canplaythrough');
}
});
plyr.embed.addEvent('finish', function() {
plyr.media.paused = true;
_triggerEvent(plyr.media, 'ended');
});
// Always seek to 0
// plyr.embed.api('seekTo', 0);
// Autoplay
if (config.autoplay) {
plyr.embed.api('play');
} }
}); });
plyr.embed.on('play', function() {
plyr.media.paused = false;
_triggerEvent(plyr.media, 'play');
_triggerEvent(plyr.media, 'playing');
});
plyr.embed.on('pause', function() {
plyr.media.paused = true;
_triggerEvent(plyr.media, 'pause');
});
plyr.embed.on('timeupdate', function(data) {
plyr.media.seeking = false;
plyr.media.currentTime = data.seconds;
_triggerEvent(plyr.media, 'timeupdate');
});
plyr.embed.on('progress', function(data) {
plyr.media.buffered = data.percent;
_triggerEvent(plyr.media, 'progress');
if (parseInt(data.percent) === 1) {
// Trigger event
_triggerEvent(plyr.media, 'canplaythrough');
}
});
plyr.embed.on('ended', function() {
plyr.media.paused = true;
_triggerEvent(plyr.media, 'ended');
});
} }
// Soundcloud ready // Soundcloud ready
@ -1878,7 +1908,7 @@
// Rewind // Rewind
function _rewind(seekTime) { function _rewind(seekTime) {
// Use default if needed // Use default if needed
if (typeof seekTime !== 'number') { if (!_is.number(seekTime)) {
seekTime = config.seekTime; seekTime = config.seekTime;
} }
_seek(plyr.media.currentTime - seekTime); _seek(plyr.media.currentTime - seekTime);
@ -1887,7 +1917,7 @@
// Fast forward // Fast forward
function _forward(seekTime) { function _forward(seekTime) {
// Use default if needed // Use default if needed
if (typeof seekTime !== 'number') { if (!_is.number(seekTime)) {
seekTime = config.seekTime; seekTime = config.seekTime;
} }
_seek(plyr.media.currentTime + seekTime); _seek(plyr.media.currentTime + seekTime);
@ -1901,11 +1931,11 @@
duration = _getDuration(); duration = _getDuration();
// Explicit position // Explicit position
if (typeof input === 'number') { if (_is.number(input)) {
targetTime = input; targetTime = input;
} }
// Event // Event
else if (input.type && _inArray(['input', 'change'], input.type)) { else if (_is.object(input) && _inArray(['input', 'change'], input.type)) {
// It's the seek slider // It's the seek slider
// Seek to the selected time // Seek to the selected time
targetTime = ((input.target.value / input.target.max) * duration); targetTime = ((input.target.value / input.target.max) * duration);
@ -1939,7 +1969,7 @@
case 'vimeo': case 'vimeo':
// Round to nearest second for vimeo // Round to nearest second for vimeo
plyr.embed.api('seekTo', targetTime.toFixed(0)); plyr.embed.setCurrentTime(targetTime.toFixed(0));
break; break;
case 'soundcloud': case 'soundcloud':
@ -2060,7 +2090,9 @@
_focusTrap(plyr.isFullscreen); _focusTrap(plyr.isFullscreen);
// Set button state // Set button state
_toggleState(plyr.buttons.fullscreen, plyr.isFullscreen); if (plyr.buttons && plyr.buttons.fullscreen) {
_toggleState(plyr.buttons.fullscreen, plyr.isFullscreen);
}
// Trigger an event // Trigger an event
_triggerEvent(plyr.container, plyr.isFullscreen ? 'enterfullscreen' : 'exitfullscreen', true); _triggerEvent(plyr.container, plyr.isFullscreen ? 'enterfullscreen' : 'exitfullscreen', true);
@ -2082,7 +2114,7 @@
// Mute // Mute
function _toggleMute(muted) { function _toggleMute(muted) {
// If the method is called without parameter, toggle based on current value // If the method is called without parameter, toggle based on current value
if (typeof muted !== 'boolean') { if (!_is.boolean(muted)) {
muted = !plyr.media.muted; muted = !plyr.media.muted;
} }
@ -2106,9 +2138,6 @@
break; break;
case 'vimeo': case 'vimeo':
plyr.embed.api('setVolume', plyr.media.muted ? 0 : parseFloat(config.volume / config.volumeMax));
break;
case 'soundcloud': case 'soundcloud':
plyr.embed.setVolume(plyr.media.muted ? 0 : parseFloat(config.volume / config.volumeMax)); plyr.embed.setVolume(plyr.media.muted ? 0 : parseFloat(config.volume / config.volumeMax));
break; break;
@ -2125,7 +2154,7 @@
min = config.volumeMin; min = config.volumeMin;
// Use default if no value specified // Use default if no value specified
if (typeof volume === 'undefined') { if (_is.undefined(volume)) {
volume = config.volume; volume = config.volume;
if (config.storage.enabled && _storage().supported) { if (config.storage.enabled && _storage().supported) {
@ -2161,16 +2190,12 @@
// Embeds // Embeds
if (_inArray(config.types.embed, plyr.type)) { if (_inArray(config.types.embed, plyr.type)) {
// YouTube
switch(plyr.type) { switch(plyr.type) {
case 'youtube': case 'youtube':
plyr.embed.setVolume(plyr.media.volume * 100); plyr.embed.setVolume(plyr.media.volume * 100);
break; break;
case 'vimeo': case 'vimeo':
plyr.embed.api('setVolume', plyr.media.volume);
break;
case 'soundcloud': case 'soundcloud':
plyr.embed.setVolume(plyr.media.volume); plyr.embed.setVolume(plyr.media.volume);
break; break;
@ -2237,7 +2262,7 @@
} }
// If the method is called without parameter, toggle based on current value // If the method is called without parameter, toggle based on current value
if (typeof show !== 'boolean') { if (!_is.boolean(show)) {
show = (plyr.container.className.indexOf(config.classes.captions.active) === -1); show = (plyr.container.className.indexOf(config.classes.captions.active) === -1);
} }
@ -2307,7 +2332,7 @@
return _getPercentage(buffered.end(0), duration); return _getPercentage(buffered.end(0), duration);
} }
// YouTube returns between 0 and 1 // YouTube returns between 0 and 1
else if (typeof buffered === 'number') { else if (_is.number(buffered)) {
return (buffered * 100); return (buffered * 100);
} }
@ -2329,11 +2354,11 @@
} }
// Default to 0 // Default to 0
if (typeof value === 'undefined') { if (_is.undefined(value)) {
value = 0; value = 0;
} }
// Default to buffer or bail // Default to buffer or bail
if (typeof progress === 'undefined') { if (_is.undefined(progress)) {
if (plyr.progress && plyr.progress.buffer) { if (plyr.progress && plyr.progress.buffer) {
progress = plyr.progress.buffer; progress = plyr.progress.buffer;
} }
@ -2343,7 +2368,7 @@
} }
// One progress element passed // One progress element passed
if (progress instanceof HTMLElement) { if (_is.htmlElement(progress)) {
progress.value = value; progress.value = value;
} }
// Object of progress + text element // Object of progress + text element
@ -2424,7 +2449,7 @@
// Update seek range and progress // Update seek range and progress
function _updateSeekDisplay(time) { function _updateSeekDisplay(time) {
// Default to 0 // Default to 0
if (typeof time !== 'number') { if (!_is.number(time)) {
time = 0; time = 0;
} }
@ -2501,7 +2526,7 @@
show = toggle; show = toggle;
// Default to false if no boolean // Default to false if no boolean
if (typeof toggle !== 'boolean') { if (!_is.boolean(toggle)) {
if (toggle && toggle.type) { if (toggle && toggle.type) {
// Is the enter fullscreen event // Is the enter fullscreen event
isEnterFullscreen = (toggle.type === 'enterfullscreen'); isEnterFullscreen = (toggle.type === 'enterfullscreen');
@ -2559,7 +2584,7 @@
// Add common function to retrieve media source // Add common function to retrieve media source
function _source(source) { function _source(source) {
// If not null or undefined, parse it // If not null or undefined, parse it
if (typeof source !== 'undefined') { if (!_is.undefined(source)) {
_updateSource(source); _updateSource(source);
return; return;
} }
@ -2572,7 +2597,7 @@
break; break;
case 'vimeo': case 'vimeo':
plyr.embed.api('getVideoUrl', function (value) { plyr.embed.getVideoUrl.then(function (value) {
url = value; url = value;
}); });
break; break;
@ -2594,7 +2619,7 @@
// Update source // Update source
// Sources are not checked for support so be careful // Sources are not checked for support so be careful
function _updateSource(source) { function _updateSource(source) {
if (typeof source === 'undefined' || !('sources' in source) || !source.sources.length) { if (!_is.object(source) || !('sources' in source) || !source.sources.length) {
_warn('Invalid source format'); _warn('Invalid source format');
return; return;
} }
@ -2671,7 +2696,7 @@
_prependChild(plyr.container, plyr.media); _prependChild(plyr.container, plyr.media);
// Autoplay the new source? // Autoplay the new source?
if (typeof source.autoplay !== 'undefined') { if (_is.boolean(source.autoplay)) {
config.autoplay = source.autoplay; config.autoplay = source.autoplay;
} }
@ -2800,7 +2825,7 @@
for (var button in plyr.buttons) { for (var button in plyr.buttons) {
var element = plyr.buttons[button]; var element = plyr.buttons[button];
if (element instanceof NodeList) { if (_is.nodeList(element)) {
for (var i = 0; i < element.length; i++) { for (var i = 0; i < element.length; i++) {
_toggleClass(element[i], config.classes.tabFocus, (element[i] === focused)); _toggleClass(element[i], config.classes.tabFocus, (element[i] === focused));
} }
@ -3023,9 +3048,8 @@
// Set blank video src attribute // Set blank video src attribute
// This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
// Small mp4: https://github.com/mathiasbynens/small/blob/master/mp4.mp4
// Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
plyr.media.setAttribute('src', 'data:video/mp4;base64,AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAAGm1kYXQAAAGzABAHAAABthBgUYI9t+8AAAMNbW9vdgAAAGxtdmhkAAAAAMXMvvrFzL76AAAD6AAAACoAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAABhpb2RzAAAAABCAgIAHAE/////+/wAAAiF0cmFrAAAAXHRraGQAAAAPxcy++sXMvvoAAAABAAAAAAAAACoAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAgAAAAIAAAAAAG9bWRpYQAAACBtZGhkAAAAAMXMvvrFzL76AAAAGAAAAAEVxwAAAAAALWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABWaWRlb0hhbmRsZXIAAAABaG1pbmYAAAAUdm1oZAAAAAEAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAShzdGJsAAAAxHN0c2QAAAAAAAAAAQAAALRtcDR2AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAgACABIAAAASAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGP//AAAAXmVzZHMAAAAAA4CAgE0AAQAEgICAPyARAAAAAAMNQAAAAAAFgICALQAAAbABAAABtYkTAAABAAAAASAAxI2IAMUARAEUQwAAAbJMYXZjNTMuMzUuMAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAAABAAAAAQAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAASAAAAAQAAABRzdGNvAAAAAAAAAAEAAAAsAAAAYHVkdGEAAABYbWV0YQAAAAAAAAAhaGRscgAAAAAAAAAAbWRpcmFwcGwAAAAAAAAAAAAAAAAraWxzdAAAACOpdG9vAAAAG2RhdGEAAAABAAAAAExhdmY1My4yMS4x'); plyr.media.setAttribute('src', 'https://cdn.selz.com/plyr/blank.mp4');
// Load the new empty source // Load the new empty source
// This will cancel existing requests // This will cancel existing requests
@ -3274,7 +3298,7 @@
var x = new XMLHttpRequest(); var x = new XMLHttpRequest();
// If the id is set and sprite exists, bail // If the id is set and sprite exists, bail
if (typeof id === 'string' && document.querySelector('#' + id) !== null) { if (_is.string(id) && document.querySelector('#' + id) !== null) {
return; return;
} }
@ -3290,7 +3314,7 @@
x.onload = function() { x.onload = function() {
var c = document.createElement('div'); var c = document.createElement('div');
c.setAttribute('hidden', ''); c.setAttribute('hidden', '');
if (typeof id === 'string') { if (_is.string(id)) {
c.setAttribute('id', id); c.setAttribute('id', id);
} }
c.innerHTML = x.responseText; c.innerHTML = x.responseText;
@ -3348,17 +3372,17 @@
// Select the elements // Select the elements
// Assume elements is a NodeList by default // Assume elements is a NodeList by default
if (typeof targets === 'string') { if (_is.string(targets)) {
targets = document.querySelectorAll(targets); targets = document.querySelectorAll(targets);
} }
// Single HTMLElement passed // Single HTMLElement passed
else if (targets instanceof HTMLElement) { else if (_is.htmlElement(targets)) {
targets = [targets]; targets = [targets];
} }
// No selector passed, possibly options as first argument // No selector passed, possibly options as first argument
else if (!(targets instanceof NodeList) && typeof targets !== 'string') { else if (!_is.nodeList(targets) && !_is.array(targets) && !_is.string(targets)) {
// If options are the first argument // If options are the first argument
if (typeof options === 'undefined' && typeof targets === 'object') { if (_is.undefined(options) && _is.object(targets)) {
options = targets; options = targets;
} }
@ -3366,17 +3390,17 @@
targets = document.querySelectorAll(selector); targets = document.querySelectorAll(selector);
} }
// Convert NodeList to array
if (_is.nodeList(targets)) {
targets = Array.prototype.slice.call(targets);
}
// Bail if disabled or no basic support // Bail if disabled or no basic support
// You may want to disable certain UAs etc // You may want to disable certain UAs etc
if (!supported().basic || !targets.length) { if (!supported().basic || !targets.length) {
return false; return false;
} }
// Convert NodeList to array
if (targets instanceof NodeList) {
targets = Array.prototype.slice.call(targets);
}
// Check if the targets have multiple media elements // Check if the targets have multiple media elements
for (var i = 0; i < targets.length; i++) { for (var i = 0; i < targets.length; i++) {
var target = targets[i]; var target = targets[i];
@ -3452,7 +3476,7 @@
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent // https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
(function () { (function () {
if (typeof window.CustomEvent === 'function') { if (typeof window.CustomEvent === 'function') {
return false; return;
} }
function CustomEvent(event, params) { function CustomEvent(event, params) {

View File

@ -225,6 +225,8 @@
border-radius: 2px; border-radius: 2px;
padding: floor(@plyr-control-spacing / 3) @plyr-control-spacing; padding: floor(@plyr-control-spacing / 3) @plyr-control-spacing;
background: @plyr-captions-bg; background: @plyr-captions-bg;
box-decoration-break: clone;
line-height: 150%;
} }
span:empty { span:empty {
display: none; display: none;

View File

@ -225,6 +225,8 @@
border-radius: 2px; border-radius: 2px;
padding: floor($plyr-control-spacing / 3) $plyr-control-spacing; padding: floor($plyr-control-spacing / 3) $plyr-control-spacing;
background: $plyr-captions-bg; background: $plyr-captions-bg;
box-decoration-break: clone;
line-height: 150%;
} }
span:empty { span:empty {
display: none; display: none;