Compare commits

..

12 Commits

Author SHA1 Message Date
ecbda018c5 Merge branch 'master' of github.com:selz/plyr
# Conflicts:
#	src/js/plyr.js
2015-04-10 07:17:23 +10:00
5187311ff0 Bug fix for isFullscreen() in Mozilla (Fixes #38) 2015-04-10 07:16:53 +10:00
d9a94ac7b0 Version bump 2015-04-08 13:42:34 +10:00
3526e322ef Minor bug fixes 2015-04-06 19:42:26 +10:00
99cabd545d Fix for generated IDs for controls, UI tweak for audio 2015-04-06 13:25:36 +10:00
1f7f7b10de Docs tweak 2015-04-06 12:06:34 +10:00
b2421b592a Merge branch 'master' of github.com:selz/plyr 2015-04-06 11:47:43 +10:00
5322f4c62f Fullscreen API methods (Fixes #74), onSetup callback 2015-04-06 11:47:23 +10:00
7ab8647fc8 Merge pull request #75 from franks921/fs-fix-localstorage-volume-settings
fix: use custom localStorage key for volume setting
2015-04-05 21:39:08 +10:00
50c76f3d7e fix: use custom localStorage key for volume setting 2015-04-05 13:26:17 +02:00
2f4c56176d Updated screenshot 2015-04-04 12:58:09 +11:00
7c5f38311b Bug fixes for controls changes 2015-04-04 12:51:24 +11:00
12 changed files with 198 additions and 104 deletions

View File

@ -1,10 +1,28 @@
# Changelog # Changelog
## v1.1.5
- Fix for incorrect `isFullscreen()` return value in Mozilla (Fixes #38)
## v1.1.4
- Minor bug fixes
## v1.1.3
- Fixes for random id used in controls with multiple instances and one call to setup
- Audio player UI improvements
## v1.1.2
- Added an onSetup callback option
- Added fullscreen API methods `toggleFullscreen()` (must be user iniated), and `isFullscreen()`
## v1.1.1
- Fix for unsupported browser handling
- Fix for config.controls having no effect
## v1.1.0 ## v1.1.0
- Added config option to set which controls are shown (if using the default controls html) and better handling of missing controls - Added config option to set which controls are shown (if using the default controls html) and better handling of missing controls
## v1.0.31 ## v1.0.31
- Display duration on metadataloaded - Display duration on `metadataloaded`
## v1.0.30 ## v1.0.30
- Fixed bug with media longer than 60 minutes (Fixes #69) - Fixed bug with media longer than 60 minutes (Fixes #69)

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

2
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

2
docs/dist/docs.js vendored

File diff suppressed because one or more lines are too long

View File

@ -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.1.0/docs.css"> <link rel="stylesheet" href="//cdn.plyr.io/1.1.5/docs.css">
</head> </head>
<body> <body>
<main> <main>

View File

@ -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.1.0/plyr.css"> <link rel="stylesheet" href="//cdn.plyr.io/1.1.5/plyr.css">
<!-- Docs styles --> <!-- Docs styles -->
<link rel="stylesheet" href="//cdn.plyr.io/1.1.0/docs.css"> <link rel="stylesheet" href="//cdn.plyr.io/1.1.5/docs.css">
</head> </head>
<body> <body>
<header> <header>
@ -83,13 +83,13 @@
b.insertBefore(c, b.childNodes[0]); b.insertBefore(c, b.childNodes[0]);
} }
} }
})(document, "https://cdn.plyr.io/1.1.0/sprite.svg"); })(document, "https://cdn.plyr.io/1.1.5/sprite.svg");
</script> </script>
<!-- Plyr core script --> <!-- Plyr core script -->
<script src="//cdn.plyr.io/1.1.0/plyr.js"></script> <script src="//cdn.plyr.io/1.1.5/plyr.js"></script>
<!-- Docs script --> <!-- Docs script -->
<script src="//cdn.plyr.io/1.1.0/docs.js"></script> <script src="//cdn.plyr.io/1.1.5/docs.js"></script>
</body> </body>
</html> </html>

View File

