Merge branch 'develop' into feature/subtitles

This commit is contained in:
Sam Potts
2017-03-25 18:43:36 +11:00
committed by GitHub
13 changed files with 274 additions and 130 deletions

View File

@ -1,3 +1,7 @@
<!---
Please use this issue template as it makes replicating and fixing the issue easier!
--->
- [ ] Issue does not already exist
- [ ] Issue observed on https://plyr.io
@ -12,6 +16,12 @@
- Operating System:
- Version:
Players affected:
- [ ] HTML5 Video
- [ ] HTML5 Audio
- [ ] YouTube
- [ ] Vimeo
### Steps to reproduce
-

View File

@ -1,5 +1,13 @@
# Changelog
## v2.0.12
- Ability to set custom `blankUrl` for source changes (https://github.com/Selz/plyr/pull/504)
- Ability to set caption button listener (https://github.com/Selz/plyr/pull/468)
## v2.0.11
- Fix for `cleanUp` being called twice (thanks to @sebastiancarlsson)
- Fix for YouTube controls on iPad (fixes #391)
## v2.0.10
- Added seek event fixes for Vimeo and YouTube (fixes #409)
- Added support for embed URLs rather than ID only (fixes #345)

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;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},controls:["play-large","play","speed-up","progress","current-time","mute","volume","captions","settings","fullscreen"]});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},controls:["play-large","play","progress","current-time","mute","volume","captions","settings","fullscreen"]});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

@ -67,8 +67,8 @@
<ul>
<li class="plyr__cite plyr__cite--video"><small><a href="http://viewfromabluemoon.com/" target="_blank">View From A Blue Moon</a> &copy; Brainfarm</small></li>
<li class="plyr__cite plyr__cite--audio"><small><a href="http://www.kishibashi.com/" target="_blank">Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;</a> &copy; Kishi Bashi</small></li>
<li class="plyr__cite plyr__cite--youtube"><small><a href="https://www.youtube.com/watch?v=bTqVqk7FSmY" target="_blank">View From A Blue Moon</a> on <span class="color--youtube"><svg class="icon"><use xlink:href="#icon-youtube"/></svg>YouTube</span></small>
<li class="plyr__cite plyr__cite--vimeo"><small><a href="https://vimeo.com/ondemand/viewfromabluemoon4k" target="_blank">View From A Blue Moon</a> on <span class="color--vimeo"><svg class="icon"><use xlink:href="#icon-vimeo"/></svg>Vimeo</span></small>
<li class="plyr__cite plyr__cite--youtube"><small><a href="https://www.youtube.com/watch?v=bTqVqk7FSmY" target="_blank">View From A Blue Moon</a> on <span class="color--youtube"><svg class="icon"><use xlink:href="#icon-youtube"/></svg>YouTube</span></small></li>
<li class="plyr__cite plyr__cite--vimeo"><small><a href="https://vimeo.com/ondemand/viewfromabluemoon4k" target="_blank">View From A Blue Moon</a> on <span class="color--vimeo"><svg class="icon"><use xlink:href="#icon-vimeo"/></svg>Vimeo</span></small></li>
</ul>
</section>
</main>

View File

@ -21,7 +21,7 @@
captions: {
defaultActive: true
},
controls: ['play-large', 'play', 'speed-up', 'progress', 'current-time', 'mute', 'volume', 'captions', 'settings', 'fullscreen']
controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'captions', 'settings', 'fullscreen']
});
plyr.loadSprite('dist/demo.svg');

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

4
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,16 @@
### Todo
#### Features
- Get list of subtitles/captions available (HTML5)
- Add preferred quality option
- Update quality options on YouTube play
- Update speed options on YouTube load
- No Vimeo quality support
- No Vimeo or YouTube caption support
- Get quality options for HTML5 somehow (multi source?)
- Get list of subtitles/captions available (HTML5)
- Build templating for controls somehow
- Finish PiP
- Finish AirPlay
#### Bugs
- Fix audio setup bug
- Fix audio setup bug when calling .setup() again

View File

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

View File

