Compare commits

...

63 Commits

Author SHA1 Message Date
df7f52d885 Added ‘global’ keyboard shortcut option 2016-08-22 14:15:49 +10:00
d5b5faafbb Version bump for NPM 2016-08-22 13:08:19 +10:00
a318e8588b Merge branch 'master' of https://github.com/Selz/plyr 2016-08-22 13:07:07 +10:00
51fb252cd8 Update changelog.md 2016-08-22 13:06:26 +10:00
86b2f61b56 Bump to v2.0.0 2016-08-22 13:00:47 +10:00
232a9fe868 Update changelog.md 2016-08-22 12:53:38 +10:00
e8bfe73b1d Update readme.md 2016-08-22 08:40:02 +10:00
ab0d762675 Update readme.md 2016-08-21 22:46:11 +10:00
a6a314e011 Update readme.md 2016-08-21 21:53:16 +10:00
514bdff92e Update readme.md 2016-08-21 21:53:02 +10:00
745e56a3a3 Update readme.md 2016-08-21 21:40:24 +10:00
130fb78b4c Version bump 2016-08-21 19:47:13 +10:00
3718ec69ba Use minified 2016-08-21 19:45:45 +10:00
4610f4a8c9 Firefox and Edge fixes 2016-08-21 19:44:46 +10:00
a8062354ec Loading tweaks, Microsoft Edge tweaks 2016-08-21 19:25:21 +10:00
Sam
aac0a5a3a9 Work on docs 2016-08-21 10:30:11 +10:00
Sam
92b9e3400b Keyboard shortcuts 2016-08-20 23:39:18 +10:00
Sam
bea513f5dd Jshint tweaks, changelog 2016-08-20 20:11:21 +10:00
9d109bf02d Refactoring and bug fixing 2016-08-20 18:02:02 +10:00
fc45ab48c9 Merge branch 'master' into develop
# Conflicts:
#	src/js/plyr.js
2016-08-20 17:46:05 +10:00
58e9b02405 Merge 2016-08-06 11:09:55 +10:00
b578fb4840 Merge branch 'master' of https://github.com/Selz/plyr 2016-08-06 11:08:33 +10:00
f18d9589eb Font stack SASS fix (Fixes #328) 2016-08-06 11:08:28 +10:00
35c6ec9461 Manually merged #313 PR 2016-08-06 11:08:04 +10:00
56d9730d0a Merge pull request #326 from mkaziz/master
Updated define to work with AMD imports
2016-08-06 10:15:53 +10:00
6e18bc8b31 Updated define to work with AMD imports 2016-08-04 02:05:12 -05:00
81756a1af9 Merge pull request #322 from mortonfox/patch-1
Fix the Initialising and Options anchor links
2016-07-30 14:10:34 +10:00
05e1ab1165 Fix the Initialising and Options anchor links 2016-07-30 00:09:39 -04:00
a0ddc5e6eb Merge pull request #321 from electerious/patch-1
Added Array as selector in .setup() to readme
2016-07-25 08:53:29 +10:00
dc40b1f93a Added Array as selector in .setup() to readme
Documentation for #319
2016-07-24 20:52:20 +02:00
d7cc29f2fb Vimeo keyboard focus fix (Fixes #317), Fix for Vimeo on basic support devices 2016-07-23 11:11:17 +10:00
0505e49038 Vimeo API upgrade, YouTube Bugfix, Array support
- Vimeo API upgrade
- Fix for YouTube bug introduced in v1.8.9 (Fixes #320)
- Added support for passing array to .setup() (Fixes #319)
2016-07-23 10:42:06 +10:00
6ff1e47341 Merge branch 'master' of https://github.com/Selz/plyr 2016-07-21 21:59:26 +10:00
e72a91de6e Fix for seek issues introduced in v1.8.9 2016-07-21 21:59:16 +10:00
52ec4c012d Update readme.md 2016-07-21 21:32:56 +10:00
ae89c92ab6 Update readme.md 2016-07-21 21:31:09 +10:00
57ad124ce8 v1.8.9 2016-07-21 21:25:27 +10:00
a85d45d2e5 Fix for fullscreen not being defined (Fixes #295) 2016-07-21 21:21:10 +10:00
a6f57fc034 Fix for multiline captions (Fixes #314) 2016-07-21 21:15:44 +10:00
04c9653b86 Merge branch 'master' of https://github.com/Selz/plyr 2016-07-21 21:14:29 +10:00
b8cdc71001 Clean up of type checks and fix for _restart() (Fixes #315) 2016-07-21 21:14:22 +10:00
277ebf0fd1 Merge pull request #312 from dpschen/patch-1
Add kirby-plyrtag
2016-07-14 22:03:50 +10:00
7682d998e7 Add kirby-plyrtag
Added a Kirby cms kirbytag https://getkirby.com/
2016-07-14 12:52:28 +02:00
05b9b9a831 Fix for MEDIA_ERR_SRC_NOT_SUPPORTED when calling .source() API method 2016-07-14 17:13:37 +10:00
eee699cec6 Version bump 2016-07-10 20:59:42 +10:00
3c9e9862d8 Added getCurrentTime API method (fixes #292) 2016-07-10 20:58:19 +10:00
39dc651a9d Fix for !hideControls on touch devices (fixes #303) 2016-07-10 20:50:55 +10:00
4effda125a Merge branch 'master' of https://github.com/Selz/plyr 2016-07-10 20:45:58 +10:00
bf9de231d8 Styling minor tweaks 2016-07-10 20:45:54 +10:00
ef12332505 Update readme.md 2016-06-29 16:23:38 +10:00
1b735f1727 Update readme.md 2016-06-26 22:21:19 +10:00
7f7ecf852e Line height fix 2016-06-26 09:07:42 +10:00
931672895f Reverted font size change 2016-06-26 09:04:38 +10:00
0952bc8239 Built JS 2016-06-26 08:45:06 +10:00
7e7508ca82 Fixed overflow issues (fixes #286) 2016-06-26 08:34:36 +10:00
095d100ba4 Version bump 2016-06-25 23:47:30 +10:00
c61fad51c1 Fix for z-index on large play button 2016-06-25 23:46:37 +10:00
7b11c6803d Merge pull request #283 from arrowthemes/patch-1
Make the player button clickable on small videos
2016-06-25 17:44:07 +04:00
6425a33ccd Merge pull request #284 from Integer64/develop
fix name svg
2016-06-22 19:10:48 +01:00
12c5dbd290 fix name svg 2016-06-23 01:56:14 +08:00
cb591dac0c Make the player button clickable on small videos
If you set the plyr video to width of 300px, the plyr__controls overlays the play centered play button such that you can't click on the play button. Adding a z-index on the plyr .plyr__play-large fixes that.
2016-06-21 21:59:00 +03:00
24bc415faf Merge pull request #256 from MrSnowflake/develop
In specific cases Plyr fails to initiate YT: YT.Player is not a constructor
2016-05-31 08:26:53 +01:00
152e94f229 Improved YT initialized check.
Added an extra check to see wether YT API has been initialized. The current check is inadequate as YT can be an object while the API still isn't completely initialized.
2016-05-30 00:35:07 +02:00
17 changed files with 1494 additions and 1004 deletions

View File

@ -8,11 +8,11 @@
"node" : false,
"rhino" : false,
"couch" : false,
"wsh" : true, // Windows Scripting Host.
"wsh" : false, // Windows Scripting Host.
"jquery" : false,
// Development.
"debug" : false, // Allow debugger statements e.g. browser breakpoints.
"debug" : true, // Allow debugger statements e.g. browser breakpoints.
"devel" : true, // Allow developments statements e.g. `console.log();`.
// ECMAScript 5.
@ -25,7 +25,7 @@
"bitwise" : false, // Prohibit bitwise operators (&, |, ^, etc.).
"boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments.
"curly" : true, // Require {} for every new block or scope.
"eqeqeq" : false, // Require triple equals i.e. `===`.
"eqeqeq" : true, // Require triple equals i.e. `===`.
"eqnull" : false, // Tolerate use of `== null`.
"evil" : false, // Tolerate use of `eval`.
"expr" : false, // Tolerate `ExpressionStatement` as Programs.

View File

@ -15,7 +15,7 @@
"main": [
"dist/plyr.css",
"dist/plyr.js",
"dist/sprite.svg",
"dist/plyr.svg",
"src/less/plyr.less",
"src/scss/plyr.scss",
"src/js/plyr.js"

View File

@ -1,6 +1,78 @@
# Changelog
# v1.8.3
# v2.0.2
- Added 'global' keyboard shortcut option
# v2.0.1
- Version bump for NPM
# v2.0.0
This version contains several potential ***breaking changes***:
- `setup()` has been reverted to pre v1.8.0 behaviour; meaning it will return the *instance* rather than the *element*. This is because the reference to the instance is no longer added to the original element (see below).
- The reference to the `plyr` instance is now added to the media element rather than original container. This is because if a container with multiple children was passed to `setup()` the references to all instances would have been added to the container, creating issues. I would recommend using the return value from `setup()` or the new `get()` method to access the instance.
- Players will always be wrapped in their own div now - this makes `setup()` and `destroy()` cleaner. This *may* break any custom styling based on DOM position.
- Players no longer seek to 0 on 'ended' - this is to fix a bug with Microsoft Edge as it triggers 'ended' on media change for whatever reason. They'll never change ;-)
And some other changes and bug fixes:
- New `get()` method on the global plyr object to get all instances inside a container
- New API methods:
- `getOriginal()` to get the original, *unmodified* element plyr was setup on (`<video>`, `<audio>` or empty `<div>` for YouTube and Vimeo)
- `getContainer()` to get the players outer wrapper element
- `getMedia()` to get the players media element (`<video>`, `<audio>` or empty `<div>` for YouTube and Vimeo)
- `getEmbed()` to access the YouTube or Vimeo API directly
- `getType()` to get the type of the player
- `isReady()` to determine if an instance has completed setup and necessary APIs are loaded (for YouTube / Vimeo)
- `on()` to provide an easy way to listen to events
- `stop()` to, you guessed it, stop the player
- `destroy()` now works correctly for YouTube and Vimeo (fixes #272)
- New `destroyed` event when `destroy()` has completed (original element is passed as event.target)
- Default volume is now 10 (max) rather than 5
- Sprite is only loaded once (fixes #259)
- Fixes for Vimeo post message bugs on source change or destroy (fixes #318)
- Save caption state in storage (fixes #311)
- Added keyboard shortcuts to the current focused player (with `keyboardShortcuts` boolean option to disable) (fixes #309)
- Fix for captions bug (fixes #332)
- Change to AMD (fixes #298)
## v1.8.12
- Vimeo keyboard focus fix (Fixes #317)
- Fix for Vimeo on basic support devices
## v1.8.11
- Fix for keyboard navigation on Vimeo (Fixes #317)
- Fix for bug introduced in v1.8.9 related to additional controls
- Vimeo API upgrade
- Fix for YouTube bug introduced in v1.8.9
- Added support for passing array to .setup() (Fixes #319)
## v1.8.10
- Fix for seek issues introduced in v1.8.9
## v1.8.9
- Fix for fullscreen not being defined (Fixes #295)
- Fix for multiline captions (Fixes #314)
- Clean up of type checks and fix for `restart()` (Fixes #315)
- Fix for `MEDIA_ERR_SRC_NOT_SUPPORTED` when calling `.source()` API method
## v1.8.8
- Added getCurrentTime API method (fixes #292)
- Fix for !hideControls on touch devices (fixes #303)
## v1.8.7
- Line height fix
## v1.8.6
- Reverted font size change
## v1.8.5
- Fixed overflow issues (fixes #286)
## v1.8.4
- Fix for large play button on small videos
## v1.8.3
- Disabled iPad support for YouTube and Vimeo due to iOS limitations with iFrame playback
- Fixed IE11 icon loading (fixes #269)
- Updated screenshot (fixes #281)
@ -9,10 +81,10 @@
- Added HLS, Shaka and dash.js examples (see #235 for more)
- Improvements for controls hiding and showing on touch devices
# v1.8.2
## v1.8.2
- Fixed event bubbling
# v1.8.1
## v1.8.1
- Fixed inaccurate log message
# v1.8.0

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,o=arguments.length;for(i=0;o>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",o=e.Element[i],n=Object,s=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=s.call(e.getAttribute("class")||""),i=t?t.split(/\s+/):[],o=0,n=i.length;n>o;o++)this.push(i[o]);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,o=t.length,n=!1;do e=t[i]+"",-1===c(this,e)&&(this.push(e),n=!0);while(++i<o);n&&this._updateClassName()},u.remove=function(){var e,t,i=arguments,o=0,n=i.length,s=!1;do for(e=i[o]+"",t=c(this,e);-1!==t;)this.splice(t,1),s=!0,t=c(this,e);while(++o<n);s&&this._updateClassName()},u.toggle=function(e,t){e+="";var i=this.contains(e),o=i?t!==!0&&"remove":t!==!1&&"add";return o&&this[o](e),t===!0||t===!1?t:!i},u.toString=function(){return this.join(" ")},n.defineProperty){var p={get:d,enumerable:!0,configurable:!0};try{n.defineProperty(o,t,p)}catch(h){-2146823252===h.number&&(p.enumerable=!1,n.defineProperty(o,t,p))}}else n[i].__defineGetter__&&o.__defineGetter__(t,d)}}(self)),function(){function e(e,t,i){if(e)if(e.classList)e.classList[i?"add":"remove"](t);else{var o=(" "+e.className+" ").replace(/\s+/g," ").replace(" "+t+" ","");e.className=o+(i?" "+t:"")}}function t(t,i){if(t in s&&(i||t!=r)&&(r.length||t!=s.video)){switch(t){case s.video:o.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 s.audio:o.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 s.youtube:o.source({type:"video",title:"View From A Blue Moon",sources:[{src:"bTqVqk7FSmY",type:"youtube"}]});break;case s.vimeo:o.source({type:"video",title:"View From A Blue Moon",sources:[{src:"143418951",type:"vimeo"}]})}r=t;for(var a=n.length-1;a>=0;a--)e(n[a].parentElement,"active",!1);e(document.querySelector('[data-source="'+t+'"]').parentElement,"active",!0)}}document.body.addEventListener("ready",function(e){console.log(e)});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 o=i[0].plyr,n=document.querySelectorAll("[data-source]"),s={video:"video",audio:"audio",youtube:"youtube",vimeo:"vimeo"},r=window.location.hash.replace("#",""),a=window.history&&window.history.pushState,c=n.length-1;c>=0;c--)n[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=s.video),r in s&&history.replaceState({type:r},"",l?"":"#"+r),r!==s.video&&t(r,!0)}}(),document.domain.indexOf("plyr.io")>-1&&(!function(e,t,i,o,n,s,r){e.GoogleAnalyticsObject=n,e[n]=e[n]||function(){(e[n].q=e[n].q||[]).push(arguments)},e[n].l=1*new Date,s=t.createElement(i),r=t.getElementsByTagName(i)[0],s.async=1,s.src=o,r.parentNode.insertBefore(s,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;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"));

View File

@ -8,78 +8,78 @@
// General functions
;(function() {
document.body.addEventListener('ready', function(event) { console.log(event); });
//document.body.addEventListener('ready', function(event) { console.log(event); });
// Setup the player
var instances = plyr.setup({
debug: true,
title: 'Video demo',
iconUrl: '../dist/plyr.svg',
tooltips: {
controls: true
},
captions: {
defaultActive: true
}
});
plyr.loadSprite('dist/demo.svg');
// Setup the player
var instances = plyr.setup({
debug: true,
title: 'Video demo',
iconUrl: '../dist/plyr.svg',
tooltips: {
controls: true
},
captions: {
defaultActive: true
}
});
plyr.loadSprite('dist/demo.svg');
// Plyr returns an array regardless
var player = instances[0];
// Plyr returns an array regardless
var player = instances[0].plyr;
// Setup type toggle
var buttons = document.querySelectorAll('[data-source]'),
types = {
video: 'video',
audio: 'audio',
youtube: 'youtube',
vimeo: 'vimeo'
},
currentType = window.location.hash.replace('#', ''),
historySupport = (window.history && window.history.pushState);
// Setup type toggle
var buttons = document.querySelectorAll('[data-source]'),
types = {
video: 'video',
audio: 'audio',
youtube: 'youtube',
vimeo: 'vimeo'
},
currentType = window.location.hash.replace('#', ''),
historySupport = (window.history && window.history.pushState);
// Bind to each button
for (var i = buttons.length - 1; i >= 0; i--) {
buttons[i].addEventListener('click', function() {
var type = this.getAttribute('data-source');
// Bind to each button
for (var i = buttons.length - 1; i >= 0; i--) {
buttons[i].addEventListener('click', function() {
var type = this.getAttribute('data-source');
newSource(type);
newSource(type);
if (historySupport) {
history.pushState({ 'type': type }, '', '#' + type);
}
});
}
if (historySupport) {
history.pushState({ 'type': type }, '', '#' + type);
}
});
}
// List for backwards/forwards
window.addEventListener('popstate', function(event) {
if(event.state && 'type' in event.state) {
newSource(event.state.type);
}
});
// List for backwards/forwards
window.addEventListener('popstate', function(event) {
if(event.state && 'type' in event.state) {
newSource(event.state.type);
}
});
// On load
if(historySupport) {
var video = !currentType.length;
// On load
if(historySupport) {
var video = !currentType.length;
// If there's no current type set, assume video
if(video) {
currentType = types.video;
}
// If there's no current type set, assume video
if(video) {
currentType = types.video;
}
// Replace current history state
if(currentType in types) {
history.replaceState({ 'type': currentType }, '', (video ? '' : '#' + currentType));
}
// Replace current history state
if(currentType in types) {
history.replaceState({ 'type': currentType }, '', (video ? '' : '#' + currentType));
}
// If it's not video, load the source
if(currentType !== types.video) {
newSource(currentType, true);
}
}
// If it's not video, load the source
if(currentType !== types.video) {
newSource(currentType, true);
}
}
// Toggle class on an element
function toggleClass(element, className, state) {
// Toggle class on an element
function toggleClass(element, className, state) {
if (element) {
if (element.classList) {
element.classList[state ? 'add' : 'remove'](className);
@ -91,95 +91,95 @@
}
}
// Set a new source
function newSource(type, init) {
// Bail if new type isn't known, it's the current type, or current type is empty (video is default) and new type is video
if(!(type in types) || (!init && type == currentType) || (!currentType.length && type == types.video)) {
return;
}
// Set a new source
function newSource(type, init) {
// Bail if new type isn't known, it's the current type, or current type is empty (video is default) and new type is video
if(!(type in types) || (!init && type == currentType) || (!currentType.length && type == types.video)) {
return;
}
switch(type) {
case types.video:
player.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: true
}]
});
break;
switch(type) {
case types.video:
player.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: true
}]
});
break;
case types.audio:
player.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 types.audio:
player.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 types.youtube:
player.source({
type: 'video',
title: 'View From A Blue Moon',
sources: [{
src: 'bTqVqk7FSmY',
type: 'youtube'
}]
});
break;
case types.youtube:
player.source({
type: 'video',
title: 'View From A Blue Moon',
sources: [{
src: 'bTqVqk7FSmY',
type: 'youtube'
}]
});
break;
case types.vimeo:
player.source({
type: 'video',
title: 'View From A Blue Moon',
sources: [{
src: '143418951',
type: 'vimeo'
}]
});
break;
}
case types.vimeo:
player.source({
type: 'video',
title: 'View From A Blue Moon',
sources: [{
src: '143418951',
type: 'vimeo'
}]
});
break;
}
// Set the current type for next time
currentType = type;
// Set the current type for next time
currentType = type;
// Remove active classes
for (var x = buttons.length - 1; x >= 0; x--) {
toggleClass(buttons[x].parentElement, 'active', false);
}
// Remove active classes
for (var x = buttons.length - 1; x >= 0; x--) {
toggleClass(buttons[x].parentElement, 'active', false);
}
// Set active on parent
toggleClass(document.querySelector('[data-source="'+ type +'"]').parentElement, 'active', true);
}
// Set active on parent
toggleClass(document.querySelector('[data-source="'+ type +'"]').parentElement, 'active', true);
}
})();
// Google analytics
// For demo site (http://[www.]plyr.io) only
if(document.domain.indexOf('plyr.io') > -1) {
(function(i,s,o,g,r,a,m){i.GoogleAnalyticsObject=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-40881672-11', 'auto');
ga('send', 'pageview');
(function(i,s,o,g,r,a,m){i.GoogleAnalyticsObject=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-40881672-11', 'auto');
ga('send', 'pageview');
}

View File

@ -39,9 +39,10 @@ header {
// Sections
section {
padding-bottom: @padding-base;
max-width: @example-width-video;
margin: 0 auto @padding-base;
@media (min-width: @screen-sm) {
padding-bottom: (@padding-base * 2);
margin-bottom: (@padding-base * 2);
}
}

View File

@ -2,11 +2,6 @@
// Examples
// ==========================================================================
section {
margin: 0 auto @padding-base;
max-width: @example-width-video;
}
// For non supported browsers
video {
max-width: 100%;
@ -21,7 +16,7 @@ video {
.plyr--audio {
max-width: @example-width-audio;
}
.plyr--video::after {
.plyr__video-wrapper::after {
content: "";
pointer-events: none;
position: absolute;

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,6 +1,6 @@
{
"name": "plyr",
"version": "1.8.3",
"version": "2.0.2",
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
"homepage": "http://plyr.io",
"main": "src/js/plyr.js",

485
readme.md
View File

@ -3,7 +3,7 @@ A simple, accessible and customizable HTML5, YouTube and Vimeo media player.
[Checkout the demo](https://plyr.io)
[![Image of Plyr](https://cdn.selz.com/plyr/plyr_v1.8.png)](https://plyr.io)
[![Image of Plyr](https://cdn.selz.com/plyr/plyr_v1.8.9.png)](https://plyr.io)
## Why?
We wanted a lightweight, accessible and customizable media player that supports [*modern*](#browser-support) browsers. Sure, there are many other players out there but we wanted to keep things simple, using the right elements for the job.
@ -13,16 +13,17 @@ We wanted a lightweight, accessible and customizable media player that supports
- **Lightweight** - under 10KB minified and gzipped
- **[Customisable](#html)** - make the player look how you want with the markup you want
- **Semantic** - uses the *right* elements. `<input type="range">` for volume and `<progress>` for progress and well, `<button>`s for buttons. There's no `<span>` or `<a href="#">` button hacks
- **Responsive** - as you'd expect these days
- **Responsive** - works with any screen size
- **HTML Video & Audio** - support for both formats
- **[Embedded Video](#embeds)** - support for YouTube and Vimeo video playback
- **[Streaming](#streaming)** - support for hls.js, Shaka and dash.js streaming playback
- **[API](#api)** - toggle playback, volume, seeking, and more
- **[Universal events](#events)** - no messing around with Vimeo and YouTube APIs, all events are universal across formats
- **[Events](#events)** - no messing around with Vimeo and YouTube APIs, all events are standardized across formats
- **[Fullscreen](#fullscreen)** - supports native fullscreen with fallback to "full window" modes
- **[Shortcuts](#shortcuts)** - supports keyboard shortcuts
- **i18n support** - support for internationalization of controls
- **No dependencies** - written in "vanilla" JavaScript, no jQuery required
- **SASS and LESS provided** - If you like _these_ over plain CSS
- **[Streaming](#streaming)** - Support for hls.js, Shaka and dash.js streaming playback
- **SASS and LESS** - to include in your build processes
Oh and yes, it works with Bootstrap.
@ -30,8 +31,8 @@ Oh and yes, it works with Bootstrap.
Check out the [changelog](changelog.md) to see what's new with Plyr.
## Planned Development
- Streaming
- Playback speed
- Quality selection
- Playlists
- Multiple language captions (with selection)
- Audio captions
@ -41,13 +42,14 @@ If you have any cool ideas or features, please let me know by [creating an issue
## CMS plugins
### [WordPress](https://wordpress.org)
### [WordPress](https://wordpress.org/plugins/plyr/)
Created and maintained by Ryan Anthony Drake ([@iamryandrake](https://github.com/iamryandrake))
[Plyr on WordPress](https://wordpress.org/plugins/plyr/)
### [Neos](https://www.neos.io/)
### [Neos](https://packagist.org/packages/jonnitto/plyr)
Created and maintained by Jon Uhlmann ([@jonnitto](https://github.com/jonnitto))
[Plyr.io for Neos.io](https://packagist.org/packages/jonnitto/plyr)
### [Kirby](https://github.com/dpschen/kirby-plyrtag)
Created and maintained by Dominik Pschenitschni ([@dpschen](https://github.com/dpschen))
## Using package managers
You can grab the source using one of the following package managers.
@ -74,10 +76,10 @@ ember addon:install ember-cli-plyr
More info is on [npm](https://www.npmjs.com/package/ember-cli-plyr) and [GitHub](https://github.com/louisrudner/ember-cli-plyr)
## Quick setup
Here's a quick run through on getting up and running.
Here's a quick run through on getting up and running. There's also a [demo on Codepen](http://codepen.io/sampotts/pen/jARJYp).
### HTML
Plyr extends upon the standard HTML5 markup so that's all you need for those types.
Plyr extends upon the standard HTML5 markup so that's all you need for those types. More info on advanced HTML markup can be found under [initialising](#initialising).
#### HTML5 Video
```html
@ -110,7 +112,7 @@ For YouTube and Vimeo, Plyr uses the standard YouTube API markup (an empty `<div
```
### JavaScript
Include the `plyr.js` script before the closing `</body>` tag and then call `plyr.setup()`. More info on `setup()` can be found under [#initialising](initialising).
Include the `plyr.js` script before the closing `</body>` tag and then call `plyr.setup()`. More info on `setup()` can be found under [initialising](#initialising).
```html
<script src="path/to/plyr.js"></script>
@ -120,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:
```html
<script src="https://cdn.plyr.io/1.8.3/plyr.js"></script>
<script src="https://cdn.plyr.io/2.0.2/plyr.js"></script>
```
### CSS
@ -133,16 +135,18 @@ Include the `plyr.css` stylsheet into your `<head>`
If you want to use our CDN for the default CSS, you can use the following:
```html
<link rel="stylesheet" href="https://cdn.plyr.io/1.8.3/plyr.css">
<link rel="stylesheet" href="https://cdn.plyr.io/2.0.2/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/1.8.3/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.2/plyr.svg`.
## Advanced
### LESS & SASS/SCSS
You can use `plyr.less` or `plyr.scss` file included in `/src` as part of your build and change variables to suit your design. The HTML markup uses the BEM methodology with `plyr` as the block, e.g. `.plyr__controls`. You can change the class hooks in the options to match any custom CSS you write. Check out the JavaScript source for more on this.
You can use `plyr.less` or `plyr.scss` file included in `/src` as part of your build and change variables to suit your design. The LESS and SASS require you to use the [autoprefixer](https://www.npmjs.com/package/gulp-autoprefixer) plugin (you should already) as all declerations use the W3C definitions - e.g. `appearance: none;` will be prefixed to `-webkit-appearance: none;` by autoprefixer.
The HTML markup uses the BEM methodology with `plyr` as the block, e.g. `.plyr__controls`. You can change the class hooks in the options to match any custom CSS you write. Check out the JavaScript source for more on this.
### SVG
The icons used in the Plyr controls are loaded in an SVG sprite. The sprite is automatically loaded from our CDN by default. If you already have an icon build system in place, you can include the source plyr icons (see `/src/sprite` for source icons).
@ -169,7 +173,7 @@ WebVTT captions are supported. To add a caption track, check the HTML example ab
#### Initialising
By default, Plyr looks for all `<video>`, `<audio>` and `[data-type]` elements with the document and initialises on any found. You can specify other options, including a different NodeList, HTMLElement or string selector as below:
By default, `setup()` will find all `<video>`, `<audio>` and `[data-type]` elements with the document and initialises on any found. Each target media element found will be wrapped in a `<div>` for styling and setup individually. You can specify a variety of arguments to `setup()` to use, including a different NodeList, HTMLElement, Array of HTMLElements or string selector as below:
Passing a [NodeList](https://developer.mozilla.org/en-US/docs/Web/API/NodeList):
```javascript
@ -181,19 +185,27 @@ Passing a [HTMLElement](https://developer.mozilla.org/en/docs/Web/API/HTMLElemen
plyr.setup(document.querySelector('.js-player'), options);
```
Passing an [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) of [HTMLElement](https://developer.mozilla.org/en/docs/Web/API/HTMLElement)s:
```javascript
plyr.setup([
document.querySelector('.js-player-1'),
document.querySelector('.js-player-2')
], options);
```
Passing a [string selector](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll):
```javascript
plyr.setup('.js-player', options);
```
The NodeList, HTMLElement or string selector can be the target `<video>`, `<audio>` or `[data-type]` (for embeds) element or a container element. If a container has several media elements inside, each media element will be wrapped in a `<div>` and setup individually.
The NodeList, HTMLElement or string selector can be the target `<video>`, `<audio>` or `[data-type]` (for embeds) element itself or a container element.
Passing just the options object:
```javascript
plyr.setup(options);
```
`setup()` will return an array of all the elements Plyr was setup on. The `plyr` object can be accessed on these elements and used for the API.
`setup()` will return an array of *instances* that can be used with the [API](#api) methods. See the [API](#api) section for more info.
#### RangeTouch
Some touch browsers (particularly Mobile Safari on iOS) seem to have issues with `<input type="range">` elements whereby touching the track to set the value doesn't work and sliding the thumb can be tricky. To combat this, I've created [RangeTouch](https://rangetouch.com) which I'd recommend including in your solution. It's a tiny script with a nice benefit for users on touch devices.
@ -307,6 +319,12 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke
<td><code>false</code></td>
<td>This will restore and *reload* HTML5 video once playback is complete. Note: depending on the browser caching, this may result in the video downloading again (or parts of it). Use with caution.</td>
</tr>
<tr>
<td><code>keyboardShortcuts</code></td>
<td>Object</td>
<td><code>{ focused: true, global: true }</code></td>
<td>Enable <a href="#shortcuts">keyboard shortcuts</a> for focused players only or global as well (if there's only one player in the document)</td>
</tr>
<tr>
<td><code>tooltips</code></td>
<td>Object</td>
@ -403,29 +421,36 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke
## API
#### Getting the `plyr` instance
A `plyr` object is added to any element that Plyr is initialized on. You can then control the player by accessing methods in the `plyr` object.
### Instance
There are two ways to access the instance, firstly you re-query the element container you used for setup (e.g. `.js-player`) like so:
The easiest way to access the plyr instances is to store the return value from your call to `setup()`:
```javascript
var player = document.querySelector('.js-player').plyr;
var players = plyr.setup('.js-player');
```
You can listen for the `setup` [event](#events) on the container, after which the `plyr` key will be available and also passed in the to your callback (in the `plyr` key of the event object).
The other method is using the return value from the call to `setup()`. An array of instances is returned so you need to use an index:
This will return an array of all instances that were setup. Another way is to use `plyr.get()` to get all instances within a given container, for example:
```javascript
var player = plyr.setup('.js-player')[0].plyr;
var players = plyr.get('.js-player');
```
This will return an array of plyr instances that were setup, so you need to specify the index of the instance you want or loop through of course. This is less useful if you are setting up multiple instances.
If no argument is passed, it will find all instances in the current document. This will return an array of all instances that were found in the given selector.
Once you have your instance, you can use the API methods below on it. For example to pause it:
A final option is to access the instance through the event handlers:
```javascript
player.pause();
instance.on('ready', function(event) {
var instance = event.detail.plyr;
});
```
### Methods
Once you have your instances, you can use the API methods below on it. For example to pause the first player:
```javascript
players[0].pause();
```
Here's a list of the methods supported:
@ -439,6 +464,36 @@ Here's a list of the methods supported:
</tr>
</thead>
<tbody>
<tr>
<td><code>getContainer()</code></td>
<td>&mdash;</td>
<td>Get the players outer container element that is automatically injected.</td>
</tr>
<tr>
<td><code>getMedia()</code></td>
<td>&mdash;</td>
<td>Get the media element (<code>&gt;video&lt;</code>, <code>&gt;audio&lt;</code> or <code>&gt;div&lt;</code> for YouTube or Vimeo).</td>
</tr>
<tr>
<td><code>getEmbed()</code></td>
<td>&mdash;</td>
<td>Get the [embed](#embed) API to access those methods - either YouTube or Vimeo.</td>
</tr>
<tr>
<td><code>getType()</code></td>
<td>&mdash;</td>
<td>Get the type - 'video', 'audio', 'youtube' or 'vimeo'.</td>
</tr>
<tr>
<td><code>isReady()</code></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>
</tr>
<tr>
<td><code>on()</code></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>
</tr>
<tr>
<td><code>play()</code></td>
<td>&mdash;</td>
@ -449,7 +504,12 @@ Here's a list of the methods supported:
<td>&mdash;</td>
<td>Pauses the media</td>
</tr>
<tr>
<tr>
<td><code>stop()</code></td>
<td>&mdash;</td>
<td>Stops the media</td>
</tr>
<tr>
<td><code>restart()</code></td>
<td>&mdash;</td>
<td>Restarts playback</td>
@ -528,12 +588,12 @@ Here's a list of the methods supported:
<tr>
<td><code>destroy()</code></td>
<td>&mdash;</td>
<td>Destroys the plyr UI and any media event listeners, effectively restoring to the previous state before <code>setup()</code> was called.</td>
<td>Restores the original element, reversing the effects of <code>setup()</code>.</td>
</tr>
<tr>
<td><code>restore()</code></td>
<td><code>getCurrentTime()</code></td>
<td>&mdash;</td>
<td>Reverses the effects of the <code>destroy()</code> method, restoring the UI and listeners.</td>
<td>Will return a float with the current time in seconds.</td>
</tr>
</tbody>
</table>
@ -628,7 +688,7 @@ Some more details on the object parameters
<tr>
<td><code>title</code></td>
<td>String</td>
<td>Title of the new media. Used for the aria labelling.</td>
<td>Title of the new media. Used for the `aria-label` attribute on the play button, and outer container.</td>
</tr>
<tr>
<td><code>sources</code></td>
@ -649,172 +709,234 @@ Some more details on the object parameters
</table>
## Events
You can listen for events on the target element you setup Plyr on (see example under the table). Some events only apply to HTML5 audio and video.
You can listen for events on the target element you setup Plyr on (see example under the table). Some events only apply to HTML5 audio and video. Using your reference to the instance, you can use the `on()` API method or `addEventListener()`. Access to the API can be obtained this way through the `event.detail.plyr` property. Here's an example:
```javascript
instance.on('ready', function(event) {
var instance = event.detail.plyr;
});
```
These events also bubble up the DOM. The event target will be the container element.
<table class="table" width="100%">
<thead>
<tr>
<th width="20%">Event name</th>
<th width="20%">HTML5 only</th>
<th width="20%">HTML5 only</th>
<th width="60%">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>canplay</code></td>
<td></td>
<td>Sent when enough data is available that the media can be played, at least for a couple of frames. This corresponds to the <code>HAVE_ENOUGH_DATA</code> <code>readyState</code>.</td>
</tr>
<tr>
<td><code>canplaythrough</code></td>
<td></td>
<td>Sent when the ready state changes to <code>CAN_PLAY_THROUGH</code>, indicating that the entire media can be played without interruption, assuming the download rate remains at least at the current level. <strong>Note</strong>: Manually setting the <code>currentTime</code> will eventually fire a <code>canplaythrough</code> event in firefox. Other browsers might not fire this event.</td>
</tr>
<tr>
<td><code>emptied</code></td>
<td></td>
<td>The media has become empty; for example, this event is sent if the media has already been loaded (or partially loaded), and the <code>load()</code> method is called to reload it.</td>
</tr>
<tr>
<td><code>ended</code></td>
<td></td>
<td>Sent when playback completes.</td>
</tr>
<tr>
<td><code>error</code></td>
<td></td>
<td>Sent when an error occurs.&nbsp; The element's <code>error</code> attribute contains more information.</td>
</tr>
<tr>
<td><code>loadeddata</code></td>
<td></td>
<td>The first frame of the media has finished loading.</td>
</tr>
<tr>
<td><code>loadedmetadata</code></td>
<td></td>
<td>The media's metadata has finished loading; all attributes now contain as much useful information as they're going to.</td>
</tr>
<tr>
<td><code>loadstart</code></td>
<td></td>
<td>Sent when loading of the media begins.</td>
</tr>
<tr>
<td><code>pause</code></td>
<td></td>
<td>Sent when playback is paused.</td>
</tr>
<tr>
<td><code>play</code></td>
<td></td>
<td>Sent when playback of the media starts after having been paused; that is, when playback is resumed after a prior <code>pause</code> event.</td>
</tr>
<tr>
<td><code>playing</code></td>
<td></td>
<td>Sent when the media begins to play (either for the first time, after having been paused, or after ending and then restarting).</td>
</tr>
<tr>
<td><code>progress</code></td>
<td></td>
<td>Sent periodically to inform interested parties of progress downloading the media. Information about the current amount of the media that has been downloaded is available in the media element's <code>buffered</code> attribute.</td>
</tr>
<tr>
<td><code>seeked</code></td>
<td></td>
<td>Sent when a seek operation completes.</td>
</tr>
<tr>
<td><code>seeking</code></td>
<td></td>
<td>Sent when a seek operation begins.</td>
</tr>
<tr>
<td><code>stalled</code></td>
<td></td>
<td>Sent when the user agent is trying to fetch media data, but data is unexpectedly not forthcoming.</td>
</tr>
<tr>
<td><code>timeupdate</code></td>
<td></td>
<td>The time indicated by the element's <code>currentTime</code> attribute has changed.</td>
</tr>
<tr>
<td><code>volumechange</code></td>
<td></td>
<td>Sent when the audio volume changes (both when the volume is set and when the <code>muted</code> attribute is changed).</td>
</tr>
<tr>
<td><code>waiting</code></td>
<td></td>
<td>Sent when the requested operation (such as playback) is delayed pending the completion of another operation (such as a seek).</td>
</tr>
<tr>
<td><code>enterfullscreen</code></td>
<td></td>
<td>User enters fullscreen (either the proper fullscreen or full-window fallback for older browsers)</td>
</tr>
<tr>
<td><code>exitfullscreen</code></td>
<td></td>
<td>User exits fullscreen</td>
</tr>
<tr>
<td><code>captionsenabled</code></td>
<td></td>
<td>Captions toggled on</td>
</tr>
<tr>
<td><code>captionsdisabled</code></td>
<td></td>
<td>Captions toggled off</td>
</tr>
<tr>
<td><code>ready</code></td>
<td></td>
<td>Triggered when initial setup is done or a source change has occurred.</td>
</tr>
<tr>
<td><code>setup</code></td>
<td></td>
<td>When an initial setup has completed</td>
</tr>
<tr>
<td><code>ready</code></td>
<td></td>
<td>Triggered when the instance is ready for API use and external APIs are ready (YouTube and Vimeo).</td>
</tr>
<tr>
<td><code>canplay</code></td>
<td></td>
<td>Sent when enough data is available that the media can be played, at least for a couple of frames. This corresponds to the <code>HAVE_ENOUGH_DATA</code> <code>readyState</code>.</td>
</tr>
<tr>
<td><code>canplaythrough</code></td>
<td></td>
<td>Sent when the ready state changes to <code>CAN_PLAY_THROUGH</code>, indicating that the entire media can be played without interruption, assuming the download rate remains at least at the current level. <strong>Note</strong>: Manually setting the <code>currentTime</code> will eventually fire a <code>canplaythrough</code> event in firefox. Other browsers might not fire this event.</td>
</tr>
<tr>
<td><code>emptied</code></td>
<td></td>
<td>The media has become empty; for example, this event is sent if the media has already been loaded (or partially loaded), and the <code>load()</code> method is called to reload it.</td>
</tr>
<tr>
<td><code>ended</code></td>
<td></td>
<td>Sent when playback completes.</td>
</tr>
<tr>
<td><code>error</code></td>
<td></td>
<td>Sent when an error occurs.&nbsp; The element's <code>error</code> attribute contains more information.</td>
</tr>
<tr>
<td><code>loadeddata</code></td>
<td></td>
<td>The first frame of the media has finished loading.</td>
</tr>
<tr>
<td><code>loadedmetadata</code></td>
<td></td>
<td>The media's metadata has finished loading; all attributes now contain as much useful information as they're going to.</td>
</tr>
<tr>
<td><code>loadstart</code></td>
<td></td>
<td>Sent when loading of the media begins.</td>
</tr>
<tr>
<td><code>pause</code></td>
<td></td>
<td>Sent when playback is paused.</td>
</tr>
<tr>
<td><code>play</code></td>
<td></td>
<td>Sent when playback of the media starts after having been paused; that is, when playback is resumed after a prior <code>pause</code> event.</td>
</tr>
<tr>
<td><code>playing</code></td>
<td></td>
<td>Sent when the media begins to play (either for the first time, after having been paused, or after ending and then restarting).</td>
</tr>
<tr>
<td><code>progress</code></td>
<td></td>
<td>Sent periodically to inform interested parties of progress downloading the media. Information about the current amount of the media that has been downloaded is available in the media element's <code>buffered</code> attribute.</td>
</tr>
<tr>
<td><code>seeked</code></td>
<td></td>
<td>Sent when a seek operation completes.</td>
</tr>
<tr>
<td><code>seeking</code></td>
<td></td>
<td>Sent when a seek operation begins.</td>
</tr>
<tr>
<td><code>stalled</code></td>
<td></td>
<td>Sent when the user agent is trying to fetch media data, but data is unexpectedly not forthcoming.</td>
</tr>
<tr>
<td><code>timeupdate</code></td>
<td></td>
<td>The time indicated by the element's <code>currentTime</code> attribute has changed.</td>
</tr>
<tr>
<td><code>volumechange</code></td>
<td></td>
<td>Sent when the audio volume changes (both when the volume is set and when the <code>muted</code> attribute is changed).</td>
</tr>
<tr>
<td><code>waiting</code></td>
<td></td>
<td>Sent when the requested operation (such as playback) is delayed pending the completion of another operation (such as a seek).</td>
</tr>
<tr>
<td><code>enterfullscreen</code></td>
<td></td>
<td>User enters fullscreen (either the proper fullscreen or full-window fallback for older browsers)</td>
</tr>
<tr>
<td><code>exitfullscreen</code></td>
<td></td>
<td>User exits fullscreen</td>
</tr>
<tr>
<td><code>captionsenabled</code></td>
<td></td>
<td>Captions toggled on</td>
</tr>
<tr>
<td><code>captionsdisabled</code></td>
<td></td>
<td>Captions toggled off</td>
</tr>
<tr>
<td><code>destroyed</code></td>
<td></td>
<td>When an instance is destroyed. The original element that replaced the container will be returned to your handler as the event target.</td>
</tr>
</tbody>
</table>
Details borrowed from: [https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events)
Here's an example of binding an event listener:
```javascript
document.querySelector('.js-plyr').addEventListener('ready', function(event) {
var player = event.target.plyr;
});
```
These events also bubble up the DOM.
## Embeds
YouTube and Vimeo are currently supported and function much like a HTML5 video. Check the relevant documentation sections for any differences.
Plyr references a custom version of the Vimeo Froogaloop API as Vimeo have neglected to maintain the library and there were bugs with their version. You don't need to worry about including your own versions of the Vimeo or YouTube JavaScript APIs.
The native API's can be accessed through the `embed` property of the plyr object. For example:
```javascript
document.querySelector('.js-plyr').addEventListener('ready', function(event) {
var player = event.target.plyr;
// YouTube
console.log(player.embed.getVideoData());
// Vimeo
console.log(player.embed.api('getColor'));
});
```
The embed third party API's can be accessed through the `getEmbed()` API method.
More info on the respective API's here:
[YouTube API Reference](https://developers.google.com/youtube/js_api_reference)
[Vimeo API Reference](https://developer.vimeo.com/player/js-api#reference)
- [YouTube API Reference](https://developers.google.com/youtube/js_api_reference)
- [Vimeo API Reference](https://developer.vimeo.com/player/js-api#reference)
*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
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 (such as an `<input>`, `<select>` or `[contenteditable]`).
<table class="table" width="100%">
<thead>
<tr>
<th width="25%">Key</th>
<th width="25%">Global</th>
<th width="50%">Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>0</code> to <code>9</code></td>
<td></td>
<td>Seek from 0 to 90% respectively</td>
</tr>
<tr>
<td><code>space</code></td>
<td></td>
<td>Toggle playback</td>
</tr>
<tr>
<td><code>K</code></td>
<td></td>
<td>Toggle playback</td>
</tr>
<tr>
<td><code>&larr;</code></td>
<td></td>
<td>Seek backward by the <code>seekTime</code> option</td>
</tr>
<tr>
<td><code>&rarr;</code></td>
<td></td>
<td>Seek forward by the <code>seekTime</code> option</td>
</tr>
<tr>
<td><code>&uarr;</code></td>
<td></td>
<td>Increase volume</td>
</tr>
<tr>
<td><code>&darr;</code></td>
<td></td>
<td>Decrease volume</td>
</tr>
<tr>
<td><code>M</code></td>
<td></td>
<td>Toggle mute</td>
</tr>
<tr>
<td><code>F</code></td>
<td></td>
<td>Toggle fullscreen</td>
</tr>
<tr>
<td><code>C</code></td>
<td></td>
<td>Toggle captions</td>
</tr>
</tbody>
</table>
## Streaming
Because Plyr is an extension of the standard HTML5 video and audio elements, third party streaming plugins can be used with Plyr. Massive thanks to Matias Russitto ([@russitto](https://github.com/russitto)) for working on this. Here's a few examples:
@ -823,7 +945,7 @@ Because Plyr is an extension of the standard HTML5 video and audio elements, thi
- Using [dash.js](https://github.com/Dash-Industry-Forum/dash.js) - [Demo](http://codepen.io/sampotts/pen/BzpJXN)
## Fullscreen
Fullscreen in Plyr is supported by all browsers that [currently support it](http://caniuse.com/#feat=fullscreen). If you're using the default CSS, you can also use a "full browser" mode which will use the full browser window by adding the `plyr-fullscreen` class to your container.
Fullscreen in Plyr is supported by all browsers that [currently support it](http://caniuse.com/#feat=fullscreen).
## Browser support
@ -888,6 +1010,11 @@ Plyr is developed by [@sam_potts](https://twitter.com/sam_potts) / [sampotts.me]
## Used by
- [Selz.com](https://selz.com)
- [Peugeot.fr](http://www.peugeot.fr/marque-et-technologie/technologies/peugeot-i-cockpit.html)
- [Peugeot.de](http://www.peugeot.de/modelle/modellberater/208-3-turer/fotos-videos.html)
- [TomTom.com](http://prioritydriving.tomtom.com/)
- [DIGBMX](http://digbmx.com/)
- [Grime Archive](https://grimearchive.com/)
- [koel - A personal music streaming server that works.](http://koel.phanan.net/)
- [Oscar Radio](http://oscar-radio.xyz/)

File diff suppressed because it is too large Load Diff

View File

@ -19,8 +19,7 @@
position: relative;
max-width: 100%;
min-width: 200px;
overflow: hidden;
font-family: Avenir, "Avenir Next", "Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif;
font-family: @plyr-font-family;
direction: ltr;
& when (@plyr-border-box = true) {
@ -41,6 +40,11 @@
}
}
// Focus
&:focus {
outline: 0;
}
// Media elements
video,
audio {
@ -226,6 +230,8 @@
border-radius: 2px;
padding: floor(@plyr-control-spacing / 3) @plyr-control-spacing;
background: @plyr-captions-bg;
box-decoration-break: clone;
line-height: 150%;
}
span:empty {
display: none;
@ -354,7 +360,6 @@
border-radius: inherit;
background: @plyr-audio-controls-bg;
border: @plyr-audio-controls-border;
box-shadow: @plyr-audio-controls-box-shadow;
color: @plyr-audio-control-color;
button {
@ -371,6 +376,7 @@
.plyr__play-large {
display: none;
position: absolute;
z-index: 1;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
@ -378,7 +384,7 @@
background: @plyr-video-control-bg-hover;
border: 4px solid currentColor;
border-radius: 100%;
box-shadow: 0 1px 1px fade(@plyr-video-controls-bg, 15%);
box-shadow: 0 1px 1px fade(#000, 15%);
color: @plyr-video-control-color;
transition: all .3s ease;
@ -663,7 +669,6 @@
display: inline-block;
vertical-align: middle;
font-size: @plyr-font-size-small;
line-height: .95;
}
// Media duration hidden on small screens
.plyr__time + .plyr__time {
@ -712,7 +717,6 @@
// Fullscreen
// --------------------------------------------------------------
.plyr--fullscreen,
.plyr--fullscreen-active {
position: fixed;
top: 0;
@ -723,7 +727,7 @@
width: 100%;
z-index: 10000000;
background: #000;
border-radius: 0;
border-radius: 0 !important;
video {
height: 100%;

View File

@ -11,7 +11,8 @@
// Colors
@plyr-color-main: #3498db;
// Font sizes
// Font
@plyr-font-family: Avenir, 'Avenir Next', 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, sans-serif;
@plyr-font-size-small: 14px;
@plyr-font-size-base: 16px;
@ -32,7 +33,6 @@
@plyr-video-control-bg-hover: @plyr-color-main;
@plyr-audio-controls-bg: #fff;
@plyr-audio-controls-border: 1px solid #dbe3e8;
@plyr-audio-controls-box-shadow: 0 1px 1px fade(#000, 5%);
@plyr-audio-control-color: #565D64;
@plyr-audio-control-color-hover: #fff;
@plyr-audio-control-bg-hover: @plyr-color-main;

View File

@ -19,8 +19,7 @@
position: relative;
max-width: 100%;
min-width: 200px;
overflow: hidden;
font-family: Avenir, "Avenir Next", "Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif;
font-family: $plyr-font-family;
direction: ltr;
@if $plyr-border-box == true {
@ -41,6 +40,11 @@
}
}
// Focus
&:focus {
outline: 0;
}
// Media elements
video,
audio {
@ -226,6 +230,8 @@
border-radius: 2px;
padding: floor($plyr-control-spacing / 3) $plyr-control-spacing;
background: $plyr-captions-bg;
box-decoration-break: clone;
line-height: 150%;
}
span:empty {
display: none;
@ -354,7 +360,6 @@
border-radius: inherit;
background: $plyr-audio-controls-bg;
border: $plyr-audio-controls-border;
box-shadow: $plyr-audio-controls-box-shadow;
color: $plyr-audio-control-color;
button {
@ -371,6 +376,7 @@
.plyr__play-large {
display: none;
position: absolute;
z-index: 1;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
@ -378,7 +384,7 @@
background: $plyr-video-control-bg-hover;
border: 4px solid currentColor;
border-radius: 100%;
box-shadow: 0 1px 1px transparentize($plyr-video-controls-bg, .85);
box-shadow: 0 1px 1px transparentize(#000, .85);
color: $plyr-video-control-color;
transition: all .3s ease;
@ -662,7 +668,6 @@
display: inline-block;
vertical-align: middle;
font-size: $plyr-font-size-small;
line-height: .95;
}
// Media duration hidden on small screens
.plyr__time + .plyr__time {
@ -711,7 +716,6 @@
// Fullscreen
// --------------------------------------------------------------
.plyr--fullscreen,
.plyr--fullscreen-active {
position: fixed;
top: 0;
@ -722,7 +726,7 @@
width: 100%;
z-index: 10000000;
background: #000;
border-radius: 0;
border-radius: 0 !important;
video {
height: 100%;

View File

@ -13,6 +13,7 @@ $plyr-sr-only-important: true !default;
$plyr-color-main: #3498db !default;
// Font sizes
$plyr-font-family: Avenir, 'Avenir Next', 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, sans-serif !default;
$plyr-font-size-small: 14px !default;
$plyr-font-size-base: 16px !default;
@ -33,7 +34,6 @@ $plyr-video-control-color-hover: #fff !default;
$plyr-video-control-bg-hover: $plyr-color-main !default;
$plyr-audio-controls-bg: #fff !default;
$plyr-audio-controls-border: 1px solid #dbe3e8 !default;
$plyr-audio-controls-box-shadow: 0 1px 1px transparentize(#000, .95) !default;
$plyr-audio-control-color: #565D64 !default;
$plyr-audio-control-color-hover: #fff !default;
$plyr-audio-control-bg-hover: $plyr-color-main;