@ -11,9 +11,21 @@ plyr.setup({
html: templates.controls.render({}), html: templates.controls.render({}),
captions: { captions: {
defaultActive: true defaultActive: true
},
onSetup: function() {
var player = this,
type = player.media.tagName.toLowerCase(),
toggle = document.querySelector("[data-toggle='fullscreen']");
console.log("✓ Setup done for <" + type + ">");
if(type === "video" && toggle) {
toggle.addEventListener("click", player.toggleFullscreen, false);
}
} }
}); });
// Google analytics // Google analytics
// For demo site (http://[www.]plyr.io) only // For demo site (http://[www.]plyr.io) only
if(document.domain.indexOf("plyr.io") > -1) { if(document.domain.indexOf("plyr.io") > -1) {

View File

@ -1,6 +1,6 @@
{ {
"name": "plyr", "name": "plyr",
"version": "1.1.0", "version": "1.1.5",
"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",

View File

@ -3,14 +3,14 @@ A simple, accessible HTML5 media player.
[Checkout the demo](http://plyr.io) [Checkout the demo](http://plyr.io)
[![Image of Plyr](https://cdn.plyr.io/static/plyr.png?1)](http://plyr.io) [![Image of Plyr](https://cdn.plyr.io/static/plyr.png?2)](http://plyr.io)
## Why? ## Why?
We wanted a lightweight, accessible and customisable media player that just supports *modern* 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 customisable media player that just supports *modern* browsers. Sure, there are many other players out there but we wanted to keep things simple, using the right elements for the job.
## Features ## Features
- **Accessible** - full support for captions and screen readers. - **Accessible** - full support for captions and screen readers.
- **Lightweight** - just 6KB minified and gzipped. - **Lightweight** - just 6.4KB 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.1.0/plyr.js` to `https://cdn.plyr.io/1.1.0/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.1.5/plyr.js` to `https://cdn.plyr.io/1.1.5/plyr.js`
### Bower ### Bower
If bower is your thang, you can grab Plyr using: If bower is your thang, you can grab Plyr using:
@ -47,15 +47,22 @@ bower install plyr
``` ```
More info on setting up dependencies can be found in the [Bower Docs](http://bower.io/docs/creating-packages/#maintaining-dependencies) More info on setting up dependencies can be found in the [Bower Docs](http://bower.io/docs/creating-packages/#maintaining-dependencies)
### Ember
The awesome [@louisrudner](https://twitter.com/louisrudner) has created an ember component, available by running:
```
ember addon:install ember-cli-plyr
```
More info is on [npm](https://www.npmjs.com/package/ember-cli-plyr) and [GitHub](https://github.com/louisrudner/ember-cli-plyr)
### CDN ### CDN
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.1.0/plyr.css"> <link rel="stylesheet" href="//cdn.plyr.io/1.1.5/plyr.css">
<script src="//cdn.plyr.io/1.1.0/plyr.js"></script> <script src="//cdn.plyr.io/1.1.5/plyr.js"></script>
``` ```
You can also access the `sprite.svg` file at `//cdn.plyr.io/1.1.0/sprite.svg`. You can also access the `sprite.svg` file at `//cdn.plyr.io/1.1.5/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.
@ -130,7 +137,7 @@ You'll notice the `crossorigin` attribute on the example `<video>` and `<audio>`
More info on CORS here: More info on CORS here:
[https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) [https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS)
###JavaScript ### JavaScript
Much of the behaviour of the player is configurable when initialising the library. Below is an example of a default instance. Much of the behaviour of the player is configurable when initialising the library. Below is an example of a default instance.
```html ```html
@ -240,6 +247,12 @@ You can pass the following options to the setup method.
<td>&mdash;</td> <td>&mdash;</td>
<td>Two properties; <code>enabled</code> which toggles if local storage should be enabled (if the browser supports it). The default value is `true`. This enables storing user settings, currently it only stores volume but more will be added later. The second property <code>key</code> is the key used for the local storage. The default is <code>plyr_volume</code> until more settings are stored.</td> <td>Two properties; <code>enabled</code> which toggles if local storage should be enabled (if the browser supports it). The default value is `true`. This enables storing user settings, currently it only stores volume but more will be added later. The second property <code>key</code> is the key used for the local storage. The default is <code>plyr_volume</code> until more settings are stored.</td>
</tr> </tr>
<tr>
<td><code>onSetup</code></td>
<td>Function</td>
<td>&mdash;</td>
<td>This callback function is called on every new plyr instance created. The context (<code>this</code>) is the plyr instance itself.</td>
</tr>
</tbody> </tbody>
</table> </table>
@ -307,6 +320,16 @@ Here's a list of the methods supported:
<td>&mdash;</td> <td>&mdash;</td>
<td>Toggles whether captions are enabled.</td> <td>Toggles whether captions are enabled.</td>
</tr> </tr>
<tr>
<td><code>toggleFullscreen()</code></td>
<td>Event</td>
<td>Toggles fullscreen. This can only be initiated by a user gesture due to browser security, i.e. a user event such as click.</td>
</tr>
<tr>
<td><code>isFullscreen()</code></td>
<td>&mdash;</td>
<td>Boolean returned if the player is in fullscreen.</td>
</tr>
<tr> <tr>
<td><code>support(...)</code></td> <td><code>support(...)</code></td>
<td>String</td> <td>String</td>
@ -327,7 +350,7 @@ Here's a list of the methods supported:
This will inject a child `source` element for every element in the array with the specified attributes. `src` is the only required attribute although adding `type` is recommended as it helps the browser decide which file to download and play. This will inject a child `source` element for every element in the array with the specified attributes. `src` is the only required attribute although adding `type` is recommended as it helps the browser decide which file to download and play.
</td> </td>
</tr> </tr>
<tr> <tr>
<td><code>poster(...)</code></td> <td><code>poster(...)</code></td>
<td>String</td> <td>String</td>
<td>Set the poster url. This is supported for the <code>video</code> element only.</td> <td>Set the poster url. This is supported for the <code>video</code> element only.</td>
@ -350,11 +373,12 @@ A complete list of events can be found here:
[Media Events - W3.org](http://www.w3.org/2010/05/video/mediaevents.html) [Media Events - W3.org](http://www.w3.org/2010/05/video/mediaevents.html)
## Fullscreen ## Fullscreen
Fullscreen in Plyr is supported for all browsers that [currently support it](http://caniuse.com/#feat=fullscreen). If you're using the default CSS, you can also use a "full browser" mode which will use the full browser window by adding the `player-fullscreen` class to your container. Fullscreen in Plyr is supported for all browsers that [currently support it](http://caniuse.com/#feat=fullscreen). If you're using the default CSS, you can also use a "full browser" mode which will use the full browser window by adding the `player-fullscreen` class to your container.
## Browser support ## Browser support
<table width="100%" style="text-align: center;"> <table width="100%" style="text-align: center">
<thead> <thead>
<tr> <tr>
<td>Safari</td> <td>Safari</td>
@ -392,11 +416,14 @@ If a User Agent is disabled but supports `<video>` and `<audio>` natively, it wi
Any unsupported browsers will display links to download the media if the correct html is used. Any unsupported browsers will display links to download the media if the correct html is used.
### Checking for support
There's an API method for checking support. You can call `plyr.supported()` and optionally pass a type to it, e.g. `plyr.supported("video")`. It will return an object with two keys; `basic` meaning there's basic support for that media type (or both if no type is passed) and `full` meaning there's full support for plyr.
## Issues ## Issues
If you find anything weird with Plyr, please let us know using the GitHub issues tracker. If you find anything weird with Plyr, please let us know using the GitHub issues tracker.
## Author ## Author
Plyr is developed by Sam Potts ([@sam_potts](https://twitter.com/sam_potts)) ([sampotts.me](http://sampotts.me)) Plyr is developed by [@sam_potts](https://twitter.com/sam_potts) / [sampotts.me](http://sampotts.me)
## Mentions ## Mentions
- [The Changelog](http://thechangelog.com/plyr-simple-html5-media-player-custom-controls-webvtt-captions/) - [The Changelog](http://thechangelog.com/plyr-simple-html5-media-player-custom-controls-webvtt-captions/)

View File

@ -1,6 +1,6 @@
// ========================================================================== // ==========================================================================
// Plyr // Plyr
// plyr.js v1.1.0 // plyr.js v1.1.5
// https://github.com/selz/plyr // https://github.com/selz/plyr
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================
@ -80,11 +80,12 @@
enabled: true, enabled: true,
key: "plyr_volume" key: "plyr_volume"
}, },
controls: ["restart", "rewind", "play", "fast-forward", "current-time", "duration", "mute", "volume", "captions", "fullscreen"] controls: ["restart", "rewind", "play", "fast-forward", "current-time", "duration", "mute", "volume", "captions", "fullscreen"],
onSetup: function() {},
}; };
// Build the default HTML // Build the default HTML
defaults.html = (function() { function _buildControls() {
// Open and add the progress and seek elements // Open and add the progress and seek elements
var html = [ var html = [
"<div class='player-controls'>", "<div class='player-controls'>",
@ -101,7 +102,7 @@
"<span class='player-controls-left'>"]; "<span class='player-controls-left'>"];
// Restart button // Restart button
if(_inArray(defaults.controls, "restart")) { if(_inArray(config.controls, "restart")) {
html.push( html.push(
"<button type='button' data-player='restart'>", "<button type='button' data-player='restart'>",
"<svg><use xlink:href='#icon-restart'></use></svg>", "<svg><use xlink:href='#icon-restart'></use></svg>",
@ -111,7 +112,7 @@
} }
// Rewind button // Rewind button
if(_inArray(defaults.controls, "rewind")) { if(_inArray(config.controls, "rewind")) {
html.push( html.push(
"<button type='button' data-player='rewind'>", "<button type='button' data-player='rewind'>",
"<svg><use xlink:href='#icon-rewind'></use></svg>", "<svg><use xlink:href='#icon-rewind'></use></svg>",
@ -121,7 +122,7 @@
} }
// Play/pause button // Play/pause button
if(_inArray(defaults.controls, "play")) { if(_inArray(config.controls, "play")) {
html.push( html.push(
"<button type='button' data-player='play'>", "<button type='button' data-player='play'>",
"<svg><use xlink:href='#icon-play'></use></svg>", "<svg><use xlink:href='#icon-play'></use></svg>",
@ -135,7 +136,7 @@
} }
// Fast forward button // Fast forward button
if(_inArray(defaults.controls, "fast-forward")) { if(_inArray(config.controls, "fast-forward")) {
html.push( html.push(
"<button type='button' data-player='fast-forward'>", "<button type='button' data-player='fast-forward'>",
"<svg><use xlink:href='#icon-fast-forward'></use></svg>", "<svg><use xlink:href='#icon-fast-forward'></use></svg>",
@ -145,7 +146,7 @@
} }
// Media current time display // Media current time display
if(_inArray(defaults.controls, "current-time")) { if(_inArray(config.controls, "current-time")) {
html.push( html.push(
"<span class='player-time'>", "<span class='player-time'>",
"<span class='sr-only'>Current time</span>", "<span class='sr-only'>Current time</span>",
@ -155,7 +156,7 @@
} }
// Media duration display // Media duration display
if(_inArray(defaults.controls, "duration")) { if(_inArray(config.controls, "duration")) {
html.push( html.push(
"<span class='player-time'>", "<span class='player-time'>",
"<span class='sr-only'>Duration</span>", "<span class='sr-only'>Duration</span>",
@ -171,7 +172,7 @@
); );
// Toggle mute button // Toggle mute button
if(_inArray(defaults.controls, "mute")) { if(_inArray(config.controls, "mute")) {
html.push( html.push(
"<input class='inverted sr-only' id='mute{id}' type='checkbox' data-player='mute'>", "<input class='inverted sr-only' id='mute{id}' type='checkbox' data-player='mute'>",
"<label id='mute{id}' for='mute{id}'>", "<label id='mute{id}' for='mute{id}'>",
@ -183,7 +184,7 @@
} }
// Volume range control // Volume range control
if(_inArray(defaults.controls, "volume")) { if(_inArray(config.controls, "volume")) {
html.push( html.push(
"<label for='volume{id}' class='sr-only'>Volume</label>", "<label for='volume{id}' class='sr-only'>Volume</label>",
"<input id='volume{id}' class='player-volume' type='range' min='0' max='10' value='5' data-player='volume'>" "<input id='volume{id}' class='player-volume' type='range' min='0' max='10' value='5' data-player='volume'>"
@ -191,7 +192,7 @@
} }
// Toggle captions button // Toggle captions button
if(_inArray(defaults.controls, "captions")) { if(_inArray(config.controls, "captions")) {
html.push( html.push(
"<input class='sr-only' id='captions{id}' type='checkbox' data-player='captions'>", "<input class='sr-only' id='captions{id}' type='checkbox' data-player='captions'>",
"<label for='captions{id}'>", "<label for='captions{id}'>",
@ -203,7 +204,7 @@
} }
// Toggle fullscreen button // Toggle fullscreen button
if(_inArray(defaults.controls, "fullscreen")) { if(_inArray(config.controls, "fullscreen")) {
html.push( html.push(
"<button type='button' data-player='fullscreen'>", "<button type='button' data-player='fullscreen'>",
"<svg class='icon-exit-fullscreen'><use xlink:href='#icon-exit-fullscreen'></use></svg>", "<svg class='icon-exit-fullscreen'><use xlink:href='#icon-exit-fullscreen'></use></svg>",
@ -220,7 +221,7 @@
); );
return html.join(""); return html.join("");
})(); }
// Debugging // Debugging
function _log(text, error) { function _log(text, error) {
@ -234,8 +235,8 @@
function _browserSniff() { function _browserSniff() {
var nAgt = navigator.userAgent, var nAgt = navigator.userAgent,
name = navigator.appName, name = navigator.appName,
fullVersion = ""+parseFloat(navigator.appVersion), fullVersion = "" + parseFloat(navigator.appVersion),
majorVersion = parseInt(navigator.appVersion,10), majorVersion = parseInt(navigator.appVersion, 10),
nameOffset, nameOffset,
verOffset, verOffset,
ix; ix;
@ -248,46 +249,47 @@
// MSIE // MSIE
else if ((verOffset=nAgt.indexOf("MSIE")) !== -1) { else if ((verOffset=nAgt.indexOf("MSIE")) !== -1) {
name = "IE"; name = "IE";
fullVersion = nAgt.substring(verOffset+5); fullVersion = nAgt.substring(verOffset + 5);
} }
// Chrome // Chrome
else if ((verOffset=nAgt.indexOf("Chrome")) !== -1) { else if ((verOffset=nAgt.indexOf("Chrome")) !== -1) {
name = "Chrome"; name = "Chrome";
fullVersion = nAgt.substring(verOffset+7); fullVersion = nAgt.substring(verOffset + 7);
} }
// Safari // Safari
else if ((verOffset=nAgt.indexOf("Safari")) !== -1) { else if ((verOffset=nAgt.indexOf("Safari")) !== -1) {
name = "Safari"; name = "Safari";
fullVersion = nAgt.substring(verOffset+7); fullVersion = nAgt.substring(verOffset + 7);
if ((verOffset=nAgt.indexOf("Version")) !== -1) { if ((verOffset=nAgt.indexOf("Version")) !== -1) {
fullVersion = nAgt.substring(verOffset+8); fullVersion = nAgt.substring(verOffset + 8);
} }
} }
// Firefox // Firefox
else if ((verOffset=nAgt.indexOf("Firefox")) !== -1) { else if ((verOffset=nAgt.indexOf("Firefox")) !== -1) {
name = "Firefox"; name = "Firefox";
fullVersion = nAgt.substring(verOffset+8); fullVersion = nAgt.substring(verOffset + 8);
} }
// In most other browsers, "name/version" is at the end of userAgent // In most other browsers, "name/version" is at the end of userAgent
else if ( (nameOffset=nAgt.lastIndexOf(" ")+1) < (verOffset=nAgt.lastIndexOf("/")) ) { else if ((nameOffset=nAgt.lastIndexOf(" ") + 1) < (verOffset=nAgt.lastIndexOf("/"))) {
name = nAgt.substring(nameOffset,verOffset); name = nAgt.substring(nameOffset,verOffset);
fullVersion = nAgt.substring(verOffset+1); fullVersion = nAgt.substring(verOffset + 1);
if (name.toLowerCase()==name.toUpperCase()) {
if (name.toLowerCase() == name.toUpperCase()) {
name = navigator.appName; name = navigator.appName;
} }
} }
// Trim the fullVersion string at semicolon/space if present // Trim the fullVersion string at semicolon/space if present
if ((ix=fullVersion.indexOf(";")) !== -1) { if ((ix = fullVersion.indexOf(";")) !== -1) {
fullVersion=fullVersion.substring(0,ix); fullVersion = fullVersion.substring(0, ix);
} }
if ((ix=fullVersion.indexOf(" ")) !== -1) { if ((ix = fullVersion.indexOf(" ")) !== -1) {
fullVersion=fullVersion.substring(0,ix); fullVersion = fullVersion.substring(0, ix);
} }
// Get major version // Get major version
majorVersion = parseInt(""+fullVersion,10); majorVersion = parseInt("" + fullVersion, 10);
if (isNaN(majorVersion)) { if (isNaN(majorVersion)) {
fullVersion = ""+parseFloat(navigator.appVersion); fullVersion = "" + parseFloat(navigator.appVersion);
majorVersion = parseInt(navigator.appVersion,10); majorVersion = parseInt(navigator.appVersion, 10);
} }
// Return data // Return data
@ -330,7 +332,7 @@
// Element exists in an array // Element exists in an array
function _inArray(haystack, needle) { function _inArray(haystack, needle) {
return (haystack.indexOf(needle) != -1); return Array.prototype.indexOf && (haystack.indexOf(needle) != -1);
} }
// Replace all // Replace all
@ -340,7 +342,7 @@
// Wrap an element // Wrap an element
function _wrap(elements, wrapper) { function _wrap(elements, wrapper) {
// Convert `elms` to an array, if necessary. // Convert `elements` to an array, if necessary.
if (!elements.length) { if (!elements.length) {
elements = [elements]; elements = [elements];
} }
@ -348,16 +350,16 @@
// Loops backwards to prevent having to clone the wrapper on the // Loops backwards to prevent having to clone the wrapper on the
// first element (see `child` below). // first element (see `child` below).
for (var i = elements.length - 1; i >= 0; i--) { for (var i = elements.length - 1; i >= 0; i--) {
var child = (i > 0) ? wrapper.cloneNode(true) : wrapper; var child = (i > 0) ? wrapper.cloneNode(true) : wrapper;
var el = elements[i]; var element = elements[i];
// Cache the current parent and sibling. // Cache the current parent and sibling.
var parent = el.parentNode; var parent = element.parentNode;
var sibling = el.nextSibling; var sibling = element.nextSibling;
// Wrap the element (is automatically removed from its current // Wrap the element (is automatically removed from its current
// parent). // parent).
child.appendChild(el); child.appendChild(element);
// If the element had a sibling, insert the wrapper before // If the element had a sibling, insert the wrapper before
// the sibling to maintain the HTML structure; otherwise, just // the sibling to maintain the HTML structure; otherwise, just
@ -519,7 +521,7 @@
} }
} }
// Safari doesn't support the ALLOW_KEYBOARD_INPUT flag so set it to not supported // Safari doesn't support the ALLOW_KEYBOARD_INPUT flag (for security) so set it to not supported
// https://bugs.webkit.org/show_bug.cgi?id=121496 // https://bugs.webkit.org/show_bug.cgi?id=121496
if(fullscreen.prefix === "webkit" && !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/)) { if(fullscreen.prefix === "webkit" && !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/)) {
fullscreen.supportsFullScreen = false; fullscreen.supportsFullScreen = false;
@ -531,19 +533,18 @@
// Sometimes the prefix is "ms", sometimes "MS" to keep you on your toes // 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() { fullscreen.isFullScreen = function(element) {
if(typeof element == "undefined") {
element = document;
}
switch (this.prefix) { switch (this.prefix) {
case "": case "":
return document.fullScreen; return document.fullscreenElement == element;
case "webkit": case "moz":
return document.webkitIsFullScreen; return document.mozFullScreenElement == element;
case "ms":
// Docs say document.msFullScreenElement returns undefined
// if no element is full screem but it returns null, cheers
// https://msdn.microsoft.com/en-us/library/ie/dn265028%28v=vs.85%29.aspx
return (document.msFullscreenElement !== null);
default: default:
return document[this.prefix + "FullScreen"]; return document[this.prefix + "FullscreenElement"] == element;
} }
}; };
fullscreen.requestFullScreen = function(element) { fullscreen.requestFullScreen = function(element) {
@ -681,22 +682,25 @@
// Insert controls // Insert controls
function _injectControls() { function _injectControls() {
// Make a copy of the html
var html = config.html;
// Insert custom video controls // Insert custom video controls
_log("Injecting custom controls."); _log("Injecting custom controls.");
// If no controls are specified, bail // If no controls are specified, create default
if(!config.html) { if(!html) {
return; html = _buildControls();
} }
// Replace seek time instances // Replace seek time instances
config.html = _replaceAll(config.html, "{seektime}", config.seekTime); html = _replaceAll(html, "{seektime}", config.seekTime);
// Replace all id references // Replace all id references with random numbers
config.html = _replaceAll(config.html, "{id}", player.random); html = _replaceAll(html, "{id}", Math.floor(Math.random() * (10000)));
// Inject into the container // Inject into the container
player.container.insertAdjacentHTML("beforeend", config.html); player.container.insertAdjacentHTML("beforeend", html);
// Setup tooltips // Setup tooltips
if(config.tooltips) { if(config.tooltips) {
@ -1035,7 +1039,7 @@
targetTime = input; targetTime = input;
} }
// Event // Event
else if (typeof input === "object" && (input.type === "change" || input.type === "input")) { else if (typeof input === "object" && (input.type === "input" || input.type === "change")) {
// 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) * player.media.duration); targetTime = ((input.target.value / input.target.max) * player.media.duration);
@ -1076,12 +1080,12 @@
// If it's a fullscreen change event, it's probably a native close // If it's a fullscreen change event, it's probably a native close
if(event && event.type === fullscreen.fullScreenEventName) { if(event && event.type === fullscreen.fullScreenEventName) {
config.fullscreen.active = fullscreen.isFullScreen(); player.isFullscreen = fullscreen.isFullScreen(player.container);
} }
// If there's native support, use it // If there's native support, use it
else if(nativeSupport) { else if(nativeSupport) {
// Request fullscreen // Request fullscreen
if(!fullscreen.isFullScreen()) { if(!fullscreen.isFullScreen(player.container)) {
fullscreen.requestFullScreen(player.container); fullscreen.requestFullScreen(player.container);
} }
// Bail from fullscreen // Bail from fullscreen
@ -1090,14 +1094,14 @@
} }
// Check if we're actually full screen (it could fail) // Check if we're actually full screen (it could fail)
config.fullscreen.active = fullscreen.isFullScreen(); player.isFullscreen = fullscreen.isFullScreen(player.container);
} }
else { else {
// Otherwise, it's a simple toggle // Otherwise, it's a simple toggle
config.fullscreen.active = !config.fullscreen.active; player.isFullscreen = !player.isFullscreen;
// Bind/unbind escape key // Bind/unbind escape key
if(config.fullscreen.active) { if(player.isFullscreen) {
_on(document, "keyup", _handleEscapeFullscreen); _on(document, "keyup", _handleEscapeFullscreen);
document.body.style.overflow = "hidden"; document.body.style.overflow = "hidden";
} }
@ -1108,13 +1112,18 @@
} }
// Set class hook // Set class hook
_toggleClass(player.container, config.classes.fullscreen.active, config.fullscreen.active); _toggleClass(player.container, config.classes.fullscreen.active, player.isFullscreen);
// Remove hover class because mouseleave doesn't occur
if (player.isFullscreen) {
_toggleClass(player.controls, config.classes.hover, false);
}
} }
// Bail from faux-fullscreen // Bail from faux-fullscreen
function _handleEscapeFullscreen(event) { function _handleEscapeFullscreen(event) {
// If it's a keypress and not escape, bail // If it's a keypress and not escape, bail
if((event.which || event.charCode || event.keyCode) === 27 && config.fullscreen.active) { if((event.which || event.charCode || event.keyCode) === 27 && player.isFullscreen) {
_toggleFullscreen(); _toggleFullscreen();
} }
} }
@ -1153,7 +1162,7 @@
// Store the volume in storage // Store the volume in storage
if(config.storage.enabled && _storage().supported) { if(config.storage.enabled && _storage().supported) {
window.localStorage.plyr_volume = volume; window.localStorage.setItem(config.storage.key, volume);
} }
} }
@ -1391,6 +1400,9 @@
// Listen for events // Listen for events
function _listeners() { function _listeners() {
// IE doesn't support input event, so we fallback to change
var inputEvent = (player.browser.name == "IE" ? "change" : "input");
// Play // Play
_on(player.buttons.play, "click", function() { _on(player.buttons.play, "click", function() {
_play(); _play();
@ -1412,9 +1424,11 @@
// Fast forward // Fast forward
_on(player.buttons.forward, "click", _forward); _on(player.buttons.forward, "click", _forward);
// Get the HTML5 range input element and append audio volume adjustment on change/input // Seek
// IE10 doesn't support the "input" event so they have to wait for change _on(player.buttons.seek, inputEvent, _seek);
_on(player.volume, "change input", function() {
// Set volume
_on(player.volume, inputEvent, function() {
_setVolume(this.value); _setVolume(this.value);
}); });
@ -1440,9 +1454,6 @@
// Display duration // Display duration
_on(player.media, "loadedmetadata", _displayDuration); _on(player.media, "loadedmetadata", _displayDuration);
// Seek
_on(player.buttons.seek, "change input", _seek);
// Captions // Captions
_on(player.buttons.captions, "change", function() { _on(player.buttons.captions, "change", function() {
_toggleCaptions(this.checked); _toggleCaptions(this.checked);
@ -1481,14 +1492,14 @@
if(player.type === "video" && config.click) { if(player.type === "video" && config.click) {
_on(player.videoContainer, "click", function() { _on(player.videoContainer, "click", function() {
if(player.media.paused) { if(player.media.paused) {
_play(); _triggerEvent(player.buttons.play, "click");
} }
else if(player.media.ended) { else if(player.media.ended) {
_seek(); _seek();
_play(); _triggerEvent(player.buttons.play, "click");
} }
else { else {
_pause(); _triggerEvent(player.buttons.pause, "click");
} }
}); });
} }
@ -1497,7 +1508,7 @@
if(config.fullscreen.hideControls) { if(config.fullscreen.hideControls) {
_on(player.controls, "mouseenter mouseleave", function(event) { _on(player.controls, "mouseenter mouseleave", function(event) {
_toggleClass(player.controls, config.classes.hover, (event.type === "mouseenter")); _toggleClass(player.controls, config.classes.hover, (event.type === "mouseenter"));
}) });
} }
} }
@ -1528,9 +1539,6 @@
// Setup media // Setup media
_setupMedia(); _setupMedia();
// Generate random number for id/for attribute values for controls
player.random = Math.floor(Math.random() * (10000));
// If there's full support // If there's full support
if(player.supported.full) { if(player.supported.full) {
// Inject custom controls // Inject custom controls
@ -1578,11 +1586,13 @@
rewind: _rewind, rewind: _rewind,
forward: _forward, forward: _forward,
seek: _seek, seek: _seek,
source: _parseSource,
poster: _updatePoster,
setVolume: _setVolume, setVolume: _setVolume,
toggleMute: _toggleMute, toggleMute: _toggleMute,
toggleCaptions: _toggleCaptions, toggleCaptions: _toggleCaptions,
source: _parseSource, toggleFullscreen: _toggleFullscreen,
poster: _updatePoster, isFullscreen: function() { return player.isFullscreen || false; },
support: function(mimeType) { return _supportMime(player, mimeType); } support: function(mimeType) { return _supportMime(player, mimeType); }
} }
} }
@ -1624,7 +1634,7 @@
// Extend the default options with user specified // Extend the default options with user specified
config = _extend(defaults, options); config = _extend(defaults, options);
// If enabled carry on // Bail if disabled or no basic support
// You may want to disable certain UAs etc // You may want to disable certain UAs etc
if(!config.enabled || !api.supported().basic) { if(!config.enabled || !api.supported().basic) {
return false; return false;
@ -1646,13 +1656,16 @@
// Set plyr to false if setup failed // Set plyr to false if setup failed
element.plyr = (Object.keys(instance).length ? instance : false); element.plyr = (Object.keys(instance).length ? instance : false);
// Callback
config.onSetup.apply(element.plyr);
} }
// Add to return array // Add to return array even if it's already setup
players.push(element.plyr); players.push(element.plyr);
} }
return players; return players;
} }
}(this.plyr = this.plyr || {})); }(this.plyr = this.plyr || {}));

View File

@ -9,6 +9,7 @@
@gray-dark: #343f4a; @gray-dark: #343f4a;
@gray: #565d64; @gray: #565d64;
@gray-light: #cbd0d3; @gray-light: #cbd0d3;
@off-white: #d6dadd;
// Font sizes // Font sizes
@font-size-small: 14px; @font-size-small: 14px;
@ -527,6 +528,17 @@
float: none; float: none;
} }
// Audio specific styles
// Position the progress within the container
&-audio .player-controls {
padding-top: (@control-spacing * 2);
}
&-audio .player-progress {
bottom: auto;
top: 0;
background: @off-white;
}
// Full screen mode // Full screen mode
&-fullscreen, &-fullscreen,
&.fullscreen-active { &.fullscreen-active {

View File

@ -9,6 +9,7 @@ $blue: #3498DB;
$gray-dark: #343f4a; $gray-dark: #343f4a;
$gray: #565d64; $gray: #565d64;
$gray-light: #cbd0d3; $gray-light: #cbd0d3;
$off-white: #d6dadd;
// Font sizes // Font sizes
$font-size-small: 14px; $font-size-small: 14px;
@ -535,6 +536,17 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
float: none; float: none;
} }
// Audio specific styles
// Position the progress within the container
&-audio .player-controls {
padding-top: ($control-spacing * 2);
}
&-audio .player-progress {
bottom: auto;
top: 0;
background: $off-white;
}
// Full screen mode // Full screen mode
&-fullscreen, &-fullscreen,
&.fullscreen-active { &.fullscreen-active {