@ -1,6 +1,8 @@
# Plyr
A simple, accessible and customizable HTML5, YouTube and Vimeo media player.
[Donate to support Plyr](#donate)
[Checkout the demo](https://plyr.io)
[![Image of Plyr](https://cdn.selz.com/plyr/plyr_v1.8.9.png)](https://plyr.io)
@ -132,10 +134,10 @@ Include the `plyr.js` script before the closing `</body>` tag and then call `ply
<script>plyr.setup();</script>
```
If you want to use our CDN for the JavaScript, you can use the following:
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript, you can use the following:
```html
<script src="https://cdn.plyr.io/2.0.10/plyr.js"></script>
<script src="https://cdn.plyr.io/2.0.12/plyr.js"></script>
```
### CSS
@ -145,14 +147,14 @@ Include the `plyr.css` stylsheet into your `<head>`
<link rel="stylesheet" href="path/to/plyr.css">
```
If you want to use our CDN for the default CSS, you can use the following:
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
```html
<link rel="stylesheet" href="https://cdn.plyr.io/2.0.10/plyr.css">
<link rel="stylesheet" href="https://cdn.plyr.io/2.0.12/plyr.css">
```
### 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.10/plyr.svg`.
The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). 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.12/plyr.svg`.
## Advanced
@ -284,6 +286,12 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke
<td><code>plyr</code></td>
<td>Specify the id prefix for the icons used in the default controls (e.g. "plyr-play" would be "plyr"). This is to prevent clashes if you're using your own SVG sprite but with the default controls. Most people can ignore this option.</td>
</tr>
<tr>
<td><code>blankUrl</code></td>
<td>String</td>
<td><code>https://cdn.selz.com/plyr/blank.mp4</code></td>
<td>Specify a URL or path to a blank video file used to properly cancel network requests. See <a href="https://github.com/Selz/plyr/issues/174">issue #174</a> for more info.</td>
</tr>
<tr>
<td><code>debug</code></td>
<td>Boolean</td>
@ -672,7 +680,12 @@ player.source({
srclang:'en',
src: '/path/to/captions.vtt',
default: true
}]
}],
loopKeyEvents: {
toggleLoop: 76,
loopin: 73,
loopout: 79
}
});
```
@ -988,6 +1001,21 @@ By default, a player will bind the following keyboard shortcuts when it has focu
<td></td>
<td>Toggle captions</td>
</tr>
<tr>
<td><code>l</code></td>
<td></td>
<td>Toggle Loop All/No Loop</td>
</tr>
<tr>
<td><code>i</code></td>
<td></td>
<td>Set the start marker of the loop</td>
</tr>
<tr>
<td><code>o</code></td>
<td></td>
<td>Set the end marker of the loop</td>
</tr>
</tbody>
</table>
@ -1030,7 +1058,7 @@ Fullscreen in Plyr is supported by all browsers that [currently support it](http
&sup2; Native player used (no support for `<progress>` or `<input type="range">`) but the API is supported (v1.0.28+)
&sup3; IE10 has no native fullscreen support, fallback can be used (see options)
&sup3; IE10 has no native fullscreen support, fallback can be used (see [options](#options))
The `enabled` option can be used to disable certain User Agents. For example, if you don't want to use Plyr for smartphones, you could use:
@ -1050,6 +1078,10 @@ If you find anything weird with Plyr, please let us know using the GitHub issues
## Author
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)
## Donate
Plyr costs money to run, not my time - I donate that for free but domains, hosting and more. Any help is appreciated...
[Donate to support Plyr](https://www.paypal.me/pottsy/20usd)
## Mentions
- [ProductHunt](https://www.producthunt.com/tech/plyr)
- [The Changelog](http://thechangelog.com/plyr-simple-html5-media-player-custom-controls-webvtt-captions/)
@ -1084,5 +1116,10 @@ Also these links helped created Plyr:
- [Media Events - W3.org](http://www.w3.org/2010/05/video/mediaevents.html)
- [Styling the `<progress>` element - hongkiat.com](http://www.hongkiat.com/blog/html5-progress-bar/)
## Thanks
[![Fastly](https://www.fastly.com/sites/all/themes/custom/fastly2016/logo.png)](https://www.fastly.com/)
Thanks to [Fastly](https://www.fastly.com/) for providing the CDN services.
## Copyright and License
[The MIT license](license.md).

View File

@ -37,9 +37,15 @@
enabled: true,
debug: false,
autoplay: false,
loop: false,
loopin: 0,
loopout: null,
loop: {
active: false,
start: 0,
end: null,
indicator: {
start: 0,
end: 0
}
},
seekTime: 10,
volume: 10,
volumeMin: 0,
@ -57,8 +63,10 @@
hideControls: true,
showPosterOnEnd: false,
disableContextMenu: true,
qualityOptions: false,
keyboardShorcuts: {
quality: {
options: false
},
keyboardShortcuts: {
focused: true,
global: false
},
@ -102,7 +110,8 @@
progress: {
container: '.plyr__progress',
buffer: '.plyr__progress--buffer',
played: '.plyr__progress--played'
played: '.plyr__progress--played',
looped: '.plyr__progress-loop'
},
captions: '.plyr__captions',
currentTime: '.plyr__time--current',
@ -175,10 +184,10 @@
speed: 'Speed',
quality: 'Quality',
loop: 'Loop',
loopin: 'Loop in',
loopout: 'Loop out',
loopall: 'Loop all',
loopclear: 'No Loop',
loopStart: 'Loop start',
loopEnd: 'Loop end',
loopAll: 'Loop all',
loopNone: 'No Loop',
},
types: {
embed: ['youtube', 'vimeo', 'soundcloud'],
@ -915,6 +924,7 @@
/* beautify ignore:start */
html.push(
'<span class="plyr__progress">',
'<div class="plyr__progress-loop"></div>',
'<label for="seek-{id}" class="plyr__sr-only">Seek</label>',
'<input id="seek-{id}" class="plyr__progress--seek" type="range" min="0" max="100" step="0.1" value="0" data-plyr="seek">',
'<progress class="plyr__progress--played" max="100" value="0" role="presentation"></progress>',
@ -1033,12 +1043,19 @@
'</button>',
'</li>',
'<li role="tab">',
showQuality,
'<button type="button" class="plyr__control plyr__control--forward" id="plyr-settings-{id}-quality-toggle" aria-haspopup="true" aria-controls="plyr-settings-{id}-quality" aria-expanded="false">',
config.i18n.quality +
'<span class="plyr__menu__value">{quality}</span>'
'</button>',
'</li>',
'<li role="tab">',
'<button type="button" class="plyr__control plyr__control--forward" id="plyr-settings-{id}-loop-toggle" aria-haspopup="true" aria-controls="plyr-settings-{id}-loop" aria-expanded="false">',
config.i18n.loop +
'<span class="plyr__menu__value" data-menu="loop"></span>',
'<span class="plyr__menu__value" data-menu="loop">{loop}</span>',
'</button>',
'</li>',
'</ul>',
@ -1156,26 +1173,26 @@
'</button>',
'</li>',
'<li>',
'<button type="button" class="plyr__control" data-plyr="loop" data-loop__type="loopall">',
config.i18n.loopall,
'<span data-loop__value="loopall"></span>',
'<button type="button" class="plyr__control" data-plyr="loop" data-plyr-loop="all">',
config.i18n.loopAll,
'<span></span>',
'</button>',
'</li>',
'<li>',
'<button type="button" class="plyr__control" data-plyr="loop" data-loop__type="loopin">',
config.i18n.loopin + ':&nbsp;',
'<span data-loop__value="loopin"></span>',
'<button type="button" class="plyr__control" data-plyr="loop" data-plyr-loop="start">',
config.i18n.loopStart,
'<span></span>',
'</button>',
'</li>',
'<li>',
'<button type="button" class="plyr__control" data-plyr="loop" data-loop__type="loopout">',
config.i18n.loopout + ':&nbsp;',
'<span data-loop__value="loopout"></span>',
'<button type="button" class="plyr__control" data-plyr="loop" data-plyr-loop="end">',
config.i18n.loopEnd,
'<span></span>',
'</button>',
'</li>',
'<li>',
'<button type="button" class="plyr__control" data-plyr="loop" data-loop__type="loopclear">',
config.i18n.loopclear,
'<button type="button" class="plyr__control" data-plyr="loop" data-plyr-loop="none">',
config.i18n.loopNone,
'</button>',
'</li>',
'</ul>',
@ -1794,9 +1811,9 @@
fullscreen: getElement(config.selectors.buttons.fullscreen),
settings: getElement(config.selectors.buttons.settings),
pip: getElement(config.selectors.buttons.pip),
speed: document.querySelectorAll(config.selectors.buttons.speed),
loop: document.querySelectorAll(config.selectors.buttons.loop),
captions_lang: getElements(config.selectors.buttons.captions_lang)
lang: getElement(config.selectors.buttons.captions_lang),
speed: getElement(config.selectors.buttons.speed),
loop: getElement(config.selectors.buttons.loop)
};
// Inputs
@ -2296,7 +2313,7 @@
// https://github.com/vimeo/player.js
plyr.embed = new window.Vimeo.Player(container, {
id: parseInt(mediaId),
loop: config.loop,
loop: config.loop.active,
autoplay: config.autoplay,
byline: false,
portrait: false,
@ -2493,46 +2510,82 @@
}
// Toggle loop
function toggleLoop(toggle) {
if (['loopin', 'loopout', 'loopall'].indexOf(toggle) === -1) {
toggle = 'loopclear';
// TODO: Set the indicator on load as user may pass loop as config
function toggleLoop(type) {
// Set default to be a true toggle
if (!inArray(['start', 'end', 'all', 'none', 'toggle'], type)) {
type = 'toggle';
}
var currentTime = Number(plyr.media.currentTime);
switch (toggle) {
case 'loopin':
if (config.loopout && config.loopout <= currentTime) {
config.loopout = null;
switch (type) {
case 'start':
if (config.loop.end && config.loop.end <= currentTime) {
config.loop.end = null;
}
config.loopin = currentTime;
config.loop.start = currentTime;
config.loop.indicator.start = plyr.progress.played.value;
break;
case 'loopout':
if (config.loopin >= currentTime) {
case 'end':
if (config.loop.start >= currentTime) {
return;
}
config.loopout = currentTime;
config.loop.end = currentTime;
config.loop.indicator.end = plyr.progress.played.value;
break;
case 'loopall':
config.loopin = 0;
config.loopout = plyr.media.duration - 2;
break;
default:
config.loopin = 0;
config.loopout = null;
break;
}
//check if can loop
config.loop = is.number(config.loopin) && is.number(config.loopout);
var loopin = updateTimeDisplay(config.loopin, document.querySelector('[data-loop__value="loopin"]'));
var loopout = is.number(config.loopout) ? updateTimeDisplay(config.loopout + 2, document.querySelector('[data-loop__value="loopout"]')) : document.querySelector('[data-loop__value="loopout"]').innerHTML = '';
if (config.loop) {
document.querySelector('[data-menu="loop"]').innerHTML = loopin + ' - ' + loopout;
case 'all':
config.loop.start = 0;
config.loop.end = plyr.media.duration - 2;
config.loop.indicator.start = 0;
config.loop.indicator.end = 100;
break;
case 'toggle':
if (config.loop.active) {
config.loop.start = 0;
config.loop.end = null;
} else {
document.querySelector('[data-menu="loop"]').innerHTML = config.i18n.loopclear;
config.loop.start = 0;
config.loop.end = plyr.media.duration - 2;
}
break;
default:
config.loop.start = 0;
config.loop.end = null;
break;
}
// Check if can loop
config.loop.active = is.number(config.loop.start) && is.number(config.loop.end);
var start = updateTimeDisplay(config.loop.start, getElement('[data-plyr-loop="start"]'));
var end = null;
if (is.number(config.loop.end)) {
// Find the <span> inside button
end = updateTimeDisplay(config.loop.end, document.querySelector('[data-loop__value="loopout"]'));
} else {
// Find the <span> inside button
//end = document.querySelector('[data-loop__value="loopout"]').innerHTML = '';
}
if (config.loop.active) {
// TODO: Improve the design of the loop indicator and put styling in CSS where it's meant to be
//getElement('[data-menu="loop"]').innerHTML = start + ' - ' + end;
//getElement(config.selectors.progress.looped).style.position = 'absolute';
//getElement(config.selectors.progress.looped).style.left = config.loopinPositionPercentage + '%';
//getElement(config.selectors.progress.looped).style.width = (config.loopoutPositionPercentage - config.loopinPositionPercentage) + '%';
//getElement(config.selectors.progress.looped).style.background = '#ffbb00';
//getElement(config.selectors.progress.looped).style.height = '3px';
//getElement(config.selectors.progress.looped).style.top = '3px';
//getElement(config.selectors.progress.looped).style['border-radius'] = '100px';
} else {
//getElement('[data-menu="loop"]').innerHTML = config.i18n.loopNone;
//getElement(config.selectors.progress.looped).style.width = '0px';
}
}
// Speed-up
@ -2546,6 +2599,7 @@
warn('Invalid speeds format');
return;
}
if (!is.number(speed)) {
var index = config.speeds.indexOf(config.currentSpeed);
@ -3026,8 +3080,8 @@
}
}
if (is.number(config.loopin) && is.number(config.loopout) && plyr.media.currentTime >= config.loopout) {
seek(config.loopin);
if (is.number(config.loop.start) && is.number(config.loop.end) && plyr.media.currentTime >= config.loop.end) {
seek(config.loop.start);
}
setProgress(progress, value);
@ -3089,10 +3143,14 @@
plyr.secs = ('0' + plyr.secs).slice(-2);
plyr.mins = ('0' + plyr.mins).slice(-2);
var txt = (displayHours ? plyr.hours + ':' : '') + plyr.mins + ':' + plyr.secs;
// Generate display
var display = (displayHours ? plyr.hours + ':' : '') + plyr.mins + ':' + plyr.secs;
// Render
element.innerHTML = txt;
return txt;
element.innerHTML = display;
// Return for looping
return display;
}
// Show the duration on metadataloaded
@ -3395,7 +3453,7 @@
if ('poster' in source) {
plyr.media.setAttribute('poster', source.poster);
}
if (config.loop) {
if (config.loop.active) {
plyr.media.setAttribute('loop', '');
}
}
@ -3519,16 +3577,16 @@
}
// Keyboard shortcuts
if (config.keyboardShorcuts.focused) {
if (config.keyboardShortcuts.focused) {
var last = null;
// Handle global presses
if (config.keyboardShorcuts.global) {
if (config.keyboardShortcuts.global) {
on(window, 'keydown keyup', function(event) {
var code = getKeyCode(event),
focused = getFocusElement(),
allowed = [48, 49, 50, 51, 52, 53, 54, 56, 57, 75, 77, 70, 67],
count = get().length;
var code = getKeyCode(event);
var focused = getFocusElement();
var allowed = [48, 49, 50, 51, 52, 53, 54, 56, 57, 75, 77, 70, 67, 73, 76, 79];
var count = get().length;
// Only handle global key press if there's only one player
// and the key is in the allowed keys
@ -3545,9 +3603,9 @@
}
function handleKey(event) {
var code = getKeyCode(event),
pressed = event.type === 'keydown',
held = pressed && code === last;
var code = getKeyCode(event);
var pressed = event.type === 'keydown';
var held = pressed && code === last;
// If the event is bubbled from the media element
// Firefox doesn't get the keycode for whatever reason
@ -3573,7 +3631,7 @@
// Reset on keyup
if (pressed) {
// Which keycodes should we prevent default
var preventDefault = [48, 49, 50, 51, 52, 53, 54, 56, 57, 32, 75, 38, 40, 77, 39, 37, 70, 67];
var preventDefault = [48, 49, 50, 51, 52, 53, 54, 56, 57, 32, 75, 38, 40, 77, 39, 37, 70, 67, 73, 76, 79];
var checkFocus = [38, 40];
if (inArray(checkFocus, code)) {
@ -3628,7 +3686,7 @@
case 77:
// M key
if (!held) {
toggleMute()
toggleMute();
}
break;
@ -3653,6 +3711,18 @@
toggleCaptions();
}
break;
case 73:
toggleLoop('start');
break;
case 76:
toggleLoop();
break;
case 79:
toggleLoop('end');
break;
}
// Escape is handle natively when in full screen
@ -3723,11 +3793,12 @@
// Fullscreen
proxy(plyr.buttons.fullscreen, 'click', config.listeners.fullscreen, toggleFullscreen);
// Loop
// Looping
proxy(plyr.buttons.loop, 'click', config.listeners.loop, function(event) {
var loopValue = event.target.getAttribute('data-loop__value') || event.target.getAttribute('data-loop__type');
if (['loopin', 'loopout', 'loopall', 'loopclear'].indexOf(loopValue) > -1) {
toggleLoop(loopValue);
var value = event.target.getAttribute('data-loop__value') || event.target.getAttribute('data-loop__type');
if (inArray(['start', 'end', 'all', 'none'], value)) {
toggleLoop(value);
}
});
@ -3737,10 +3808,10 @@
}
// Captions
on(plyr.buttons.captions, 'click', toggleCaptions);
on(plyr.buttons.captions_menu, 'click', toggleCaptions);
// Captions language
proxy(plyr.buttons.captions_lang, 'click', config.listeners.captions_lang, function(e) {
proxy(plyr.buttons.captions, 'click', config.listeners.captions toggleCaptions);
// ?? on(plyr.buttons.captions_menu, 'click', toggleCaptions);
// Language
proxy(plyr.buttons.lang, 'click', config.listeners.lang, function(e) {
var langIndex = e.target.attributes.getNamedItem("data-index").value;
setCaptionIndex(langIndex);
});
@ -4226,7 +4297,7 @@
return plyr.media.paused;
},
isLooping: function() {
return config.loopin && config.loopout;
return config.loop.active;
},
on: function(event, callback) {
on(plyr.container, event, callback);

View File

@ -198,7 +198,11 @@
.plyr__video-embed {
padding-bottom: 56.25%; /* 16:9 */
height: 0;
border-radius: inherit;
// Require overflow and z-index to force border-radius
overflow: hidden;
z-index: 0;
iframe {
position: absolute;
@ -208,7 +212,6 @@
height: 100%;
border: 0;
user-select: none;
z-index: 1;
}
// Vimeo hack
@ -291,16 +294,14 @@
.plyr__menu {
margin-left: (@plyr-control-spacing / 2);
&:first-child {
&:first-child,
&:first-child + [data-plyr="pause"] {
margin-left: 0;
}
}
.plyr__volume {
margin-left: (@plyr-control-spacing / 2);
}
[data-plyr="pause"] {
margin-left: 0;
}
@media (min-width: @plyr-bp-screen-sm) {
> .plyr__control,
@ -343,6 +344,7 @@
height: @plyr-control-icon-size;
display: block;
fill: currentColor;
pointer-events: none;
}
// Hide toggle icons by default
.icon--exit-fullscreen,
@ -363,6 +365,7 @@
left: 0;
right: 0;
bottom: 0;
z-index: 2;
padding: (@plyr-control-spacing * 5) @plyr-control-spacing @plyr-control-spacing;
background: linear-gradient(fade(@plyr-video-controls-bg, 0%), fade(@plyr-video-controls-bg, 70%));
border-bottom-left-radius: inherit;
@ -423,6 +426,7 @@
height: 20px;
display: block;
fill: currentColor;
pointer-events: none;
}
&:focus {
@ -921,6 +925,10 @@
height: 100%;
width: 100%;
}
.plyr__video-embed {
// Revert overflow change
overflow: visible;
}
.plyr__controls {
position: absolute;
bottom: 0;

View File

@ -181,9 +181,12 @@
.plyr__video-embed {
padding-bottom: 56.25%; /* 16:9 */
height: 0;
overflow: hidden;
border-radius: inherit;
// Require overflow and z-index to force border-radius
overflow: hidden;
z-index: 0;
iframe {
position: absolute;
top: 0;
@ -269,21 +272,20 @@
text-align: center;
// Spacing
> button,
> .plyr__control,
.plyr__progress,
.plyr__time {
.plyr__time,
.plyr__menu {
margin-left: ($plyr-control-spacing / 2);
&:first-child {
&:first-child,
&:first-child + [data-plyr="pause"] {
margin-left: 0;
}
}
.plyr__volume {
margin-left: ($plyr-control-spacing / 2);
}
[data-plyr="pause"] {
margin-left: 0;
}
// Buttons
button {
@ -305,6 +307,7 @@
height: $plyr-control-icon-size;
display: block;
fill: currentColor;
pointer-events: none;
}
// Default focus
@ -398,6 +401,7 @@
height: 20px;
display: block;
fill: currentColor;
pointer-events: none;
}
&:focus {
@ -740,6 +744,10 @@
height: 100%;
width: 100%;
}
.plyr__video-embed {
// Revert overflow change
overflow: visible;
}
.plyr__controls {
position: absolute;
bottom: 0;