Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
7ccbfad6ad | |||
91f8a158d2 | |||
8925dcde01 | |||
530abac3a7 | |||
e702d9a881 | |||
b0aeccb793 | |||
43d8d748ce | |||
b43ea5c7d3 | |||
f56759222d | |||
c8b7bb570c | |||
d536b29550 | |||
ecbda018c5 | |||
5187311ff0 | |||
d9a94ac7b0 | |||
3526e322ef | |||
99cabd545d | |||
1f7f7b10de | |||
b2421b592a | |||
5322f4c62f | |||
7ab8647fc8 | |||
50c76f3d7e | |||
2f4c56176d |
16
changelog.md
16
changelog.md
@ -1,5 +1,19 @@
|
||||
# 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
|
||||
@ -8,7 +22,7 @@
|
||||
- Added config option to set which controls are shown (if using the default controls html) and better handling of missing controls
|
||||
|
||||
## v1.0.31
|
||||
- Display duration on metadataloaded
|
||||
- Display duration on `metadataloaded`
|
||||
|
||||
## v1.0.30
|
||||
- Fixed bug with media longer than 60 minutes (Fixes #69)
|
||||
|
2
dist/plyr.css
vendored
2
dist/plyr.css
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.js
vendored
2
dist/plyr.js
vendored
File diff suppressed because one or more lines are too long
2
docs/dist/docs.js
vendored
2
docs/dist/docs.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">
|
||||
|
||||
<!-- Docs styles -->
|
||||
<link rel="stylesheet" href="//cdn.plyr.io/1.1.1/docs.css">
|
||||
<link rel="stylesheet" href="//cdn.plyr.io/1.1.6/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
|
@ -8,10 +8,10 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="//cdn.plyr.io/1.1.1/plyr.css">
|
||||
<link rel="stylesheet" href="https://cdn.plyr.io/1.1.6/plyr.css">
|
||||
|
||||
<!-- Docs styles -->
|
||||
<link rel="stylesheet" href="//cdn.plyr.io/1.1.1/docs.css">
|
||||
<link rel="stylesheet" href="https://cdn.plyr.io/1.1.6/docs.css">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
@ -23,18 +23,16 @@
|
||||
<main>
|
||||
<section class="example-video">
|
||||
<div class="player">
|
||||
<video poster="//cdn.selz.com/plyr/1.0/poster.jpg" controls crossorigin>
|
||||
<video poster="https://cdn.selz.com/plyr/1.0/poster.jpg" controls crossorigin>
|
||||
<!-- Video files -->
|
||||
<source src="//cdn.selz.com/plyr/1.0/movie.mp4" type="video/mp4">
|
||||
<source src="//cdn.selz.com/plyr/1.0/movie.webm" type="video/webm">
|
||||
<source src="https://cdn.selz.com/plyr/1.0/movie.mp4" type="video/mp4">
|
||||
<source src="https://cdn.selz.com/plyr/1.0/movie.webm" type="video/webm">
|
||||
|
||||
<!-- Text track file -->
|
||||
<track kind="captions" label="English" srclang="en" src="//cdn.selz.com/plyr/1.0/en.vtt" default>
|
||||
<track kind="captions" label="English" srclang="en" src="https://cdn.selz.com/plyr/1.0/en.vtt" default>
|
||||
|
||||
<!-- Fallback for browsers that don't support the <video> element -->
|
||||
<div>
|
||||
<a href="//cdn.selz.com/plyr/1.0/movie.mp4">Download</a>
|
||||
</div>
|
||||
<a href="https://cdn.selz.com/plyr/1.0/movie.mp4">Download</a>
|
||||
</video>
|
||||
</div>
|
||||
<small>Big Buck Bunny. More info can be found at <a href="https://peach.blender.org" target="_blank">peach.blender.org</a>.</small>
|
||||
@ -44,13 +42,11 @@
|
||||
<div class="player">
|
||||
<audio controls>
|
||||
<!-- Audio files -->
|
||||
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3" type="audio/mp3">
|
||||
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.ogg" type="audio/ogg">
|
||||
<source src="https://cdn.selz.com/plyr/1.0/logistics-96-sample.mp3" type="audio/mp3">
|
||||
<source src="https://cdn.selz.com/plyr/1.0/logistics-96-sample.ogg" type="audio/ogg">
|
||||
|
||||
<!-- Fallback for browsers that don't support the <audio> element -->
|
||||
<div>
|
||||
<a href="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3">Download</a>
|
||||
</div>
|
||||
<a href="https://cdn.selz.com/plyr/1.0/logistics-96-sample.mp3">Download</a>
|
||||
</audio>
|
||||
</div>
|
||||
<small>"96" by Logistics, which can be purchased from <a href="https://www.hospitalrecords.com/shop/artist/logistics" target="_blank">Hospital Records</a>.</small>
|
||||
@ -83,13 +79,13 @@
|
||||
b.insertBefore(c, b.childNodes[0]);
|
||||
}
|
||||
}
|
||||
})(document, "https://cdn.plyr.io/1.1.1/sprite.svg");
|
||||
})(document, "https://cdn.plyr.io/1.1.6/sprite.svg");
|
||||
</script>
|
||||
|
||||
<!-- Plyr core script -->
|
||||
<script src="//cdn.plyr.io/1.1.1/plyr.js"></script>
|
||||
<script src="https://cdn.plyr.io/1.1.6/plyr.js"></script>
|
||||
|
||||
<!-- Docs script -->
|
||||
<script src="//cdn.plyr.io/1.1.1/docs.js"></script>
|
||||
<script src="https://cdn.plyr.io/1.1.6/docs.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
@ -11,9 +11,21 @@ plyr.setup({
|
||||
html: templates.controls.render({}),
|
||||
captions: {
|
||||
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
|
||||
// For demo site (http://[www.]plyr.io) only
|
||||
if(document.domain.indexOf("plyr.io") > -1) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "plyr",
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.6",
|
||||
"description": "A simple HTML5 media player using custom controls",
|
||||
"homepage": "http://plyr.io",
|
||||
"main": "gulpfile.js",
|
||||
|
98
readme.md
98
readme.md
@ -3,14 +3,14 @@ A simple, accessible HTML5 media player.
|
||||
|
||||
[Checkout the demo](http://plyr.io)
|
||||
|
||||
[](http://plyr.io)
|
||||
[](http://plyr.io)
|
||||
|
||||
## 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.
|
||||
|
||||
## Features
|
||||
- **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.
|
||||
- **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.
|
||||
@ -25,11 +25,10 @@ Oh and yes, it works with Bootstrap.
|
||||
Check out [the changelog](changelog.md)
|
||||
|
||||
## Planned development
|
||||
- Accept a string selector, a node, or a nodelist for the `container` property of `selectors`.
|
||||
- Multiple language captions (with selection)
|
||||
- Playlists (audio and video)
|
||||
- Set source by API
|
||||
- Tooltip option (for seeking and controls)
|
||||
- YouTube and Vimeo support
|
||||
- Playback speed
|
||||
- Multiple language captions (with selection)
|
||||
... and whatever else has been raised in [issues](https://github.com/Selz/plyr/issues)
|
||||
|
||||
If you have any cool ideas or features, please let me know by [creating an issue](https://github.com/Selz/plyr/issues/new) or of course, forking and sending a pull request.
|
||||
@ -38,7 +37,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.
|
||||
|
||||
**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.1/plyr.js` to `https://cdn.plyr.io/1.1.1/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.6/plyr.js` to `https://cdn.plyr.io/1.1.6/plyr.js`
|
||||
|
||||
### Bower
|
||||
If bower is your thang, you can grab Plyr using:
|
||||
@ -47,15 +46,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)
|
||||
|
||||
### 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
|
||||
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:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="//cdn.plyr.io/1.1.1/plyr.css">
|
||||
<script src="//cdn.plyr.io/1.1.1/plyr.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.plyr.io/1.1.6/plyr.css">
|
||||
<script src="https://cdn.plyr.io/1.1.6/plyr.js"></script>
|
||||
```
|
||||
|
||||
You can also access the `sprite.svg` file at `//cdn.plyr.io/1.1.1/sprite.svg`.
|
||||
You can also access the `sprite.svg` file at `https://cdn.plyr.io/1.1.6/sprite.svg`.
|
||||
|
||||
### 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.
|
||||
@ -92,18 +98,16 @@ and the AJAX technique here:
|
||||
The only extra markup that's needed to use plyr is a `<div>` wrapper. Replace the source, poster and captions with urls for your media.
|
||||
```html
|
||||
<div class="player">
|
||||
<video poster="//cdn.selz.com/plyr/1.0/poster.jpg" controls crossorigin>
|
||||
<video poster="https://cdn.selz.com/plyr/1.0/poster.jpg" controls crossorigin>
|
||||
<!-- Video files -->
|
||||
<source src="//cdn.selz.com/plyr/1.0/movie.mp4" type="video/mp4">
|
||||
<source src="//cdn.selz.com/plyr/1.0/movie.webm" type="video/webm">
|
||||
<source src="https://cdn.selz.com/plyr/1.0/movie.mp4" type="video/mp4">
|
||||
<source src="https://cdn.selz.com/plyr/1.0/movie.webm" type="video/webm">
|
||||
|
||||
<!-- Text track file -->
|
||||
<track kind="captions" label="English captions" src="//cdn.selz.com/plyr/1.0/movie_captions_en.vtt" srclang="en" default>
|
||||
<track kind="captions" label="English captions" src="https://cdn.selz.com/plyr/1.0/movie_captions_en.vtt" srclang="en" default>
|
||||
|
||||
<!-- Fallback for browsers that don't support the <video> element -->
|
||||
<div>
|
||||
<a href="//cdn.selz.com/plyr/1.0/movie.mp4">Download</a>
|
||||
</div>
|
||||
<a href="https://cdn.selz.com/plyr/1.0/movie.mp4">Download</a>
|
||||
</video>
|
||||
</div>
|
||||
```
|
||||
@ -113,13 +117,11 @@ And the same for `<audio>`
|
||||
<div class="player">
|
||||
<audio controls>
|
||||
<!-- Audio files -->
|
||||
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3" type="audio/mp3">
|
||||
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.ogg" type="audio/ogg">
|
||||
<source src="https://cdn.selz.com/plyr/1.0/logistics-96-sample.mp3" type="audio/mp3">
|
||||
<source src="https://cdn.selz.com/plyr/1.0/logistics-96-sample.ogg" type="audio/ogg">
|
||||
|
||||
<!-- Fallback for browsers that don't support the <audio> element -->
|
||||
<div>
|
||||
<a href="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3">Download</a>
|
||||
</div>
|
||||
<a href="https://cdn.selz.com/plyr/1.0/logistics-96-sample.mp3">Download</a>
|
||||
</audio>
|
||||
</div>
|
||||
```
|
||||
@ -130,21 +132,17 @@ You'll notice the `crossorigin` attribute on the example `<video>` and `<audio>`
|
||||
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)
|
||||
|
||||
###JavaScript
|
||||
Much of the behaviour of the player is configurable when initialising the library. Below is an example of a default instance.
|
||||
### JavaScript
|
||||
Much of the behaviour of the player is configurable when initialising the library. Here's an example of a default setup:
|
||||
|
||||
```html
|
||||
<script src="dist/plyr.js"></script>
|
||||
<script>
|
||||
plyr.setup({
|
||||
*options*
|
||||
});
|
||||
</script>
|
||||
<script>plyr.setup();</script>
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
You can pass the following options to the setup method.
|
||||
You can pass the following options to the setup method using `plyr.setup({...})`.
|
||||
|
||||
<table class="table" width="100%">
|
||||
<thead>
|
||||
@ -240,6 +238,12 @@ You can pass the following options to the setup method.
|
||||
<td>—</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>
|
||||
<td><code>onSetup</code></td>
|
||||
<td>Function</td>
|
||||
<td>—</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>
|
||||
</table>
|
||||
|
||||
@ -307,6 +311,16 @@ Here's a list of the methods supported:
|
||||
<td>—</td>
|
||||
<td>Toggles whether captions are enabled.</td>
|
||||
</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>—</td>
|
||||
<td>Boolean returned if the player is in fullscreen.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>support(...)</code></td>
|
||||
<td>String</td>
|
||||
@ -327,11 +341,21 @@ 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.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr>
|
||||
<td><code>poster(...)</code></td>
|
||||
<td>String</td>
|
||||
<td>Set the poster url. This is supported for the <code>video</code> element only.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>destroy()</code></td>
|
||||
<td>—</td>
|
||||
<td>Destroys the plyr UI and any media event listeners, effectively restoring to the previous state before <code>setup()</code> was called.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>restore()</code></td>
|
||||
<td>—</td>
|
||||
<td>Reverses the effects of the <code>destroy()</code> method, restoring the UI and listeners.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -350,11 +374,12 @@ A complete list of events can be found here:
|
||||
[Media Events - W3.org](http://www.w3.org/2010/05/video/mediaevents.html)
|
||||
|
||||
## 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.
|
||||
|
||||
## Browser support
|
||||
|
||||
<table width="100%" style="text-align: center;">
|
||||
<table width="100%" style="text-align: center">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Safari</td>
|
||||
@ -392,11 +417,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.
|
||||
|
||||
### 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
|
||||
If you find anything weird with Plyr, please let us know using the GitHub issues tracker.
|
||||
|
||||
## 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) with help from the awesome [contributors](https://github.com/Selz/plyr/graphs/contributors)
|
||||
|
||||
## Mentions
|
||||
- [The Changelog](http://thechangelog.com/plyr-simple-html5-media-player-custom-controls-webvtt-captions/)
|
||||
@ -424,4 +452,4 @@ Also these links helped created Plyr:
|
||||
- [Styling the `<progress>` element - hongkiat.com](http://www.hongkiat.com/blog/html5-progress-bar/)
|
||||
|
||||
## Copyright and License
|
||||
[The MIT license](license.md).
|
||||
[The MIT license](license.md).
|
||||
|
225
src/js/plyr.js
225
src/js/plyr.js
@ -1,6 +1,6 @@
|
||||
// ==========================================================================
|
||||
// Plyr
|
||||
// plyr.js v1.1.1
|
||||
// plyr.js v1.1.6
|
||||
// https://github.com/selz/plyr
|
||||
// License: The MIT License (MIT)
|
||||
// ==========================================================================
|
||||
@ -80,7 +80,8 @@
|
||||
enabled: true,
|
||||
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
|
||||
@ -234,8 +235,8 @@
|
||||
function _browserSniff() {
|
||||
var nAgt = navigator.userAgent,
|
||||
name = navigator.appName,
|
||||
fullVersion = ""+parseFloat(navigator.appVersion),
|
||||
majorVersion = parseInt(navigator.appVersion,10),
|
||||
fullVersion = "" + parseFloat(navigator.appVersion),
|
||||
majorVersion = parseInt(navigator.appVersion, 10),
|
||||
nameOffset,
|
||||
verOffset,
|
||||
ix;
|
||||
@ -248,46 +249,47 @@
|
||||
// MSIE
|
||||
else if ((verOffset=nAgt.indexOf("MSIE")) !== -1) {
|
||||
name = "IE";
|
||||
fullVersion = nAgt.substring(verOffset+5);
|
||||
fullVersion = nAgt.substring(verOffset + 5);
|
||||
}
|
||||
// Chrome
|
||||
else if ((verOffset=nAgt.indexOf("Chrome")) !== -1) {
|
||||
name = "Chrome";
|
||||
fullVersion = nAgt.substring(verOffset+7);
|
||||
fullVersion = nAgt.substring(verOffset + 7);
|
||||
}
|
||||
// Safari
|
||||
else if ((verOffset=nAgt.indexOf("Safari")) !== -1) {
|
||||
name = "Safari";
|
||||
fullVersion = nAgt.substring(verOffset+7);
|
||||
fullVersion = nAgt.substring(verOffset + 7);
|
||||
if ((verOffset=nAgt.indexOf("Version")) !== -1) {
|
||||
fullVersion = nAgt.substring(verOffset+8);
|
||||
fullVersion = nAgt.substring(verOffset + 8);
|
||||
}
|
||||
}
|
||||
// Firefox
|
||||
else if ((verOffset=nAgt.indexOf("Firefox")) !== -1) {
|
||||
name = "Firefox";
|
||||
fullVersion = nAgt.substring(verOffset+8);
|
||||
fullVersion = nAgt.substring(verOffset + 8);
|
||||
}
|
||||
// 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);
|
||||
fullVersion = nAgt.substring(verOffset+1);
|
||||
if (name.toLowerCase()==name.toUpperCase()) {
|
||||
fullVersion = nAgt.substring(verOffset + 1);
|
||||
|
||||
if (name.toLowerCase() == name.toUpperCase()) {
|
||||
name = navigator.appName;
|
||||
}
|
||||
}
|
||||
// Trim the fullVersion string at semicolon/space if present
|
||||
if ((ix=fullVersion.indexOf(";")) !== -1) {
|
||||
fullVersion=fullVersion.substring(0,ix);
|
||||
if ((ix = fullVersion.indexOf(";")) !== -1) {
|
||||
fullVersion = fullVersion.substring(0, ix);
|
||||
}
|
||||
if ((ix=fullVersion.indexOf(" ")) !== -1) {
|
||||
fullVersion=fullVersion.substring(0,ix);
|
||||
if ((ix = fullVersion.indexOf(" ")) !== -1) {
|
||||
fullVersion = fullVersion.substring(0, ix);
|
||||
}
|
||||
// Get major version
|
||||
majorVersion = parseInt(""+fullVersion,10);
|
||||
majorVersion = parseInt("" + fullVersion, 10);
|
||||
if (isNaN(majorVersion)) {
|
||||
fullVersion = ""+parseFloat(navigator.appVersion);
|
||||
majorVersion = parseInt(navigator.appVersion,10);
|
||||
fullVersion = "" + parseFloat(navigator.appVersion);
|
||||
majorVersion = parseInt(navigator.appVersion, 10);
|
||||
}
|
||||
|
||||
// Return data
|
||||
@ -340,7 +342,7 @@
|
||||
|
||||
// Wrap an element
|
||||
function _wrap(elements, wrapper) {
|
||||
// Convert `elms` to an array, if necessary.
|
||||
// Convert `elements` to an array, if necessary.
|
||||
if (!elements.length) {
|
||||
elements = [elements];
|
||||
}
|
||||
@ -348,28 +350,44 @@
|
||||
// Loops backwards to prevent having to clone the wrapper on the
|
||||
// first element (see `child` below).
|
||||
for (var i = elements.length - 1; i >= 0; i--) {
|
||||
var child = (i > 0) ? wrapper.cloneNode(true) : wrapper;
|
||||
var el = elements[i];
|
||||
var child = (i > 0) ? wrapper.cloneNode(true) : wrapper;
|
||||
var element = elements[i];
|
||||
|
||||
// Cache the current parent and sibling.
|
||||
var parent = el.parentNode;
|
||||
var sibling = el.nextSibling;
|
||||
var parent = element.parentNode;
|
||||
var sibling = element.nextSibling;
|
||||
|
||||
// Wrap the element (is automatically removed from its current
|
||||
// parent).
|
||||
child.appendChild(el);
|
||||
child.appendChild(element);
|
||||
|
||||
// If the element had a sibling, insert the wrapper before
|
||||
// the sibling to maintain the HTML structure; otherwise, just
|
||||
// append it to the parent.
|
||||
if (sibling) {
|
||||
parent.insertBefore(child, sibling);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
parent.appendChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unwrap an element
|
||||
// http://plainjs.com/javascript/manipulation/unwrap-a-dom-element-35/
|
||||
function _unwrap(wrapper) {
|
||||
// Get the element's parent node
|
||||
var parent = wrapper.parentNode;
|
||||
|
||||
// Move all children out of the element
|
||||
while (wrapper.firstChild) {
|
||||
parent.insertBefore(wrapper.firstChild, wrapper);
|
||||
}
|
||||
|
||||
// Remove the empty element
|
||||
parent.removeChild(wrapper);
|
||||
}
|
||||
|
||||
// Remove an element
|
||||
function _remove(element) {
|
||||
element.parentNode.removeChild(element);
|
||||
@ -402,7 +420,7 @@
|
||||
|
||||
// Toggle event
|
||||
function _toggleHandler(element, events, callback, toggle) {
|
||||
events = events.split(" ");
|
||||
var eventList = events.split(" ");
|
||||
|
||||
// If a nodelist is passed, call itself on each node
|
||||
if(element instanceof NodeList) {
|
||||
@ -415,8 +433,8 @@
|
||||
}
|
||||
|
||||
// If a single node is passed, bind the event listener
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
element[toggle ? "addEventListener" : "removeEventListener"](events[i], callback, false);
|
||||
for (var i = 0; i < eventList.length; i++) {
|
||||
element[toggle ? "addEventListener" : "removeEventListener"](eventList[i], callback, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -519,7 +537,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
|
||||
if(fullscreen.prefix === "webkit" && !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/)) {
|
||||
fullscreen.supportsFullScreen = false;
|
||||
@ -531,19 +549,18 @@
|
||||
// Sometimes the prefix is "ms", sometimes "MS" to keep you on your toes
|
||||
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) {
|
||||
case "":
|
||||
return document.fullScreen;
|
||||
case "webkit":
|
||||
return document.webkitIsFullScreen;
|
||||
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);
|
||||
return document.fullscreenElement == element;
|
||||
case "moz":
|
||||
return document.mozFullScreenElement == element;
|
||||
default:
|
||||
return document[this.prefix + "FullScreen"];
|
||||
return document[this.prefix + "FullscreenElement"] == element;
|
||||
}
|
||||
};
|
||||
fullscreen.requestFullScreen = function(element) {
|
||||
@ -681,22 +698,25 @@
|
||||
|
||||
// Insert controls
|
||||
function _injectControls() {
|
||||
// Make a copy of the html
|
||||
var html = config.html;
|
||||
|
||||
// Insert custom video controls
|
||||
_log("Injecting custom controls.");
|
||||
|
||||
// If no controls are specified, create default
|
||||
if(!config.html) {
|
||||
config.html = _buildControls();
|
||||
if(!html) {
|
||||
html = _buildControls();
|
||||
}
|
||||
|
||||
// Replace seek time instances
|
||||
config.html = _replaceAll(config.html, "{seektime}", config.seekTime);
|
||||
html = _replaceAll(html, "{seektime}", config.seekTime);
|
||||
|
||||
// Replace all id references
|
||||
config.html = _replaceAll(config.html, "{id}", player.random);
|
||||
// Replace all id references with random numbers
|
||||
html = _replaceAll(html, "{id}", Math.floor(Math.random() * (10000)));
|
||||
|
||||
// Inject into the container
|
||||
player.container.insertAdjacentHTML("beforeend", config.html);
|
||||
player.container.insertAdjacentHTML("beforeend", html);
|
||||
|
||||
// Setup tooltips
|
||||
if(config.tooltips) {
|
||||
@ -1035,7 +1055,7 @@
|
||||
targetTime = input;
|
||||
}
|
||||
// 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
|
||||
// Seek to the selected time
|
||||
targetTime = ((input.target.value / input.target.max) * player.media.duration);
|
||||
@ -1076,12 +1096,12 @@
|
||||
|
||||
// If it's a fullscreen change event, it's probably a native close
|
||||
if(event && event.type === fullscreen.fullScreenEventName) {
|
||||
config.fullscreen.active = fullscreen.isFullScreen();
|
||||
player.isFullscreen = fullscreen.isFullScreen(player.container);
|
||||
}
|
||||
// If there's native support, use it
|
||||
else if(nativeSupport) {
|
||||
// Request fullscreen
|
||||
if(!fullscreen.isFullScreen()) {
|
||||
if(!fullscreen.isFullScreen(player.container)) {
|
||||
fullscreen.requestFullScreen(player.container);
|
||||
}
|
||||
// Bail from fullscreen
|
||||
@ -1090,14 +1110,14 @@
|
||||
}
|
||||
|
||||
// Check if we're actually full screen (it could fail)
|
||||
config.fullscreen.active = fullscreen.isFullScreen();
|
||||
player.isFullscreen = fullscreen.isFullScreen(player.container);
|
||||
}
|
||||
else {
|
||||
// Otherwise, it's a simple toggle
|
||||
config.fullscreen.active = !config.fullscreen.active;
|
||||
player.isFullscreen = !player.isFullscreen;
|
||||
|
||||
// Bind/unbind escape key
|
||||
if(config.fullscreen.active) {
|
||||
if(player.isFullscreen) {
|
||||
_on(document, "keyup", _handleEscapeFullscreen);
|
||||
document.body.style.overflow = "hidden";
|
||||
}
|
||||
@ -1108,13 +1128,18 @@
|
||||
}
|
||||
|
||||
// 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
|
||||
function _handleEscapeFullscreen(event) {
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
@ -1153,7 +1178,7 @@
|
||||
|
||||
// Store the volume in storage
|
||||
if(config.storage.enabled && _storage().supported) {
|
||||
window.localStorage.plyr_volume = volume;
|
||||
window.localStorage.setItem(config.storage.key, volume);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1391,6 +1416,9 @@
|
||||
|
||||
// Listen for events
|
||||
function _listeners() {
|
||||
// IE doesn't support input event, so we fallback to change
|
||||
var inputEvent = (player.browser.name == "IE" ? "change" : "input");
|
||||
|
||||
// Play
|
||||
_on(player.buttons.play, "click", function() {
|
||||
_play();
|
||||
@ -1412,9 +1440,11 @@
|
||||
// Fast forward
|
||||
_on(player.buttons.forward, "click", _forward);
|
||||
|
||||
// Get the HTML5 range input element and append audio volume adjustment on change/input
|
||||
// IE10 doesn't support the "input" event so they have to wait for change
|
||||
_on(player.volume, "change input", function() {
|
||||
// Seek
|
||||
_on(player.buttons.seek, inputEvent, _seek);
|
||||
|
||||
// Set volume
|
||||
_on(player.volume, inputEvent, function() {
|
||||
_setVolume(this.value);
|
||||
});
|
||||
|
||||
@ -1440,9 +1470,6 @@
|
||||
// Display duration
|
||||
_on(player.media, "loadedmetadata", _displayDuration);
|
||||
|
||||
// Seek
|
||||
_on(player.buttons.seek, "change input", _seek);
|
||||
|
||||
// Captions
|
||||
_on(player.buttons.captions, "change", function() {
|
||||
_toggleCaptions(this.checked);
|
||||
@ -1481,14 +1508,14 @@
|
||||
if(player.type === "video" && config.click) {
|
||||
_on(player.videoContainer, "click", function() {
|
||||
if(player.media.paused) {
|
||||
_play();
|
||||
_triggerEvent(player.buttons.play, "click");
|
||||
}
|
||||
else if(player.media.ended) {
|
||||
_seek();
|
||||
_play();
|
||||
_triggerEvent(player.buttons.play, "click");
|
||||
}
|
||||
else {
|
||||
_pause();
|
||||
_triggerEvent(player.buttons.pause, "click");
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1497,11 +1524,51 @@
|
||||
if(config.fullscreen.hideControls) {
|
||||
_on(player.controls, "mouseenter mouseleave", function(event) {
|
||||
_toggleClass(player.controls, config.classes.hover, (event.type === "mouseenter"));
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy an instance
|
||||
function _destroy() {
|
||||
// Bail if the element is not initialized
|
||||
if(!player.init) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Event listeners are removed when elements are removed
|
||||
// http://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory
|
||||
|
||||
// Remove controls
|
||||
_remove(_getElement(config.selectors.controls));
|
||||
|
||||
// If video, we need to remove some more
|
||||
if(player.type === "video") {
|
||||
// Remove captions
|
||||
_remove(_getElement(config.selectors.captions));
|
||||
|
||||
// Remove video wrapper
|
||||
_unwrap(player.videoContainer);
|
||||
}
|
||||
|
||||
// Restore native video controls
|
||||
player.media.setAttribute("controls", "");
|
||||
|
||||
// Clone the media element to remove listeners
|
||||
// http://stackoverflow.com/questions/19469881/javascript-remove-all-event-listeners-of-specific-type
|
||||
var clone = player.media.cloneNode(true);
|
||||
player.media.parentNode.replaceChild(clone, player.media);
|
||||
|
||||
// Remove init flag
|
||||
player.init = false;
|
||||
}
|
||||
|
||||
// Setup a player
|
||||
function _init() {
|
||||
// Bail if the element is initialized
|
||||
if(player.init) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Setup the fullscreen api
|
||||
fullscreen = _fullscreen();
|
||||
|
||||
@ -1528,9 +1595,6 @@
|
||||
// Setup media
|
||||
_setupMedia();
|
||||
|
||||
// Generate random number for id/for attribute values for controls
|
||||
player.random = Math.floor(Math.random() * (10000));
|
||||
|
||||
// If there's full support
|
||||
if(player.supported.full) {
|
||||
// Inject custom controls
|
||||
@ -1563,10 +1627,14 @@
|
||||
}
|
||||
|
||||
// Successful setup
|
||||
return true;
|
||||
player.init = true;
|
||||
}
|
||||
|
||||
if(!_init()) {
|
||||
// Initialize instance
|
||||
_init();
|
||||
|
||||
// If init failed, return an empty object
|
||||
if(!player.init) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -1578,12 +1646,16 @@
|
||||
rewind: _rewind,
|
||||
forward: _forward,
|
||||
seek: _seek,
|
||||
source: _parseSource,
|
||||
poster: _updatePoster,
|
||||
setVolume: _setVolume,
|
||||
toggleMute: _toggleMute,
|
||||
toggleCaptions: _toggleCaptions,
|
||||
source: _parseSource,
|
||||
poster: _updatePoster,
|
||||
support: function(mimeType) { return _supportMime(player, mimeType); }
|
||||
toggleFullscreen: _toggleFullscreen,
|
||||
isFullscreen: function() { return player.isFullscreen || false; },
|
||||
support: function(mimeType) { return _supportMime(player, mimeType); },
|
||||
destroy: _destroy,
|
||||
restore: _init
|
||||
}
|
||||
}
|
||||
|
||||
@ -1646,13 +1718,16 @@
|
||||
|
||||
// Set plyr to false if setup failed
|
||||
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);
|
||||
}
|
||||
|
||||
return players;
|
||||
}
|
||||
|
||||
}(this.plyr = this.plyr || {}));
|
||||
}(this.plyr = this.plyr || {}));
|
||||
|
@ -9,6 +9,7 @@
|
||||
@gray-dark: #343f4a;
|
||||
@gray: #565d64;
|
||||
@gray-light: #cbd0d3;
|
||||
@off-white: #d6dadd;
|
||||
|
||||
// Font sizes
|
||||
@font-size-small: 14px;
|
||||
@ -527,6 +528,17 @@
|
||||
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
|
||||
&-fullscreen,
|
||||
&.fullscreen-active {
|
||||
|
@ -5,49 +5,50 @@
|
||||
// Variables
|
||||
// -------------------------------
|
||||
// Colors
|
||||
$blue: #3498DB;
|
||||
$gray-dark: #343f4a;
|
||||
$gray: #565d64;
|
||||
$gray-light: #cbd0d3;
|
||||
$blue: #3498DB !default;
|
||||
$gray-dark: #343f4a !default;
|
||||
$gray: #565d64 !default;
|
||||
$gray-light: #cbd0d3 !default;
|
||||
$off-white: #d6dadd !default;
|
||||
|
||||
// Font sizes
|
||||
$font-size-small: 14px;
|
||||
$font-size-base: 16px;
|
||||
$font-size-large: ceil(($font-size-base * 1.5));
|
||||
$font-size-small: 14px !default;
|
||||
$font-size-base: 16px !default;
|
||||
$font-size-large: ceil(($font-size-base * 1.5)) !default;
|
||||
|
||||
// Controls
|
||||
$control-spacing: 10px;
|
||||
$controls-bg: $gray-dark;
|
||||
$control-bg-hover: $blue;
|
||||
$control-color: $gray-light;
|
||||
$control-color-inactive: $gray;
|
||||
$control-color-hover: #fff;
|
||||
$control-spacing: 10px !default;
|
||||
$controls-bg: $gray-dark !default;
|
||||
$control-bg-hover: $blue !default;
|
||||
$control-color: $gray-light !default;
|
||||
$control-color-inactive: $gray !default;
|
||||
$control-color-hover: #fff !default;
|
||||
|
||||
// Tooltips
|
||||
$tooltip-bg: $controls-bg;
|
||||
$tooltip-color: #fff;
|
||||
$tooltip-padding: $control-spacing;
|
||||
$tooltip-arrow-size: 5px;
|
||||
$tooltip-radius: 3px;
|
||||
$tooltip-bg: $controls-bg !default;
|
||||
$tooltip-color: #fff !default;
|
||||
$tooltip-padding: $control-spacing !default;
|
||||
$tooltip-arrow-size: 5px !default;
|
||||
$tooltip-radius: 3px !default;
|
||||
|
||||
// Progress
|
||||
$progress-bg: rgba(red($gray), green($gray), blue($gray), .2);
|
||||
$progress-playing-bg: $blue;
|
||||
$progress-buffered-bg: rgba(red($gray), green($gray), blue($gray), .25);
|
||||
$progress-loading-size: 40px;
|
||||
$progress-loading-bg: rgba(0,0,0, .15);
|
||||
$progress-bg: rgba(red($gray), green($gray), blue($gray), .2) !default;
|
||||
$progress-playing-bg: $blue !default;
|
||||
$progress-buffered-bg: rgba(red($gray), green($gray), blue($gray), .25) !default;
|
||||
$progress-loading-size: 40px !default;
|
||||
$progress-loading-bg: rgba(0,0,0, .15) !default;
|
||||
|
||||
// Volume
|
||||
$volume-track-height: 6px;
|
||||
$volume-track-bg: $gray;
|
||||
$volume-thumb-height: ($volume-track-height * 2);
|
||||
$volume-thumb-width: ($volume-track-height * 2);
|
||||
$volume-thumb-bg: $control-color;
|
||||
$volume-thumb-bg-focus: $control-bg-hover;
|
||||
$volume-track-height: 6px !default;
|
||||
$volume-track-bg: $gray !default;
|
||||
$volume-thumb-height: ($volume-track-height * 2) !default;
|
||||
$volume-thumb-width: ($volume-track-height * 2) !default;
|
||||
$volume-thumb-bg: $control-color !default;
|
||||
$volume-thumb-bg-focus: $control-bg-hover !default;
|
||||
|
||||
// Breakpoints
|
||||
$bp-control-split: 560px; // When controls split into left/right
|
||||
$bp-captions-large: 768px; // When captions jump to the larger font size
|
||||
$bp-control-split: 560px !default; // When controls split into left/right
|
||||
$bp-captions-large: 768px !default; // When captions jump to the larger font size
|
||||
|
||||
// Utility classes & mixins
|
||||
// -------------------------------
|
||||
@ -535,6 +536,17 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
|
||||
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
|
||||
&-fullscreen,
|
||||
&.fullscreen-active {
|
||||
|
Reference in New Issue
Block a user