API improvements
This commit is contained in:
parent
388cb4df39
commit
c61db87fd6
@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.0.28
|
||||||
|
- Added API support for browsers that don't have full plyr support (pretty much <=IE9 and `<video>` on iPhone/iPod)
|
||||||
|
|
||||||
|
## v1.0.27
|
||||||
|
- Keyboard accessibility improvements (Fixes #66)
|
||||||
|
|
||||||
## v1.0.26
|
## v1.0.26
|
||||||
- Fixes for SASS (cheers @brunowego)
|
- Fixes for SASS (cheers @brunowego)
|
||||||
- Indentation reset to 4 spaces
|
- Indentation reset to 4 spaces
|
||||||
|
2
dist/plyr.js
vendored
2
dist/plyr.js
vendored
File diff suppressed because one or more lines are too long
@ -6,7 +6,7 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<!-- Docs styles -->
|
<!-- Docs styles -->
|
||||||
<link rel="stylesheet" href="//cdn.plyr.io/1.0.27/docs.css">
|
<link rel="stylesheet" href="//cdn.plyr.io/1.0.28/docs.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main>
|
<main>
|
||||||
|
@ -8,10 +8,10 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<!-- Styles -->
|
<!-- Styles -->
|
||||||
<link rel="stylesheet" href="//cdn.plyr.io/1.0.27/plyr.css">
|
<link rel="stylesheet" href="//cdn.plyr.io/1.0.28/plyr.css">
|
||||||
|
|
||||||
<!-- Docs styles -->
|
<!-- Docs styles -->
|
||||||
<link rel="stylesheet" href="//cdn.plyr.io/1.0.27/docs.css">
|
<link rel="stylesheet" href="//cdn.plyr.io/1.0.28/docs.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
@ -67,13 +67,29 @@
|
|||||||
<!-- Load SVG defs -->
|
<!-- Load SVG defs -->
|
||||||
<!-- You should bundle all SVG/Icons into one file using a build tool such as gulp and svg store -->
|
<!-- You should bundle all SVG/Icons into one file using a build tool such as gulp and svg store -->
|
||||||
<script>
|
<script>
|
||||||
(function(d,p){var a=new XMLHttpRequest(),b=d.body;a.open("GET",p,!0);a.send();a.onload=function(){var c=d.createElement("div");c.style.display="none";c.innerHTML=a.responseText;b.insertBefore(c,b.childNodes[0])}})(document,"//cdn.plyr.io/1.0.27/sprite.svg");
|
(function(d, u){
|
||||||
|
var a = new XMLHttpRequest(),
|
||||||
|
b = d.body;
|
||||||
|
|
||||||
|
// Check for CORS support
|
||||||
|
// If you're loading from same domain, you can remove the if statement
|
||||||
|
if("withCredentials" in a) {
|
||||||
|
a.open("GET", u, true);
|
||||||
|
a.send();
|
||||||
|
a.onload = function(){
|
||||||
|
var c = d.createElement("div");
|
||||||
|
c.style.display="none";
|
||||||
|
c.innerHTML = a.responseText;
|
||||||
|
b.insertBefore(c, b.childNodes[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})(document, "https://cdn.plyr.io/1.0.28/sprite.svg");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Plyr core script -->
|
<!-- Plyr core script -->
|
||||||
<script src="//cdn.plyr.io/1.0.27/plyr.js"></script>
|
<script src="//cdn.plyr.io/1.0.28/plyr.js"></script>
|
||||||
|
|
||||||
<!-- Docs script -->
|
<!-- Docs script -->
|
||||||
<script src="//cdn.plyr.io/1.0.27/docs.js"></script>
|
<script src="//cdn.plyr.io/1.0.28/docs.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "plyr",
|
"name": "plyr",
|
||||||
"version": "1.0.27",
|
"version": "1.0.28",
|
||||||
"description": "A simple HTML5 media player using custom controls",
|
"description": "A simple HTML5 media player using custom controls",
|
||||||
"homepage": "http://plyr.io",
|
"homepage": "http://plyr.io",
|
||||||
"main": "gulpfile.js",
|
"main": "gulpfile.js",
|
||||||
|
16
readme.md
16
readme.md
@ -10,7 +10,7 @@ We wanted a lightweight, accessible and customisable media player that just supp
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
- **Accessible** - full support for captions and screen readers.
|
- **Accessible** - full support for captions and screen readers.
|
||||||
- **Lightweight** - just 5.7KB minified and gzipped.
|
- **Lightweight** - just 6KB minified and gzipped.
|
||||||
- **Customisable** - make the player look how you want with the markup you want.
|
- **Customisable** - make the player look how you want with the markup you want.
|
||||||
- **Semantic** - uses the *right* elements. `<input type="range">` for volume and `<progress>` for progress and well, `<button>`s for buttons. There's no `<span>` or `<a href="#">` button hacks.
|
- **Semantic** - uses the *right* elements. `<input type="range">` for volume and `<progress>` for progress and well, `<button>`s for buttons. There's no `<span>` or `<a href="#">` button hacks.
|
||||||
- **Responsive** - as you'd expect these days.
|
- **Responsive** - as you'd expect these days.
|
||||||
@ -38,7 +38,7 @@ If you have any cool ideas or features, please let me know by [creating an issue
|
|||||||
|
|
||||||
Check `docs/index.html` and `docs/dist/docs.js` for an example setup.
|
Check `docs/index.html` and `docs/dist/docs.js` for an example setup.
|
||||||
|
|
||||||
**Heads up**, the example `index.html` file needs to be served from a webserver (such as Apache, Nginx, IIS or similar) unless you change the file sources to include http or https. e.g. change `//cdn.plyr.io/1.0.27/plyr.js` to `https://cdn.plyr.io/1.0.27/plyr.js`
|
**Heads up**, the example `index.html` file needs to be served from a webserver (such as Apache, Nginx, IIS or similar) unless you change the file sources to include http or https. e.g. change `//cdn.plyr.io/1.0.28/plyr.js` to `https://cdn.plyr.io/1.0.28/plyr.js`
|
||||||
|
|
||||||
### Bower
|
### Bower
|
||||||
If bower is your thang, you can grab Plyr using:
|
If bower is your thang, you can grab Plyr using:
|
||||||
@ -51,11 +51,11 @@ More info on setting up dependencies can be found in the [Bower Docs](http://bow
|
|||||||
If you want to use our CDN, you can use the following. HTTPS (SSL) is supported.
|
If you want to use our CDN, you can use the following. HTTPS (SSL) is supported.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<link rel="stylesheet" href="//cdn.plyr.io/1.0.27/plyr.css">
|
<link rel="stylesheet" href="//cdn.plyr.io/1.0.28/plyr.css">
|
||||||
<script src="//cdn.plyr.io/1.0.27/plyr.js"></script>
|
<script src="//cdn.plyr.io/1.0.28/plyr.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also access the `sprite.svg` file at `//cdn.plyr.io/1.0.27/sprite.svg`.
|
You can also access the `sprite.svg` file at `//cdn.plyr.io/1.0.28/sprite.svg`.
|
||||||
|
|
||||||
### CSS
|
### CSS
|
||||||
If you want to use the default css, add the `plyr.css` file from /dist into your head, or even better use `plyr.less` or `plyr.sass` file included in `/src` in your build to save a request.
|
If you want to use the default css, add the `plyr.css` file from /dist into your head, or even better use `plyr.less` or `plyr.sass` file included in `/src` in your build to save a request.
|
||||||
@ -359,15 +359,15 @@ Fullscreen in Plyr is supported for all browsers that [currently support it](htt
|
|||||||
<td>✔</td>
|
<td>✔</td>
|
||||||
<td>✔</td>
|
<td>✔</td>
|
||||||
<td>✔</td>
|
<td>✔</td>
|
||||||
<td>✖²</td>
|
<td>API²</td>
|
||||||
<td>✔³</td>
|
<td>✔³</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
¹ iPhone forces the native player for `<video>` so no customisation possible. `<audio>` elements have volume controls disabled.
|
¹ Mobile Safari on the iPhone forces the native player for `<video>` so no useful customisation is possible. `<audio>` elements have volume controls disabled.
|
||||||
|
|
||||||
² Native player used (no support for `<progress>` or `<input type="range">`)
|
² Native player used (no support for `<progress>` or `<input type="range">`) but the API is supported (v1.0.28+)
|
||||||
|
|
||||||
³ IE10 has no native fullscreen support, fallback can be used (see options)
|
³ IE10 has no native fullscreen support, fallback can be used (see options)
|
||||||
|
|
||||||
|
153
src/js/plyr.js
153
src/js/plyr.js
@ -1,6 +1,6 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Plyr
|
// Plyr
|
||||||
// plyr.js v1.0.27
|
// plyr.js v1.0.28
|
||||||
// https://github.com/selz/plyr
|
// https://github.com/selz/plyr
|
||||||
// License: The MIT License (MIT)
|
// License: The MIT License (MIT)
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
@ -219,7 +219,7 @@
|
|||||||
// Check for mime type support against a player instance
|
// Check for mime type support against a player instance
|
||||||
// Credits: http://diveintohtml5.info/everything.html
|
// Credits: http://diveintohtml5.info/everything.html
|
||||||
// Related: http://www.leanbackplayer.com/test/h5mt.html
|
// Related: http://www.leanbackplayer.com/test/h5mt.html
|
||||||
function _support(player, mimeType) {
|
function _supportMime(player, mimeType) {
|
||||||
var media = player.media;
|
var media = player.media;
|
||||||
|
|
||||||
// Only check video types for video players
|
// Only check video types for video players
|
||||||
@ -496,7 +496,7 @@
|
|||||||
// Seek the manual caption time and update UI
|
// Seek the manual caption time and update UI
|
||||||
function _seekManualCaptions(time) {
|
function _seekManualCaptions(time) {
|
||||||
// If it's not video, or we're using textTracks, bail.
|
// If it's not video, or we're using textTracks, bail.
|
||||||
if (player.usingTextTracks || player.type !== "video") {
|
if (player.usingTextTracks || player.type !== "video" || !player.supported.full) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -681,8 +681,6 @@
|
|||||||
|
|
||||||
// Setup media
|
// Setup media
|
||||||
function _setupMedia() {
|
function _setupMedia() {
|
||||||
player.media = player.container.querySelectorAll("audio, video")[0];
|
|
||||||
|
|
||||||
// If there's no media, bail
|
// If there's no media, bail
|
||||||
if(!player.media) {
|
if(!player.media) {
|
||||||
_log("No audio or video element found!", true);
|
_log("No audio or video element found!", true);
|
||||||
@ -690,10 +688,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove native video controls
|
// Remove native video controls
|
||||||
player.media.removeAttribute("controls");
|
if(player.supported.full) {
|
||||||
|
player.media.removeAttribute("controls");
|
||||||
// Set media type
|
}
|
||||||
player.type = player.media.tagName.toLowerCase();
|
|
||||||
|
|
||||||
// Add type class
|
// Add type class
|
||||||
_toggleClass(player.container, config.classes[player.type], true);
|
_toggleClass(player.container, config.classes[player.type], true);
|
||||||
@ -707,7 +704,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inject the player wrapper
|
// Inject the player wrapper
|
||||||
if(player.type === "video") {
|
if(player.type === "video" && player.supported.full) {
|
||||||
// Create the wrapper div
|
// Create the wrapper div
|
||||||
var wrapper = document.createElement("div");
|
var wrapper = document.createElement("div");
|
||||||
wrapper.setAttribute("class", config.classes.videoWrapper);
|
wrapper.setAttribute("class", config.classes.videoWrapper);
|
||||||
@ -1027,8 +1024,15 @@
|
|||||||
volume = 10;
|
volume = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
player.volume.value = volume;
|
// If the controls are there
|
||||||
|
if(player.supported.full) {
|
||||||
|
player.volume.value = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the player volume
|
||||||
player.media.volume = parseFloat(volume / 10);
|
player.media.volume = parseFloat(volume / 10);
|
||||||
|
|
||||||
|
// Update the UI
|
||||||
_checkMute();
|
_checkMute();
|
||||||
|
|
||||||
// Store the volume in storage
|
// Store the volume in storage
|
||||||
@ -1040,24 +1044,35 @@
|
|||||||
// 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 active === "undefined") {
|
if(typeof muted === "undefined") {
|
||||||
muted = !player.media.muted;
|
muted = !player.media.muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the controls are there
|
||||||
|
if(player.supported.full) {
|
||||||
player.buttons.mute.checked = muted;
|
player.buttons.mute.checked = muted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set mute on the player
|
||||||
player.media.muted = muted;
|
player.media.muted = muted;
|
||||||
|
|
||||||
|
// Update UI
|
||||||
_checkMute();
|
_checkMute();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle captions
|
// Toggle captions
|
||||||
function _toggleCaptions(active) {
|
function _toggleCaptions(show) {
|
||||||
// If the method is called without parameter, toggle based on current value
|
if(!player.supported.plyr) {
|
||||||
if(typeof active === "undefined") {
|
return;
|
||||||
active = (player.container.className.indexOf(config.classes.captions.active) === -1);
|
|
||||||
player.buttons.captions.checked = active;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (active) {
|
// If the method is called without parameter, toggle based on current value
|
||||||
|
if(typeof active === "undefined") {
|
||||||
|
show = (player.container.className.indexOf(config.classes.captions.active) === -1);
|
||||||
|
player.buttons.captions.checked = show;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show) {
|
||||||
_toggleClass(player.container, config.classes.captions.active, true);
|
_toggleClass(player.container, config.classes.captions.active, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1214,7 +1229,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset time display
|
// Reset time display
|
||||||
_timeUpdate();
|
if(player.supported.full) {
|
||||||
|
_timeUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
// Re-load sources
|
// Re-load sources
|
||||||
player.media.load();
|
player.media.load();
|
||||||
@ -1270,7 +1287,9 @@
|
|||||||
_on(player.buttons.fullscreen, "click", _toggleFullscreen);
|
_on(player.buttons.fullscreen, "click", _toggleFullscreen);
|
||||||
|
|
||||||
// Handle user exiting fullscreen by escaping etc
|
// Handle user exiting fullscreen by escaping etc
|
||||||
_on(document, fullscreen.fullScreenEventName, _toggleFullscreen);
|
if(fullscreen.supportsFullScreen) {
|
||||||
|
_on(document, fullscreen.fullScreenEventName, _toggleFullscreen);
|
||||||
|
}
|
||||||
|
|
||||||
// Time change on media
|
// Time change on media
|
||||||
_on(player.media, "timeupdate seeking", _timeUpdate);
|
_on(player.media, "timeupdate seeking", _timeUpdate);
|
||||||
@ -1336,48 +1355,63 @@
|
|||||||
// Setup the fullscreen api
|
// Setup the fullscreen api
|
||||||
fullscreen = _fullscreen();
|
fullscreen = _fullscreen();
|
||||||
|
|
||||||
// Sniff
|
// Sniff out the browser
|
||||||
player.browser = _browserSniff();
|
player.browser = _browserSniff();
|
||||||
|
|
||||||
|
// Check for full support
|
||||||
|
player.supported = api.supported();
|
||||||
|
|
||||||
|
// If no native support, bail
|
||||||
|
if(!player.supported.basic) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the media element
|
||||||
|
player.media = player.container.querySelectorAll("audio, video")[0];
|
||||||
|
|
||||||
|
// Set media type
|
||||||
|
player.type = player.media.tagName.toLowerCase();
|
||||||
|
|
||||||
|
// If iPhone/iPod and video, customisation support is limited
|
||||||
|
if(/iPhone|iPod/i.test(navigator.userAgent) && player.type === "video") {
|
||||||
|
player.supported.full = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Debug info
|
// Debug info
|
||||||
_log(player.browser.name + " " + player.browser.version);
|
_log(player.browser.name + " " + player.browser.version);
|
||||||
|
|
||||||
// If IE8, stop customization (use fallback)
|
|
||||||
// If IE9, stop customization (use native controls)
|
|
||||||
if (player.browser.name === "IE" && (player.browser.version === 8 || player.browser.version === 9) ) {
|
|
||||||
_log("Browser not suppported.", true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup media
|
// Setup media
|
||||||
_setupMedia();
|
_setupMedia();
|
||||||
|
|
||||||
// Generate random number for id/for attribute values for controls
|
// Generate random number for id/for attribute values for controls
|
||||||
player.random = Math.floor(Math.random() * (10000));
|
player.random = Math.floor(Math.random() * (10000));
|
||||||
|
|
||||||
// Inject custom controls
|
// If there's full support
|
||||||
_injectControls();
|
if(player.supported.full) {
|
||||||
|
// Inject custom controls
|
||||||
|
_injectControls();
|
||||||
|
|
||||||
// Find the elements
|
// Find the elements
|
||||||
if(!_findElements()) {
|
if(!_findElements()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up aria-label for Play button with the title option
|
||||||
|
_setupAria();
|
||||||
|
|
||||||
|
// Captions
|
||||||
|
_setupCaptions();
|
||||||
|
|
||||||
|
// Set volume
|
||||||
|
_setVolume();
|
||||||
|
|
||||||
|
// Setup fullscreen
|
||||||
|
_setupFullscreen();
|
||||||
|
|
||||||
|
// Listeners
|
||||||
|
_listeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up aria-label for Play button with the title option
|
|
||||||
_setupAria();
|
|
||||||
|
|
||||||
// Captions
|
|
||||||
_setupCaptions();
|
|
||||||
|
|
||||||
// Set volume
|
|
||||||
_setVolume();
|
|
||||||
|
|
||||||
// Setup fullscreen
|
|
||||||
_setupFullscreen();
|
|
||||||
|
|
||||||
// Listeners
|
|
||||||
_listeners();
|
|
||||||
|
|
||||||
// Successful setup
|
// Successful setup
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1399,10 +1433,21 @@
|
|||||||
toggleCaptions: _toggleCaptions,
|
toggleCaptions: _toggleCaptions,
|
||||||
source: _parseSource,
|
source: _parseSource,
|
||||||
poster: _updatePoster,
|
poster: _updatePoster,
|
||||||
support: function(mimeType) { return _support(player, mimeType); }
|
support: function(mimeType) { return _supportMime(player, mimeType); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for support
|
||||||
|
api.supported = function() {
|
||||||
|
var browser = _browserSniff(),
|
||||||
|
basic = (!!document.createElement("audio").canPlayType && !!document.createElement("video").canPlayType);
|
||||||
|
|
||||||
|
return {
|
||||||
|
basic: basic,
|
||||||
|
full: basic && !(browser.name === "IE" && (browser.version <= 9))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Expose setup function
|
// Expose setup function
|
||||||
api.setup = function(options){
|
api.setup = function(options){
|
||||||
// Extend the default options with user specified
|
// Extend the default options with user specified
|
||||||
@ -1410,7 +1455,7 @@
|
|||||||
|
|
||||||
// If enabled carry on
|
// If enabled carry on
|
||||||
// You may want to disable certain UAs etc
|
// You may want to disable certain UAs etc
|
||||||
if(!config.enabled) {
|
if(!config.enabled || !api.supported().basic) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1423,13 +1468,6 @@
|
|||||||
// Get the current element
|
// Get the current element
|
||||||
var element = elements[i];
|
var element = elements[i];
|
||||||
|
|
||||||
// Disabled for <video> for iPhone
|
|
||||||
// Since it doesn't allow customisation
|
|
||||||
if (element.querySelectorAll("audio, video")[0].tagName.toLowerCase() === "video"
|
|
||||||
&& /iPhone/i.test(navigator.userAgent)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup a player instance and add to the element
|
// Setup a player instance and add to the element
|
||||||
if(typeof element.plyr === "undefined") {
|
if(typeof element.plyr === "undefined") {
|
||||||
// Create new instance
|
// Create new instance
|
||||||
@ -1445,4 +1483,5 @@
|
|||||||
|
|
||||||
return players;
|
return players;
|
||||||
}
|
}
|
||||||
|
|
||||||
}(this.plyr = this.plyr || {}));
|
}(this.plyr = this.plyr || {}));
|
Loading…
x
Reference in New Issue
Block a user