Compare commits

...

17 Commits

Author SHA1 Message Date
a509a5e1bc v2.0.8
- Added `isPaused()` API method (thanks to @darrena092)
- Allowed `.on()` API method to be chainable (thanks to @gurupras) (fixes #357)
- Improved the "awful" rendering of captions on small screens in fullscreen mode (fixes #390)
- Fix for Firefox VTT compatibility (thanks to @magourex)
- Fix for Firefox Developer Edition blank video due to `-webkit-mask-image` issue (fixes #392)
- Added Issue and PR templates with the aim of reducing duplicate or duff issues
2016-10-23 13:48:05 +11:00
bec10e7836 Fix for caption size (fixes #390), Fix for Firefox Dev (fixes #392) 2016-10-23 13:35:49 +11:00
f9a184800b Add Issue and PR templates 2016-10-23 13:34:44 +11:00
f428c3ff8b Manually merged #395 2016-10-23 12:19:39 +11:00
97eb40a8e3 Merge pull request #389 from darrena092/master
Added .isPaused().
2016-10-23 11:51:10 +11:00
8211631950 Gulp build done. 2016-10-06 15:43:41 +01:00
a17cbb0e8b Added .isPaused to API 2016-10-06 15:33:49 +01:00
8098be6f93 Merge pull request #379 from magourex/master
Support WebVTT with CRLF or LF Line separator with firefox #378
2016-10-01 22:10:35 +10:00
1c73c9fbfe Update plyr.js 2016-09-27 10:57:35 +02:00
978606edb4 CSS path 2016-09-06 23:54:04 +10:00
Sam
435b5c74bf Fixed API method, added new methods (fixes #346, #351)
- Fixed `getCurrentTime()` method (fixes #351)
- Added `getVolume()` , `isMuted()` and `getDuration()` API methods (fixes #346)
2016-08-29 23:36:43 +10:00
Sam
15fd7041ab Fixed AMD definition 2016-08-26 21:43:51 +10:00
1ced6b4d67 Vimeo IE9/10 (Fixes #348), HTML5 ready event (Fixes #349) 2016-08-26 18:15:24 +10:00
Sam
6694c1e6cf Fix for Firefox full screen (fixes #343) 2016-08-23 00:34:43 +10:00
19ca906e50 Update changelog.md 2016-08-22 20:41:49 +10:00
12e94775d6 Global keyboard shortcut changes 2016-08-22 14:44:18 +10:00
df7f52d885 Added ‘global’ keyboard shortcut option 2016-08-22 14:15:49 +10:00
17 changed files with 377 additions and 290 deletions

18
.github/issue_template.md vendored Normal file
View File

@ -0,0 +1,18 @@
- [ ] Issue does not already exist
- [ ] Issue observed on https://plyr.io
### Expected behaviour
### Actual behaviour
### Environment
- Browser:
- Version:
- Operating System:
- Version:
### Steps to reproduce
-
### Relevant links

8
.github/pull_request_template.md vendored Normal file
View File

@ -0,0 +1,8 @@
### Link to related issue (if applicable)
### Sumary of proposed changes
### Task list
- [ ] Tested on [supported browsers](https://github.com/Selz/plyr#browser-support)
- [ ] Gulp build completed

11
.jsbeautifyrc Normal file
View File

@ -0,0 +1,11 @@
{
"html": {
"allowed_file_extensions": []
},
"css": {
"allowed_file_extensions": []
},
"js": {
"allowed_file_extensions": []
}
}

View File

@ -1,7 +1,36 @@
# Changelog # Changelog
# v2.0.1 ## v2.0.8
- Version bump for NPM - Added `isPaused()` API method (thanks to @darrena092)
- Allowed `.on()` API method to be chainable (thanks to @gurupras) (fixes #357)
- Improved the "awful" rendering of captions on small screens in fullscreen mode (fixes #390)
- Fix for Firefox VTT compatibility (thanks to @magourex)
- Fix for Firefox Developer Edition blank video due to `-webkit-mask-image` issue (fixes #392)
- Added Issue and PR templates with the aim of reducing duplicate or duff issues
## v2.0.7
- Fixed `getCurrentTime()` method (fixes #351)
- Added `getVolume()` , `isMuted()` and `getDuration()` API methods (fixes #346)
## v2.0.6
- Fixed merge issue with `Updated define to work with AMD imports #326` PR
- Code formatting
## v2.0.5
- Fix for Vimeo in IE9 & IE10
- Fix for HTML5 elements not firing `ready` event
## v2.0.4
- Fix for Firefox full screen (fixes #343)
## v2.0.3
- Set 'global' keyboard shortcut option to false as default, added `<textarea>` to editable elements to be ignored
## v2.0.2
- Added 'global' keyboard shortcut option
## v2.0.1
- Version bump for NPM (sorry for folks who upgraded to the now deleted v1.9.0 through NPM)
# v2.0.0 # v2.0.0
This version contains several potential ***breaking changes***: This version contains several potential ***breaking changes***:

2
demo/dist/demo.css vendored

File diff suppressed because one or more lines are too long

2
demo/dist/demo.js vendored
View File

@ -1 +1 @@
"document"in self&&("classList"in document.createElement("_")?!function(){"use strict";var e=document.createElement("_");if(e.classList.add("c1","c2"),!e.classList.contains("c2")){var t=function(e){var t=DOMTokenList.prototype[e];DOMTokenList.prototype[e]=function(e){var i,s=arguments.length;for(i=0;s>i;i++)e=arguments[i],t.call(this,e)}};t("add"),t("remove")}if(e.classList.toggle("c3",!1),e.classList.contains("c3")){var i=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(e,t){return 1 in arguments&&!this.contains(e)==!t?t:i.call(this,e)}}e=null}():!function(e){"use strict";if("Element"in e){var t="classList",i="prototype",s=e.Element[i],o=Object,n=String[i].trim||function(){return this.replace(/^\s+|\s+$/g,"")},r=Array[i].indexOf||function(e){for(var t=0,i=this.length;i>t;t++)if(t in this&&this[t]===e)return t;return-1},a=function(e,t){this.name=e,this.code=DOMException[e],this.message=t},c=function(e,t){if(""===t)throw new a("SYNTAX_ERR","An invalid or illegal string was specified");if(/\s/.test(t))throw new a("INVALID_CHARACTER_ERR","String contains an invalid character");return r.call(e,t)},l=function(e){for(var t=n.call(e.getAttribute("class")||""),i=t?t.split(/\s+/):[],s=0,o=i.length;o>s;s++)this.push(i[s]);this._updateClassName=function(){e.setAttribute("class",this.toString())}},u=l[i]=[],d=function(){return new l(this)};if(a[i]=Error[i],u.item=function(e){return this[e]||null},u.contains=function(e){return e+="",-1!==c(this,e)},u.add=function(){var e,t=arguments,i=0,s=t.length,o=!1;do e=t[i]+"",-1===c(this,e)&&(this.push(e),o=!0);while(++i<s);o&&this._updateClassName()},u.remove=function(){var e,t,i=arguments,s=0,o=i.length,n=!1;do for(e=i[s]+"",t=c(this,e);-1!==t;)this.splice(t,1),n=!0,t=c(this,e);while(++s<o);n&&this._updateClassName()},u.toggle=function(e,t){e+="";var i=this.contains(e),s=i?t!==!0&&"remove":t!==!1&&"add";return s&&this[s](e),t===!0||t===!1?t:!i},u.toString=function(){return this.join(" ")},o.defineProperty){var p={get:d,enumerable:!0,configurable:!0};try{o.defineProperty(s,t,p)}catch(h){-2146823252===h.number&&(p.enumerable=!1,o.defineProperty(s,t,p))}}else o[i].__defineGetter__&&s.__defineGetter__(t,d)}}(self)),function(){function e(e,t,i){if(e)if(e.classList)e.classList[i?"add":"remove"](t);else{var s=(" "+e.className+" ").replace(/\s+/g," ").replace(" "+t+" ","");e.className=s+(i?" "+t:"")}}function t(t,i){if(t in n&&(i||t!=r)&&(r.length||t!=n.video)){switch(t){case n.video:s.source({type:"video",title:"View From A Blue Moon",sources:[{src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4",type:"video/mp4"},{src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.webm",type:"video/webm"}],poster:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg",tracks:[{kind:"captions",label:"English",srclang:"en",src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt","default":!0}]});break;case n.audio:s.source({type:"audio",title:"Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;",sources:[{src:"https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3",type:"audio/mp3"},{src:"https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg",type:"audio/ogg"}]});break;case n.youtube:s.source({type:"video",title:"View From A Blue Moon",sources:[{src:"bTqVqk7FSmY",type:"youtube"}]});break;case n.vimeo:s.source({type:"video",title:"View From A Blue Moon",sources:[{src:"143418951",type:"vimeo"}]})}r=t;for(var a=o.length-1;a>=0;a--)e(o[a].parentElement,"active",!1);e(document.querySelector('[data-source="'+t+'"]').parentElement,"active",!0)}}var i=plyr.setup({debug:!0,title:"Video demo",iconUrl:"../dist/plyr.svg",tooltips:{controls:!0},captions:{defaultActive:!0}});plyr.loadSprite("dist/demo.svg");for(var s=i[0],o=document.querySelectorAll("[data-source]"),n={video:"video",audio:"audio",youtube:"youtube",vimeo:"vimeo"},r=window.location.hash.replace("#",""),a=window.history&&window.history.pushState,c=o.length-1;c>=0;c--)o[c].addEventListener("click",function(){var e=this.getAttribute("data-source");t(e),a&&history.pushState({type:e},"","#"+e)});if(window.addEventListener("popstate",function(e){e.state&&"type"in e.state&&t(e.state.type)}),a){var l=!r.length;l&&(r=n.video),r in n&&history.replaceState({type:r},"",l?"":"#"+r),r!==n.video&&t(r,!0)}}(),document.domain.indexOf("plyr.io")>-1&&(!function(e,t,i,s,o,n,r){e.GoogleAnalyticsObject=o,e[o]=e[o]||function(){(e[o].q=e[o].q||[]).push(arguments)},e[o].l=1*new Date,n=t.createElement(i),r=t.getElementsByTagName(i)[0],n.async=1,n.src=s,r.parentNode.insertBefore(n,r)}(window,document,"script","//www.google-analytics.com/analytics.js","ga"),ga("create","UA-40881672-11","auto"),ga("send","pageview")); "document"in self&&("classList"in document.createElement("_")?!function(){"use strict";var e=document.createElement("_");if(e.classList.add("c1","c2"),!e.classList.contains("c2")){var t=function(e){var t=DOMTokenList.prototype[e];DOMTokenList.prototype[e]=function(e){var i,s=arguments.length;for(i=0;i<s;i++)e=arguments[i],t.call(this,e)}};t("add"),t("remove")}if(e.classList.toggle("c3",!1),e.classList.contains("c3")){var i=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(e,t){return 1 in arguments&&!this.contains(e)==!t?t:i.call(this,e)}}e=null}():!function(e){"use strict";if("Element"in e){var t="classList",i="prototype",s=e.Element[i],o=Object,n=String[i].trim||function(){return this.replace(/^\s+|\s+$/g,"")},r=Array[i].indexOf||function(e){for(var t=0,i=this.length;t<i;t++)if(t in this&&this[t]===e)return t;return-1},a=function(e,t){this.name=e,this.code=DOMException[e],this.message=t},c=function(e,t){if(""===t)throw new a("SYNTAX_ERR","An invalid or illegal string was specified");if(/\s/.test(t))throw new a("INVALID_CHARACTER_ERR","String contains an invalid character");return r.call(e,t)},l=function(e){for(var t=n.call(e.getAttribute("class")||""),i=t?t.split(/\s+/):[],s=0,o=i.length;s<o;s++)this.push(i[s]);this._updateClassName=function(){e.setAttribute("class",this.toString())}},u=l[i]=[],d=function(){return new l(this)};if(a[i]=Error[i],u.item=function(e){return this[e]||null},u.contains=function(e){return e+="",c(this,e)!==-1},u.add=function(){var e,t=arguments,i=0,s=t.length,o=!1;do e=t[i]+"",c(this,e)===-1&&(this.push(e),o=!0);while(++i<s);o&&this._updateClassName()},u.remove=function(){var e,t,i=arguments,s=0,o=i.length,n=!1;do for(e=i[s]+"",t=c(this,e);t!==-1;)this.splice(t,1),n=!0,t=c(this,e);while(++s<o);n&&this._updateClassName()},u.toggle=function(e,t){e+="";var i=this.contains(e),s=i?t!==!0&&"remove":t!==!1&&"add";return s&&this[s](e),t===!0||t===!1?t:!i},u.toString=function(){return this.join(" ")},o.defineProperty){var p={get:d,enumerable:!0,configurable:!0};try{o.defineProperty(s,t,p)}catch(e){e.number===-2146823252&&(p.enumerable=!1,o.defineProperty(s,t,p))}}else o[i].__defineGetter__&&s.__defineGetter__(t,d)}}(self)),function(){function e(e,t,i){if(e)if(e.classList)e.classList[i?"add":"remove"](t);else{var s=(" "+e.className+" ").replace(/\s+/g," ").replace(" "+t+" ","");e.className=s+(i?" "+t:"")}}function t(t,i){if(t in n&&(i||t!=r)&&(r.length||t!=n.video)){switch(t){case n.video:s.source({type:"video",title:"View From A Blue Moon",sources:[{src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4",type:"video/mp4"},{src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.webm",type:"video/webm"}],poster:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg",tracks:[{kind:"captions",label:"English",srclang:"en",src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt",default:!0}]});break;case n.audio:s.source({type:"audio",title:"Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;",sources:[{src:"https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3",type:"audio/mp3"},{src:"https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg",type:"audio/ogg"}]});break;case n.youtube:s.source({type:"video",title:"View From A Blue Moon",sources:[{src:"bTqVqk7FSmY",type:"youtube"}]});break;case n.vimeo:s.source({type:"video",title:"View From A Blue Moon",sources:[{src:"143418951",type:"vimeo"}]})}r=t;for(var a=o.length-1;a>=0;a--)e(o[a].parentElement,"active",!1);e(document.querySelector('[data-source="'+t+'"]').parentElement,"active",!0)}}var i=plyr.setup({debug:!0,title:"Video demo",iconUrl:"../dist/plyr.svg",tooltips:{controls:!0},captions:{defaultActive:!0}});plyr.loadSprite("dist/demo.svg");for(var s=i[0],o=document.querySelectorAll("[data-source]"),n={video:"video",audio:"audio",youtube:"youtube",vimeo:"vimeo"},r=window.location.hash.replace("#",""),a=window.history&&window.history.pushState,c=o.length-1;c>=0;c--)o[c].addEventListener("click",function(){var e=this.getAttribute("data-source");t(e),a&&history.pushState({type:e},"","#"+e)});if(window.addEventListener("popstate",function(e){e.state&&"type"in e.state&&t(e.state.type)}),a){var l=!r.length;l&&(r=n.video),r in n&&history.replaceState({type:r},"",l?"":"#"+r),r!==n.video&&t(r,!0)}}(),document.domain.indexOf("plyr.io")>-1&&(!function(e,t,i,s,o,n,r){e.GoogleAnalyticsObject=o,e[o]=e[o]||function(){(e[o].q=e[o].q||[]).push(arguments)},e[o].l=1*new Date,n=t.createElement(i),r=t.getElementsByTagName(i)[0],n.async=1,n.src=s,r.parentNode.insertBefore(n,r)}(window,document,"script","//www.google-analytics.com/analytics.js","ga"),ga("create","UA-40881672-11","auto"),ga("send","pageview"));

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="dist/docs.css"> <link rel="stylesheet" href="dist/demo.css">
</head> </head>
<body> <body>
<main> <main>

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

4
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

View File

@ -245,15 +245,15 @@ options = {
// If aws is setup // If aws is setup
if("cdn" in aws) { if("cdn" in aws) {
var regex = "(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:-[\\da-z\\-]+(?:\.[\\da-z\\-]+)*)?(?:\\+[\\da-z\\-]+(?:\.[\\da-z\\-]+)*)?", var regex = "(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:-[\\da-z\\-]+(?:\.[\\da-z\\-]+)*)?(?:\\+[\\da-z\\-]+(?:\.[\\da-z\\-]+)*)?",
cdnpath = new RegExp(aws.cdn.bucket + "\/" + regex, "gi"), cdnpath = new RegExp(aws.cdn.domain + "\/" + regex, "gi"),
semver = new RegExp("v" + regex, "gi"), semver = new RegExp("v" + regex, "gi"),
localPath = new RegExp("(\.\.\/)?dist", "gi"), localPath = new RegExp("(\.\.\/)?dist", "gi"),
versionPath = "https://" + aws.cdn.bucket + "/" + version; versionPath = "https://" + aws.cdn.domain + "/" + version;
} }
// Publish version to CDN bucket // Publish version to CDN bucket
gulp.task("cdn", function () { gulp.task("cdn", function () {
console.log("Uploading " + version + " to " + aws.cdn.bucket + "..."); console.log("Uploading " + version + " to " + aws.cdn.domain + "...");
// Upload to CDN // Upload to CDN
return gulp.src(paths.upload) return gulp.src(paths.upload)
@ -270,17 +270,17 @@ gulp.task("cdn", function () {
// Publish to demo bucket // Publish to demo bucket
gulp.task("demo", function () { gulp.task("demo", function () {
console.log("Uploading " + version + " demo to " + aws.demo.bucket + "..."); console.log("Uploading " + version + " demo to " + aws.demo.domain + "...");
// Replace versioned files in readme.md // Replace versioned files in readme.md
gulp.src([root + "/readme.md"]) gulp.src([root + "/readme.md"])
.pipe(replace(cdnpath, aws.cdn.bucket + "/" + version)) .pipe(replace(cdnpath, aws.cdn.domain + "/" + version))
.pipe(gulp.dest(root)); .pipe(gulp.dest(root));
// Replace versioned files in plyr.js // Replace versioned files in plyr.js
gulp.src(path.join(root, "src/js/plyr.js")) gulp.src(path.join(root, "src/js/plyr.js"))
.pipe(replace(semver, "v" + version)) .pipe(replace(semver, "v" + version))
.pipe(replace(cdnpath, aws.cdn.bucket + "/" + version)) .pipe(replace(cdnpath, aws.cdn.domain + "/" + version))
.pipe(gulp.dest(path.join(root, "src/js/"))); .pipe(gulp.dest(path.join(root, "src/js/")));
// Replace local file paths with remote paths in demo HTML // Replace local file paths with remote paths in demo HTML
@ -320,14 +320,14 @@ gulp.task("symlinks", function () {
// Open the demo site to check it's sweet // Open the demo site to check it's sweet
gulp.task("open", function () { gulp.task("open", function () {
console.log("Opening " + aws.demo.bucket + "..."); console.log("Opening " + aws.demo.domain + "...");
// A file must be specified or gulp will skip the task // A file must be specified or gulp will skip the task
// Doesn't matter which file since we set the URL above // Doesn't matter which file since we set the URL above
// Weird, I know... // Weird, I know...
return gulp.src([paths.demo.root + "index.html"]) return gulp.src([paths.demo.root + "index.html"])
.pipe(open("", { .pipe(open("", {
url: "http://" + aws.demo.bucket url: "http://" + aws.demo.domain
})); }));
}); });

View File

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

View File

@ -122,7 +122,7 @@ Include the `plyr.js` script before the closing `</body>` tag and then call `ply
If you want to use our CDN for the JavaScript, you can use the following: If you want to use our CDN for the JavaScript, you can use the following:
```html ```html
<script src="https://cdn.plyr.io/2.0.1/plyr.js"></script> <script src="https://cdn.plyr.io/2.0.8/plyr.js"></script>
``` ```
### CSS ### CSS
@ -135,11 +135,11 @@ Include the `plyr.css` stylsheet into your `<head>`
If you want to use our CDN for the default CSS, you can use the following: If you want to use our CDN for the default CSS, you can use the following:
```html ```html
<link rel="stylesheet" href="https://cdn.plyr.io/2.0.1/plyr.css"> <link rel="stylesheet" href="https://cdn.plyr.io/2.0.8/plyr.css">
``` ```
### SVG Sprite ### SVG Sprite
The SVG sprite is loaded automatically from our CDN. To change this, see the [options](#Options) below. For reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/2.0.1/plyr.svg`. The SVG sprite is loaded automatically from our CDN. To change this, see the [options](#Options) below. For reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/2.0.8/plyr.svg`.
## Advanced ## Advanced
@ -321,9 +321,9 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke
</tr> </tr>
<tr> <tr>
<td><code>keyboardShortcuts</code></td> <td><code>keyboardShortcuts</code></td>
<td>Boolean</td> <td>Object</td>
<td><code>true</code></td> <td><code>{ focused: true, global: false }</code></td>
<td>Enable <a href="#shortcuts">keyboard shortcuts</a></td> <td>Enable <a href="#shortcuts">keyboard shortcuts</a> for focused players only or globally as well (this will only work if there's one player in the document)</td>
</tr> </tr>
<tr> <tr>
<td><code>tooltips</code></td> <td><code>tooltips</code></td>
@ -487,12 +487,12 @@ Here's a list of the methods supported:
<tr> <tr>
<td><code>isReady()</code></td> <td><code>isReady()</code></td>
<td>&mdash;</td> <td>&mdash;</td>
<td>Determine if the player is loaded and UI ready - this is because HTML5 is ready instantly but YouTube and Vimeo can take some time to load their APIs.</td> <td>Determine if the player is loaded and UI ready.</td>
</tr> </tr>
<tr> <tr>
<td><code>on()</code></td> <td><code>on()</code></td>
<td>String, Function</td> <td>String, Function</td>
<td>Watch for an event (first argument) and run a callback function (second argument). This saves you doing your own <code>addEventListner</code> code.</td> <td>Watch for an event (first argument) and run a callback function (second argument). This saves you doing your own <code>addEventListner</code> code. This is chainable.</td>
</tr> </tr>
<tr> <tr>
<td><code>play()</code></td> <td><code>play()</code></td>
@ -529,6 +529,26 @@ Here's a list of the methods supported:
<td>Number</td> <td>Number</td>
<td>Seeks the media to the provided parameter, time in seconds.</td> <td>Seeks the media to the provided parameter, time in seconds.</td>
</tr> </tr>
<tr>
<td><code>getCurrentTime()</code></td>
<td>&mdash;</td>
<td>Will return a float with the current time in seconds.</td>
</tr>
<tr>
<td><code>getDuration()</code></td>
<td>&mdash;</td>
<td>Will return a float with the duration in seconds.</td>
</tr>
<tr>
<td><code>getVolume()</code></td>
<td>&mdash;</td>
<td>Will return a float between 0 and 1 for the current volume level.</td>
</tr>
<tr>
<td><code>isMuted()</code></td>
<td>&mdash;</td>
<td>Will return a boolean for whether the media is currently muted.</td>
</tr>
<tr> <tr>
<td><code>setVolume(...)</code></td> <td><code>setVolume(...)</code></td>
<td>Number</td> <td>Number</td>
@ -539,6 +559,11 @@ Here's a list of the methods supported:
<td>Boolean</td> <td>Boolean</td>
<td>Toggles playback for the player based on either the boolean argument or it's current state.</td> <td>Toggles playback for the player based on either the boolean argument or it's current state.</td>
</tr> </tr>
<tr>
<td><code>isPaused()</code></td>
<td>&mdash;</td>
<td>Will return a boolean for whether the media is currently paused.</td>
</tr>
<tr> <tr>
<td><code>toggleMute()</code></td> <td><code>toggleMute()</code></td>
<td>&mdash;</td> <td>&mdash;</td>
@ -590,11 +615,6 @@ Here's a list of the methods supported:
<td>&mdash;</td> <td>&mdash;</td>
<td>Restores the original element, reversing the effects of <code>setup()</code>.</td> <td>Restores the original element, reversing the effects of <code>setup()</code>.</td>
</tr> </tr>
<tr>
<td><code>getCurrentTime()</code></td>
<td>&mdash;</td>
<td>Will return a float with the current time in seconds.</td>
</tr>
</tbody> </tbody>
</table> </table>
@ -736,7 +756,7 @@ These events also bubble up the DOM. The event target will be the container elem
<tr> <tr>
<td><code>ready</code></td> <td><code>ready</code></td>
<td></td> <td></td>
<td>Triggered when the instance is ready for API use and external APIs are ready (YouTube and Vimeo).</td> <td>Triggered when the instance is ready for API use and external APIs are ready (in the case of YouTube and Vimeo).</td>
</tr> </tr>
<tr> <tr>
<td><code>canplay</code></td> <td><code>canplay</code></td>
@ -873,50 +893,65 @@ More info on the respective API's here:
*Please note*: not all API methods may work 100%. Your mileage may vary. It's better to use the universal plyr API where possible. *Please note*: not all API methods may work 100%. Your mileage may vary. It's better to use the universal plyr API where possible.
## Shortcuts ## Shortcuts
By default, a focused player will bind the following keyboard shortcuts: By default, a player will bind the following keyboard shortcuts when it has focus. If you have the `global` option to `true` and there's only one player in the document then the shortcuts will work when any element has focus, apart from an element that requires input.
<table class="table" width="100%"> <table class="table" width="100%">
<thead> <thead>
<tr> <tr>
<th width="25%">Key</th> <th width="25%">Key</th>
<th width="75%">Action</th> <th width="25%">Global</th>
<th width="50%">Action</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><code>0</code> to <code>9</code></td> <td><code>0</code> to <code>9</code></td>
<td></td>
<td>Seek from 0 to 90% respectively</td> <td>Seek from 0 to 90% respectively</td>
</tr> </tr>
<tr> <tr>
<td><code>space</code> or <code>K</code></td> <td><code>space</code></td>
<td></td>
<td>Toggle playback</td>
</tr>
<tr>
<td><code>K</code></td>
<td></td>
<td>Toggle playback</td> <td>Toggle playback</td>
</tr> </tr>
<tr> <tr>
<td><code>&larr;</code></td> <td><code>&larr;</code></td>
<td></td>
<td>Seek backward by the <code>seekTime</code> option</td> <td>Seek backward by the <code>seekTime</code> option</td>
</tr> </tr>
<tr> <tr>
<td><code>&rarr;</code></td> <td><code>&rarr;</code></td>
<td></td>
<td>Seek forward by the <code>seekTime</code> option</td> <td>Seek forward by the <code>seekTime</code> option</td>
</tr> </tr>
<tr> <tr>
<td><code>&uarr;</code></td> <td><code>&uarr;</code></td>
<td></td>
<td>Increase volume</td> <td>Increase volume</td>
</tr> </tr>
<tr> <tr>
<td><code>&darr;</code></td> <td><code>&darr;</code></td>
<td></td>
<td>Decrease volume</td> <td>Decrease volume</td>
</tr> </tr>
<tr> <tr>
<td><code>M</code></td> <td><code>M</code></td>
<td></td>
<td>Toggle mute</td> <td>Toggle mute</td>
</tr> </tr>
<tr> <tr>
<td><code>F</code></td> <td><code>F</code></td>
<td></td>
<td>Toggle fullscreen</td> <td>Toggle fullscreen</td>
</tr> </tr>
<tr> <tr>
<td><code>C</code></td> <td><code>C</code></td>
<td></td>
<td>Toggle captions</td> <td>Toggle captions</td>
</tr> </tr>
</tbody> </tbody>

View File

@ -1,6 +1,6 @@
// ========================================================================== // ==========================================================================
// Plyr // Plyr
// plyr.js v2.0.1 // plyr.js v2.0.8
// https://github.com/selz/plyr // https://github.com/selz/plyr
// License: The MIT License (MIT) // License: The MIT License (MIT)
// ========================================================================== // ==========================================================================
@ -16,7 +16,7 @@
module.exports = factory(root, document); module.exports = factory(root, document);
} else if (typeof define === 'function' && define.amd) { } else if (typeof define === 'function' && define.amd) {
// AMD // AMD
define(null, function() { factory(root, document) }); define([], function () { return factory(root, document); });
} else { } else {
// Browser globals (root is window) // Browser globals (root is window)
root.plyr = factory(root, document); root.plyr = factory(root, document);
@ -43,12 +43,15 @@
displayDuration: true, displayDuration: true,
loadSprite: true, loadSprite: true,
iconPrefix: 'plyr', iconPrefix: 'plyr',
iconUrl: 'https://cdn.plyr.io/2.0.1/plyr.svg', iconUrl: 'https://cdn.plyr.io/2.0.8/plyr.svg',
clickToPlay: true, clickToPlay: true,
hideControls: true, hideControls: true,
showPosterOnEnd: false, showPosterOnEnd: false,
disableContextMenu: true, disableContextMenu: true,
keyboardShorcuts: true, keyboardShorcuts: {
focused: true,
global: false
},
tooltips: { tooltips: {
controls: false, controls: false,
seek: true seek: true
@ -56,6 +59,7 @@
selectors: { selectors: {
html5: 'video, audio', html5: 'video, audio',
embed: '[data-type]', embed: '[data-type]',
editable: 'input, textarea, select, [contenteditable]',
container: '.plyr', container: '.plyr',
controls: { controls: {
container: null, container: null,
@ -171,7 +175,7 @@
fullscreen: null fullscreen: null
}, },
// Events to watch on HTML5 media elements // Events to watch on HTML5 media elements
events: ['ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'emptied'], events: ['ready', 'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'emptied'],
// Logging // Logging
logPrefix: '[Plyr]' logPrefix: '[Plyr]'
}; };
@ -191,41 +195,36 @@
isChrome = false, isChrome = false,
isSafari = false; isSafari = false;
// MSIE 11
if ((navigator.appVersion.indexOf('Windows NT') !== -1) && (navigator.appVersion.indexOf('rv:11') !== -1)) { if ((navigator.appVersion.indexOf('Windows NT') !== -1) && (navigator.appVersion.indexOf('rv:11') !== -1)) {
// MSIE 11
isIE = true; isIE = true;
name = 'IE'; name = 'IE';
fullVersion = '11'; fullVersion = '11';
} } else if ((verOffset = ua.indexOf('MSIE')) !== -1) {
// MSIE // MSIE
else if ((verOffset = ua.indexOf('MSIE')) !== -1) {
isIE = true; isIE = true;
name = 'IE'; name = 'IE';
fullVersion = ua.substring(verOffset + 5); fullVersion = ua.substring(verOffset + 5);
} } else if ((verOffset = ua.indexOf('Chrome')) !== -1) {
// Chrome // Chrome
else if ((verOffset = ua.indexOf('Chrome')) !== -1) {
isChrome = true; isChrome = true;
name = 'Chrome'; name = 'Chrome';
fullVersion = ua.substring(verOffset + 7); fullVersion = ua.substring(verOffset + 7);
} } else if ((verOffset = ua.indexOf('Safari')) !== -1) {
// Safari // Safari
else if ((verOffset = ua.indexOf('Safari')) !== -1) {
isSafari = true; isSafari = true;
name = 'Safari'; name = 'Safari';
fullVersion = ua.substring(verOffset + 7); fullVersion = ua.substring(verOffset + 7);
if ((verOffset = ua.indexOf('Version')) !== -1) { if ((verOffset = ua.indexOf('Version')) !== -1) {
fullVersion = ua.substring(verOffset + 8); fullVersion = ua.substring(verOffset + 8);
} }
} } else if ((verOffset = ua.indexOf('Firefox')) !== -1) {
// Firefox // Firefox
else if ((verOffset = ua.indexOf('Firefox')) !== -1) {
isFirefox = true; isFirefox = true;
name = 'Firefox'; name = 'Firefox';
fullVersion = ua.substring(verOffset + 8); fullVersion = ua.substring(verOffset + 8);
} } else if ((nameOffset = ua.lastIndexOf(' ') + 1) < (verOffset = ua.lastIndexOf('/'))) {
// 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 = ua.lastIndexOf(' ') + 1) < (verOffset = ua.lastIndexOf('/'))) {
name = ua.substring(nameOffset,verOffset); name = ua.substring(nameOffset,verOffset);
fullVersion = ua.substring(verOffset + 1); fullVersion = ua.substring(verOffset + 1);
@ -268,7 +267,6 @@
function _supportMime(plyr, mimeType) { function _supportMime(plyr, mimeType) {
var media = plyr.media; var media = plyr.media;
// Only check video types for video players
if (plyr.type === 'video') { if (plyr.type === 'video') {
// Check type // Check type
switch (mimeType) { switch (mimeType) {
@ -276,10 +274,7 @@
case 'video/mp4': return !!(media.canPlayType && media.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, '')); case 'video/mp4': return !!(media.canPlayType && media.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, ''));
case 'video/ogg': return !!(media.canPlayType && media.canPlayType('video/ogg; codecs="theora"').replace(/no/, '')); case 'video/ogg': return !!(media.canPlayType && media.canPlayType('video/ogg; codecs="theora"').replace(/no/, ''));
} }
} } else if (plyr.type === 'audio') {
// Only check audio types for audio players
else if (plyr.type === 'audio') {
// Check type // Check type
switch (mimeType) { switch (mimeType) {
case 'audio/mpeg': return !!(media.canPlayType && media.canPlayType('audio/mpeg;').replace(/no/, '')); case 'audio/mpeg': return !!(media.canPlayType && media.canPlayType('audio/mpeg;').replace(/no/, ''));
@ -340,8 +335,7 @@
// append it to the parent. // append it to the parent.
if (sibling) { if (sibling) {
parent.insertBefore(child, sibling); parent.insertBefore(child, sibling);
} } else {
else {
parent.appendChild(child); parent.appendChild(child);
} }
@ -406,8 +400,7 @@
if (element) { if (element) {
if (element.classList) { if (element.classList) {
element.classList[state ? 'add' : 'remove'](className); element.classList[state ? 'add' : 'remove'](className);
} } else {
else {
var name = (' ' + element.className + ' ').replace(/\s+/g, ' ').replace(' ' + className + ' ', ''); var name = (' ' + element.className + ' ').replace(/\s+/g, ' ').replace(' ' + className + ' ', '');
element.className = name + (state ? ' ' + className : ''); element.className = name + (state ? ' ' + className : '');
} }
@ -419,8 +412,7 @@
if (element) { if (element) {
if (element.classList) { if (element.classList) {
return element.classList.contains(className); return element.classList.contains(className);
} } else {
else {
return new RegExp('(\\s|^)' + className + '(\\s|$)').test(element.className); return new RegExp('(\\s|^)' + className + '(\\s|$)').test(element.className);
} }
} }
@ -564,8 +556,7 @@
if (source[property] && source[property].constructor && source[property].constructor === Object) { if (source[property] && source[property].constructor && source[property].constructor === Object) {
destination[property] = destination[property] || {}; destination[property] = destination[property] || {};
_extend(destination[property], source[property]); _extend(destination[property], source[property]);
} } else {
else {
destination[property] = source[property]; destination[property] = source[property];
} }
} }
@ -616,13 +607,12 @@
element: null, element: null,
prefix: '' prefix: ''
}, },
browserPrefixes = 'webkit o ms khtml'.split(' '); browserPrefixes = 'webkit o moz ms khtml'.split(' ');
// Check for native support // Check for native support
if (!_is.undefined(document.cancelFullScreen)) { if (!_is.undefined(document.cancelFullScreen)) {
fullscreen.supportsFullScreen = true; fullscreen.supportsFullScreen = true;
} } else {
else {
// Check for fullscreen support by vendor prefix // Check for fullscreen support by vendor prefix
for (var i = 0, il = browserPrefixes.length; i < il; i++ ) { for (var i = 0, il = browserPrefixes.length; i < il; i++ ) {
fullscreen.prefix = browserPrefixes[i]; fullscreen.prefix = browserPrefixes[i];
@ -630,9 +620,8 @@
if (!_is.undefined(document[fullscreen.prefix + 'CancelFullScreen'])) { if (!_is.undefined(document[fullscreen.prefix + 'CancelFullScreen'])) {
fullscreen.supportsFullScreen = true; fullscreen.supportsFullScreen = true;
break; break;
} } else if (!_is.undefined(document.msExitFullscreen) && document.msFullscreenEnabled) {
// Special case for MS (when isn't it?) // Special case for MS (when isn't it?)
else if (!_is.undefined(document.msExitFullscreen) && document.msFullscreenEnabled) {
fullscreen.prefix = 'ms'; fullscreen.prefix = 'ms';
fullscreen.supportsFullScreen = true; fullscreen.supportsFullScreen = true;
break; break;
@ -653,6 +642,8 @@
switch (this.prefix) { switch (this.prefix) {
case '': case '':
return document.fullscreenElement === element; return document.fullscreenElement === element;
case 'moz':
return document.mozFullScreenElement === element;
default: default:
return document[this.prefix + 'FullscreenElement'] === element; return document[this.prefix + 'FullscreenElement'] === element;
} }
@ -916,8 +907,7 @@
// Add styling hook // Add styling hook
_toggleClass(plyr.container, config.classes.fullscreen.enabled, true); _toggleClass(plyr.container, config.classes.fullscreen.enabled, true);
} } else {
else {
_log('Fullscreen not supported and fallback disabled'); _log('Fullscreen not supported and fallback disabled');
} }
@ -968,17 +958,14 @@
if (captionSrc === '') { if (captionSrc === '') {
plyr.captionExists = false; plyr.captionExists = false;
_log('No caption track found'); _log('No caption track found');
} } else {
else {
_log('Caption track found; URI: ' + captionSrc); _log('Caption track found; URI: ' + captionSrc);
} }
// If no caption file exists, hide container for caption text // If no caption file exists, hide container for caption text
if (!plyr.captionExists) { if (!plyr.captionExists) {
_toggleClass(plyr.container, config.classes.captions.enabled); _toggleClass(plyr.container, config.classes.captions.enabled);
} } else {
// If caption file exists, process captions
else {
// Turn off native caption rendering to avoid double captions // Turn off native caption rendering to avoid double captions
// This doesn't seem to work in Safari 7+, so the <track> elements are removed from the dom below // This doesn't seem to work in Safari 7+, so the <track> elements are removed from the dom below
var tracks = plyr.media.textTracks; var tracks = plyr.media.textTracks;
@ -1014,16 +1001,14 @@
// Display a cue, if there is one // Display a cue, if there is one
if (this.activeCues[0] && 'text' in this.activeCues[0]) { if (this.activeCues[0] && 'text' in this.activeCues[0]) {
_setCaption(this.activeCues[0].getCueAsHTML()); _setCaption(this.activeCues[0].getCueAsHTML());
} } else {
else {
_setCaption(); _setCaption();
} }
}); });
} }
} }
} } else {
// Caption tracks not natively supported // Caption tracks not natively supported
else {
_log('TextTracks not supported so rendering captions manually'); _log('TextTracks not supported so rendering captions manually');
// Render captions from array at appropriate time // Render captions from array at appropriate time
@ -1041,14 +1026,25 @@
caption, caption,
req = xhr.responseText; req = xhr.responseText;
captions = req.split('\n\n'); //According to webvtt spec, line terminator consists of one of the following
// CRLF (U+000D U+000A), LF (U+000A) or CR (U+000D)
var lineSeparator = '\r\n';
if(req.indexOf(lineSeparator+lineSeparator) === -1) {
if(req.indexOf('\r\r') !== -1){
lineSeparator = '\r';
} else {
lineSeparator = '\n';
}
}
captions = req.split(lineSeparator+lineSeparator);
for (var r = 0; r < captions.length; r++) { for (var r = 0; r < captions.length; r++) {
caption = captions[r]; caption = captions[r];
plyr.captions[r] = []; plyr.captions[r] = [];
// Get the parts of the captions // Get the parts of the captions
var parts = caption.split('\n'), var parts = caption.split(lineSeparator),
index = 0; index = 0;
// Incase caption numbers are added // Incase caption numbers are added
@ -1063,8 +1059,7 @@
plyr.captions.shift(); plyr.captions.shift();
_log('Successfully loaded the caption file via AJAX'); _log('Successfully loaded the caption file via AJAX');
} } else {
else {
_warn(config.logPrefix + 'There was a problem loading the caption file via AJAX'); _warn(config.logPrefix + 'There was a problem loading the caption file via AJAX');
} }
} }
@ -1095,8 +1090,7 @@
// Set the span content // Set the span content
if (_is.string(caption)) { if (_is.string(caption)) {
content.innerHTML = caption.trim(); content.innerHTML = caption.trim();
} } else {
else {
content.appendChild(caption); content.appendChild(caption);
} }
@ -1130,8 +1124,7 @@
function _subTcSecs(tc) { function _subTcSecs(tc) {
if (tc === null || tc === undefined) { if (tc === null || tc === undefined) {
return 0; return 0;
} } else {
else {
var tc1 = [], var tc1 = [],
tc2 = [], tc2 = [],
seconds; seconds;
@ -1175,8 +1168,7 @@
// Render the caption // Render the caption
_setCaption(plyr.currentCaption); _setCaption(plyr.currentCaption);
} } else {
else {
_setCaption(); _setCaption();
} }
} }
@ -1233,13 +1225,12 @@
function _checkFocus(event) { function _checkFocus(event) {
// If it is TAB // If it is TAB
if (event.which === 9 && plyr.isFullscreen) { if (event.which === 9 && plyr.isFullscreen) {
// Move focus to first element that can be tabbed if Shift isn't used
if (event.target === last && !event.shiftKey) { if (event.target === last && !event.shiftKey) {
// Move focus to first element that can be tabbed if Shift isn't used
event.preventDefault(); event.preventDefault();
first.focus(); first.focus();
} } else if (event.target === first && event.shiftKey) {
// Move focus to last element that can be tabbed if Shift is used // Move focus to last element that can be tabbed if Shift is used
else if (event.target === first && event.shiftKey) {
event.preventDefault(); event.preventDefault();
last.focus(); last.focus();
} }
@ -1254,8 +1245,7 @@
function _insertChildElements(type, attributes) { function _insertChildElements(type, attributes) {
if (_is.string(attributes)) { if (_is.string(attributes)) {
_insertElement(type, plyr.media, { src: attributes }); _insertElement(type, plyr.media, { src: attributes });
} } else if (attributes.constructor === Array) {
else if (attributes.constructor === Array) {
for (var i = attributes.length - 1; i >= 0; i--) { for (var i = attributes.length - 1; i >= 0; i--) {
_insertElement(type, plyr.media, attributes[i]); _insertElement(type, plyr.media, attributes[i]);
} }
@ -1272,8 +1262,7 @@
if (iconUrl.absolute) { if (iconUrl.absolute) {
_log('AJAX loading absolute SVG sprite' + (plyr.browser.isIE ? ' (due to IE)' : '')); _log('AJAX loading absolute SVG sprite' + (plyr.browser.isIE ? ' (due to IE)' : ''));
loadSprite(iconUrl.url, "sprite-plyr"); loadSprite(iconUrl.url, "sprite-plyr");
} } else {
else {
_log('Sprite will be used as external resource directly'); _log('Sprite will be used as external resource directly');
} }
} }
@ -1389,8 +1378,7 @@
function _toggleNativeControls(toggle) { function _toggleNativeControls(toggle) {
if (toggle && _inArray(config.types.html5, plyr.type)) { if (toggle && _inArray(config.types.html5, plyr.type)) {
plyr.media.setAttribute('controls', ''); plyr.media.setAttribute('controls', '');
} } else {
else {
plyr.media.removeAttribute('controls'); plyr.media.removeAttribute('controls');
} }
} }
@ -1442,14 +1430,12 @@
if (!value) { if (!value) {
// Key wasn't set (or had been cleared), move along // Key wasn't set (or had been cleared), move along
return; return;
} } else if (/^\d+(\.\d+)?$/.test(value)) {
else if (/^\d+(\.\d+)?$/.test(value)) {
// If value is a number, it's probably volume from an older // If value is a number, it's probably volume from an older
// version of plyr. See: https://github.com/Selz/plyr/pull/313 // version of plyr. See: https://github.com/Selz/plyr/pull/313
// Update the key to be JSON // Update the key to be JSON
_updateStorage({volume: parseFloat(value)}); _updateStorage({volume: parseFloat(value)});
} } else {
else {
// Assume it's JSON from this or a later version of plyr // Assume it's JSON from this or a later version of plyr
plyr.storage = JSON.parse(value); plyr.storage = JSON.parse(value);
} }
@ -1532,7 +1518,6 @@
_toggleClass(plyr.media, config.classes.videoWrapper, true); _toggleClass(plyr.media, config.classes.videoWrapper, true);
_toggleClass(plyr.media, config.classes.embedWrapper, true); _toggleClass(plyr.media, config.classes.embedWrapper, true);
// YouTube
if (plyr.type === 'youtube') { if (plyr.type === 'youtube') {
// Create the YouTube container // Create the YouTube container
plyr.media.appendChild(container); plyr.media.appendChild(container);
@ -1543,8 +1528,7 @@
// Setup API // Setup API
if (_is.object(window.YT)) { if (_is.object(window.YT)) {
_youTubeReady(mediaId, container); _youTubeReady(mediaId, container);
} } else {
else {
// Load the API // Load the API
_injectScript(config.urls.youtube.api); _injectScript(config.urls.youtube.api);
@ -1559,14 +1543,11 @@
window.onYouTubeReadyCallbacks.forEach(function(callback) { callback(); }); window.onYouTubeReadyCallbacks.forEach(function(callback) { callback(); });
}; };
} }
} } else if (plyr.type === 'vimeo') {
// Vimeo
else if (plyr.type === 'vimeo') {
// Vimeo needs an extra div to hide controls on desktop (which has full support) // Vimeo needs an extra div to hide controls on desktop (which has full support)
if (plyr.supported.full) { if (plyr.supported.full) {
plyr.media.appendChild(container); plyr.media.appendChild(container);
} } else {
else {
container = plyr.media; container = plyr.media;
} }
@ -1584,14 +1565,11 @@
_vimeoReady(mediaId, container); _vimeoReady(mediaId, container);
} }
}, 50); }, 50);
} } else {
else {
_vimeoReady(mediaId, container); _vimeoReady(mediaId, container);
} }
} } else if (plyr.type === 'soundcloud') {
// Soundcloud
// TODO: Currently unsupported and undocumented // TODO: Currently unsupported and undocumented
else if (plyr.type === 'soundcloud') {
// Inject the iframe // Inject the iframe
var soundCloud = document.createElement('iframe'); var soundCloud = document.createElement('iframe');
@ -1779,8 +1757,8 @@
function _vimeoReady(mediaId, container) { function _vimeoReady(mediaId, container) {
// Setup instance // Setup instance
// https://github.com/vimeo/player.js // https://github.com/vimeo/player.js
plyr.embed = new window.Vimeo.Player(container.id, { plyr.embed = new window.Vimeo.Player(container, {
id: mediaId, id: parseInt(mediaId),
loop: config.loop, loop: config.loop,
autoplay: config.autoplay, autoplay: config.autoplay,
byline: false, byline: false,
@ -1830,7 +1808,7 @@
plyr.embed.on('loaded', function() { plyr.embed.on('loaded', function() {
// Fix keyboard focus issues // Fix keyboard focus issues
// https://github.com/Selz/plyr/issues/317 // https://github.com/Selz/plyr/issues/317
if(_is.htmlElement(plyr.embed.element) && plyr.supported.full) { if (_is.htmlElement(plyr.embed.element) && plyr.supported.full) {
plyr.embed.element.setAttribute('tabindex', '-1'); plyr.embed.element.setAttribute('tabindex', '-1');
} }
}); });
@ -1962,12 +1940,9 @@
toggle = plyr.media.paused; toggle = plyr.media.paused;
} }
// Play
if (toggle) { if (toggle) {
_play(); _play();
} } else {
// Pause
else {
_pause(); _pause();
} }
@ -1999,12 +1974,9 @@
paused = plyr.media.paused, paused = plyr.media.paused,
duration = _getDuration(); duration = _getDuration();
// Explicit position
if (_is.number(input)) { if (_is.number(input)) {
targetTime = input; targetTime = input;
} } else if (_is.object(input) && _inArray(['input', 'change'], input.type)) {
// Event
else if (_is.object(input) && _inArray(['input', 'change'], input.type)) {
// It's the seek slider // It's the seek slider
// Seek to the selected time // Seek to the selected time
targetTime = ((input.target.value / input.target.max) * duration); targetTime = ((input.target.value / input.target.max) * duration);
@ -2013,8 +1985,7 @@
// Normalise targetTime // Normalise targetTime
if (targetTime < 0) { if (targetTime < 0) {
targetTime = 0; targetTime = 0;
} } else if (targetTime > duration) {
else if (targetTime > duration) {
targetTime = duration; targetTime = duration;
} }
@ -2073,7 +2044,7 @@
mediaDuration = 0; mediaDuration = 0;
// Only if duration available // Only if duration available
if(plyr.media.duration !== null && !isNaN(plyr.media.duration)) { if (plyr.media.duration !== null && !isNaN(plyr.media.duration)) {
mediaDuration = plyr.media.duration; mediaDuration = plyr.media.duration;
} }
@ -2112,19 +2083,16 @@
// If it's a fullscreen change event, update the UI // If it's a fullscreen change event, update the UI
if (event && event.type === fullscreen.fullScreenEventName) { if (event && event.type === fullscreen.fullScreenEventName) {
plyr.isFullscreen = fullscreen.isFullScreen(plyr.container); plyr.isFullscreen = fullscreen.isFullScreen(plyr.container);
} } else {
// Else it's a user request to enter or exit // Else it's a user request to enter or exit
else {
// Request fullscreen
if (!fullscreen.isFullScreen(plyr.container)) { if (!fullscreen.isFullScreen(plyr.container)) {
// Save scroll position // Save scroll position
_saveScrollPosition(); _saveScrollPosition();
// Request full screen // Request full screen
fullscreen.requestFullScreen(plyr.container); fullscreen.requestFullScreen(plyr.container);
} } else {
// Bail from fullscreen // Bail from fullscreen
else {
fullscreen.cancelFullScreen(); fullscreen.cancelFullScreen();
} }
@ -2133,8 +2101,7 @@
return; return;
} }
} } else {
else {
// Otherwise, it's a simple toggle // Otherwise, it's a simple toggle
plyr.isFullscreen = !plyr.isFullscreen; plyr.isFullscreen = !plyr.isFullscreen;
@ -2249,7 +2216,9 @@
} }
// Toggle muted state // Toggle muted state
if (plyr.media.muted && volume > 0) { if (volume === 0) {
plyr.media.muted = true;
} else if (plyr.media.muted && volume > 0) {
_toggleMute(); _toggleMute();
} }
} }
@ -2383,12 +2352,11 @@
value = (function() { value = (function() {
var buffered = plyr.media.buffered; var buffered = plyr.media.buffered;
// HTML5
if (buffered && buffered.length) { if (buffered && buffered.length) {
// HTML5
return _getPercentage(buffered.end(0), duration); return _getPercentage(buffered.end(0), duration);
} } else if (_is.number(buffered)) {
// YouTube returns between 0 and 1 // YouTube returns between 0 and 1
else if (_is.number(buffered)) {
return (buffered * 100); return (buffered * 100);
} }
@ -2417,8 +2385,7 @@
if (_is.undefined(progress)) { if (_is.undefined(progress)) {
if (plyr.progress && plyr.progress.buffer) { if (plyr.progress && plyr.progress.buffer) {
progress = plyr.progress.buffer; progress = plyr.progress.buffer;
} } else {
else {
return; return;
} }
} }
@ -2426,9 +2393,8 @@
// One progress element passed // One progress element passed
if (_is.htmlElement(progress)) { if (_is.htmlElement(progress)) {
progress.value = value; progress.value = value;
} } else if (progress) {
// Object of progress + text element // Object of progress + text element
else if (progress) {
if (progress.bar) { if (progress.bar) {
progress.bar.value = value; progress.bar.value = value;
} }
@ -2541,20 +2507,17 @@
if (!event) { if (!event) {
if (_hasClass(plyr.progress.tooltip, visible)) { if (_hasClass(plyr.progress.tooltip, visible)) {
percent = plyr.progress.tooltip.style.left.replace('%', ''); percent = plyr.progress.tooltip.style.left.replace('%', '');
} } else {
else {
return; return;
} }
} } else {
else {
percent = ((100 / clientRect.width) * (event.pageX - clientRect.left)); percent = ((100 / clientRect.width) * (event.pageX - clientRect.left));
} }
// Set bounds // Set bounds
if (percent < 0) { if (percent < 0) {
percent = 0; percent = 0;
} } else if (percent > 100) {
else if (percent > 100) {
percent = 100; percent = 100;
} }
@ -2601,8 +2564,7 @@
if (toggle.type === 'focus') { if (toggle.type === 'focus') {
delay = 3000; delay = 3000;
} }
} } else {
else {
show = _hasClass(plyr.container, config.classes.hideControls); show = _hasClass(plyr.container, config.classes.hideControls);
} }
} }
@ -2840,8 +2802,7 @@
// Get the last play button to account for the large play button // Get the last play button to account for the large play button
if (target && target.length > 1) { if (target && target.length > 1) {
target = target[target.length - 1]; target = target[target.length - 1];
} } else {
else {
target = target[0]; target = target[0];
} }
@ -2866,8 +2827,7 @@
if (!focused || focused === document.body) { if (!focused || focused === document.body) {
focused = null; focused = null;
} } else {
else {
focused = document.querySelector(':focus'); focused = document.querySelector(':focus');
} }
@ -2888,20 +2848,42 @@
for (var i = 0; i < element.length; i++) { for (var i = 0; i < element.length; i++) {
_toggleClass(element[i], config.classes.tabFocus, (element[i] === focused)); _toggleClass(element[i], config.classes.tabFocus, (element[i] === focused));
} }
} } else {
else {
_toggleClass(element, config.classes.tabFocus, (element === focused)); _toggleClass(element, config.classes.tabFocus, (element === focused));
} }
} }
} }
// Keyboard shortcuts // Keyboard shortcuts
if (config.keyboardShorcuts) { if (config.keyboardShorcuts.focused) {
var first = true; var last = null;
_on(plyr.container, 'keydown keyup', function(event) { // Handle global presses
if (config.keyboardShorcuts.global) {
_on(window, 'keydown keyup', function(event) {
var code = getKeyCode(event), var code = getKeyCode(event),
pressed = event.type === 'keydown'; focused = getFocusElement(),
allowed = [48,49,50,51,52,53,54,56,57,75,77,70,67],
count = get().length;
// Only handle global key press if there's only one player
// and the key is in the allowed keys
// and if the focused element is not editable (e.g. text input)
// and any that accept key input http://webaim.org/techniques/keyboard/
if (count === 1 && _inArray(allowed, code) && (!_is.htmlElement(focused) || !_matches(focused, config.selectors.editable))) {
handleKey(event);
}
});
}
// Handle presses on focused
_on(plyr.container, 'keydown keyup', handleKey);
}
function handleKey(event) {
var code = getKeyCode(event),
pressed = event.type === 'keydown',
held = pressed && code === last;
// If the event is bubbled from the media element // If the event is bubbled from the media element
// Firefox doesn't get the keycode for whatever reason // Firefox doesn't get the keycode for whatever reason
@ -2932,6 +2914,7 @@
// If the code is found prevent default (e.g. prevent scrolling for arrows) // If the code is found prevent default (e.g. prevent scrolling for arrows)
if (_inArray(preventDefault, code)) { if (_inArray(preventDefault, code)) {
event.preventDefault(); event.preventDefault();
event.stopPropagation();
} }
switch(code) { switch(code) {
@ -2945,24 +2928,24 @@
case 54: case 54:
case 55: case 55:
case 56: case 56:
case 57: if (first) { seekByKey() } break; case 57: if (!held) { seekByKey(); } break;
// Space and K key // Space and K key
case 32: case 32:
case 75: if (first) { _togglePlay(); } break; case 75: if (!held) { _togglePlay(); } break;
// Arrow up // Arrow up
case 38: _increaseVolume(); break; case 38: _increaseVolume(); break;
// Arrow down // Arrow down
case 40: _decreaseVolume(); break; case 40: _decreaseVolume(); break;
// M key // M key
case 77: if (first) { _toggleMute() } break; case 77: if (!held) { _toggleMute() } break;
// Arrow forward // Arrow forward
case 39: _forward(); break; case 39: _forward(); break;
// Arrow back // Arrow back
case 37: _rewind(); break; case 37: _rewind(); break;
// F key // F key
case 70: if (first) { _toggleFullscreen() } break; case 70: _toggleFullscreen(); break;
// C key // C key
case 67: if (first) { _toggleCaptions() } break; case 67: if (!held) { _toggleCaptions(); } break;
} }
// Escape is handle natively when in full screen // Escape is handle natively when in full screen
@ -2971,13 +2954,11 @@
_toggleFullscreen(); _toggleFullscreen();
} }
// First run completed // Store last code for next cycle
first = false; last = code;
} else {
last = null;
} }
else {
first = true;
}
});
} }
// Focus/tab management // Focus/tab management
@ -3072,8 +3053,7 @@
if (event.deltaY < 0 || event.deltaX > 0) { if (event.deltaY < 0 || event.deltaX > 0) {
if (inverted) { if (inverted) {
_decreaseVolume(step); _decreaseVolume(step);
} } else {
else {
_increaseVolume(step); _increaseVolume(step);
} }
} }
@ -3082,8 +3062,7 @@
if (event.deltaY > 0 || event.deltaX < 0) { if (event.deltaY > 0 || event.deltaX < 0) {
if (inverted) { if (inverted) {
_increaseVolume(step); _increaseVolume(step);
} } else {
else {
_decreaseVolume(step); _decreaseVolume(step);
} }
} }
@ -3104,7 +3083,7 @@
// Handle the media finishing // Handle the media finishing
_on(plyr.media, 'ended', function() { _on(plyr.media, 'ended', function() {
// Show poster on end // Show poster on end
if(plyr.type === 'video' && config.showPosterOnEnd) { if (plyr.type === 'video' && config.showPosterOnEnd) {
// Clear // Clear
if (plyr.type === 'video') { if (plyr.type === 'video') {
_setCaption(); _setCaption();
@ -3152,12 +3131,10 @@
if (plyr.media.paused) { if (plyr.media.paused) {
_play(); _play();
} } else if (plyr.media.ended) {
else if (plyr.media.ended) {
_seek(); _seek();
_play(); _play();
} } else {
else {
_pause(); _pause();
} }
}); });
@ -3305,8 +3282,7 @@
// Clean up // Clean up
media.removeAttribute('data-type'); media.removeAttribute('data-type');
media.removeAttribute('data-video-id'); media.removeAttribute('data-video-id');
} } else {
else {
plyr.type = tagName; plyr.type = tagName;
config.crossorigin = (media.getAttribute('crossorigin') !== null); config.crossorigin = (media.getAttribute('crossorigin') !== null);
config.autoplay = (config.autoplay || (media.getAttribute('autoplay') !== null)); config.autoplay = (config.autoplay || (media.getAttribute('autoplay') !== null));
@ -3418,9 +3394,14 @@
getEmbed: function() { return plyr.embed; }, getEmbed: function() { return plyr.embed; },
getMedia: function() { return plyr.media; }, getMedia: function() { return plyr.media; },
getType: function() { return plyr.type; }, getType: function() { return plyr.type; },
getDuration: _getDuration,
getCurrentTime: function() { return plyr.media.currentTime; },
getVolume: function() { return plyr.media.volume; },
isMuted: function() { return plyr.media.muted; },
isReady: function() { return _hasClass(plyr.container, config.classes.ready); }, isReady: function() { return _hasClass(plyr.container, config.classes.ready); },
isLoading: function() { return _hasClass(plyr.container, config.classes.loading); }, isLoading: function() { return _hasClass(plyr.container, config.classes.loading); },
on: function(event, callback) { _on(plyr.container, event, callback); }, isPaused: function() { return plyr.media.paused; },
on: function(event, callback) { _on(plyr.container, event, callback); return this; },
play: _play, play: _play,
pause: _pause, pause: _pause,
stop: function() { _pause(); _seek(); }, stop: function() { _pause(); _seek(); },
@ -3438,14 +3419,15 @@
toggleControls: _toggleControls, toggleControls: _toggleControls,
isFullscreen: function() { return plyr.isFullscreen || false; }, isFullscreen: function() { return plyr.isFullscreen || false; },
support: function(mimeType) { return _supportMime(plyr, mimeType); }, support: function(mimeType) { return _supportMime(plyr, mimeType); },
destroy: _destroy, destroy: _destroy
getCurrentTime: function() { return media.currentTime; }
}; };
// Everything done // Everything done
function _ready() { function _ready() {
// Ready event // Ready event at end of execution stack
_triggerEvent(plyr.container, 'ready', true); window.setTimeout(function() {
_triggerEvent(plyr.media, 'ready');
}, 0);
// Set class hook on media element // Set class hook on media element
_toggleClass(plyr.media, defaults.classes.setup, true); _toggleClass(plyr.media, defaults.classes.setup, true);
@ -3493,8 +3475,7 @@
// Check for CORS support // Check for CORS support
if ('withCredentials' in x) { if ('withCredentials' in x) {
x.open('GET', url, true); x.open('GET', url, true);
} } else {
else {
return; return;
} }
@ -3553,16 +3534,14 @@
selector = [defaults.selectors.html5, defaults.selectors.embed].join(','); selector = [defaults.selectors.html5, defaults.selectors.embed].join(',');
// Select the elements // Select the elements
// Assume elements is a NodeList by default
if (_is.string(targets)) { if (_is.string(targets)) {
// String selector passed
targets = document.querySelectorAll(targets); targets = document.querySelectorAll(targets);
} } else if (_is.htmlElement(targets)) {
// Single HTMLElement passed // Single HTMLElement passed
else if (_is.htmlElement(targets)) {
targets = [targets]; targets = [targets];
} } else if (!_is.nodeList(targets) && !_is.array(targets) && !_is.string(targets)) {
// No selector passed, possibly options as first argument // No selector passed, possibly options as first argument
else if (!_is.nodeList(targets) && !_is.array(targets) && !_is.string(targets)) {
// If options are the first argument // If options are the first argument
if (_is.undefined(options) && _is.object(targets)) { if (_is.undefined(options) && _is.object(targets)) {
options = targets; options = targets;
@ -3609,9 +3588,8 @@
for (var x = 0; x < children.length; x++) { for (var x = 0; x < children.length; x++) {
add(target, children[x]); add(target, children[x]);
} }
} } else if (_matches(target, selector)) {
// Wrap target if it's a media element // Target is media element
else if (_matches(target, selector)) {
add(target, target); add(target, target);
} }
} }
@ -3652,7 +3630,7 @@
// Listen for events if debugging // Listen for events if debugging
if (config.debug) { if (config.debug) {
var events = config.events.concat(['setup', 'ready', 'statechange', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled']); var events = config.events.concat(['setup', 'statechange', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled']);
_on(instance.getContainer(), events.join(' '), function(event) { _on(instance.getContainer(), events.join(' '), function(event) {
console.log([config.logPrefix, 'event:', event.type].join(' '), event.detail.plyr); console.log([config.logPrefix, 'event:', event.type].join(' '), event.detail.plyr);
@ -3673,12 +3651,11 @@
// Get all instances within a provided container // Get all instances within a provided container
function get(container) { function get(container) {
// Get selector if string passed
if (_is.string(container)) { if (_is.string(container)) {
// Get selector if string passed
container = document.querySelector(container); container = document.querySelector(container);
} } else if (_is.undefined(container)) {
// Use body by default to get all on page // Use body by default to get all on page
else if (_is.undefined(container)) {
container = document.body; container = document.body;
} }

View File

@ -173,9 +173,6 @@
position: relative; position: relative;
background: #000; background: #000;
border-radius: inherit; border-radius: inherit;
// Cleaner radius, also forces iframe radius
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
} }
// Container for embeds // Container for embeds
@ -184,6 +181,9 @@
height: 0; height: 0;
overflow: hidden; overflow: hidden;
// Require z-index to force border-radius
z-index: 0;
iframe { iframe {
position: absolute; position: absolute;
top: 0; top: 0;
@ -192,6 +192,7 @@
height: 100%; height: 100%;
border: 0; border: 0;
user-select: none; user-select: none;
z-index: 1;
} }
// Vimeo hack // Vimeo hack
@ -244,12 +245,15 @@
.plyr--captions-active .plyr__captions { .plyr--captions-active .plyr__captions {
display: block; display: block;
} }
.plyr--fullscreen-active .plyr__captions {
font-size: @plyr-font-size-captions-large;
}
.plyr--hide-controls .plyr__captions { .plyr--hide-controls .plyr__captions {
transform: translateY(-(@plyr-control-spacing * 1.5)); transform: translateY(-(@plyr-control-spacing * 1.5));
} }
// Large captions in full screen on larger screens
@media (min-width: @plyr-bp-screen-lg) {
.plyr--fullscreen-active .plyr__captions {
font-size: @plyr-font-size-captions-large;
}
}
// Controls // Controls
// -------------------------------------------------------------- // --------------------------------------------------------------

View File

@ -69,3 +69,4 @@
// Breakpoints // Breakpoints
@plyr-bp-screen-sm: 480px; @plyr-bp-screen-sm: 480px;
@plyr-bp-screen-md: 768px; @plyr-bp-screen-md: 768px;
@plyr-bp-screen-lg: 1024px;

View File

@ -172,9 +172,6 @@
position: relative; position: relative;
background: #000; background: #000;
border-radius: inherit; border-radius: inherit;
// Cleaner radius, also forces iframe radius
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
} }
// Container for embeds // Container for embeds
@ -184,6 +181,9 @@
overflow: hidden; overflow: hidden;
border-radius: inherit; border-radius: inherit;
// Require z-index to force border-radius
z-index: 0;
iframe { iframe {
position: absolute; position: absolute;
top: 0; top: 0;
@ -244,12 +244,15 @@
.plyr--captions-active .plyr__captions { .plyr--captions-active .plyr__captions {
display: block; display: block;
} }
.plyr--fullscreen-active .plyr__captions {
font-size: $plyr-font-size-captions-large;
}
.plyr--hide-controls .plyr__captions { .plyr--hide-controls .plyr__captions {
transform: translateY(-($plyr-control-spacing * 2)); transform: translateY(-($plyr-control-spacing * 2));
} }
// Large captions in full screen on larger screens
@media (min-width: $plyr-bp-screen-lg) {
.plyr--fullscreen-active .plyr__captions {
font-size: $plyr-font-size-captions-large;
}
}
// Controls // Controls
// -------------------------------------------------------------- // --------------------------------------------------------------

View File

@ -70,3 +70,4 @@ $plyr-range-selected-bg: $plyr-color-main !default;
// Breakpoints // Breakpoints
$plyr-bp-screen-sm: 480px !default; $plyr-bp-screen-sm: 480px !default;
$plyr-bp-screen-md: 768px !default; $plyr-bp-screen-md: 768px !default;
$plyr-bp-screen-lg: 1024px !default;