Compare commits

...

48 Commits

Author SHA1 Message Date
Sam
1a745e1eaa Merge branch 'master' of https://github.com/Selz/plyr 2016-06-07 12:34:40 +01:00
Sam
70646ca907 See changelog (fixes #265, #253, #257) 2016-06-07 12:34:36 +01:00
af774b6f02 Merge pull request #260 from cytec/fix-control-icon-size
use $plyr-control-icon-size in sass file
2016-06-02 10:41:36 +01:00
7a9eac093a use $plyr-control-icon-size in sass file 2016-06-02 11:40:09 +02:00
Sam
4afd311ef6 Version bump 2016-06-02 10:19:35 +01:00
Sam
7eec6c6739 Fix for multiple sprites being requested (fixes #259) 2016-06-02 10:18:33 +01:00
Sam
521431e093 Fix for scroll direction on volume (fixes #258) 2016-06-01 09:38:29 +01:00
Sam
552f448ccd Seek rounding from 1 to 4 decimal places (fixes #242) 2016-05-30 07:41:17 +01:00
cb318dd6ad Update readme.md 2016-05-27 08:42:11 +01:00
Sam
9ee0d00a35 Merge branch 'master' of https://github.com/Selz/plyr 2016-05-26 22:32:23 +01:00
Sam
c0909095e3 Added disableContextMenu option to hide the right click context menu (fixes #248 and #225) 2016-05-26 22:32:18 +01:00
1e732694eb Merge pull request #246 from zvizvi/master
FIx Plyr to work with RTL systems
2016-05-26 08:03:40 +01:00
30922246e9 FIx Plyr to work with RTL systems 2016-05-26 03:35:08 +03:00
edf5a14171 FIx Plyr to work with RTL systems
(less)
2016-05-26 03:33:05 +03:00
1c9f7901bc FIx Plyr to work with RTL systems
(scss)
2016-05-26 03:32:22 +03:00
1bd6ffc84d Merge pull request #237 from itaditya/master
Update readme.md
2016-05-25 19:13:13 +01:00
845ed000fc Merge pull request #244 from thijstriemstra/patch-1
reference unminified js script
2016-05-25 19:12:05 +01:00
c7b2347ccd reference unminified js script
Reading the minified js script is impossible so reference the source version instead.
2016-05-25 19:41:12 +02:00
a2f18c4e31 Merge pull request #241 from rabbitears/patch-1
Fix typo
2016-05-24 21:52:26 +01:00
37c8948d2c Fix typo 2016-05-24 14:08:15 -04:00
Sam
351e1540c5 Version bump 2016-05-23 22:33:16 +01:00
Sam
b3299b4641 Fix for Tooltips overflowing (fixes #230) 2016-05-23 22:29:20 +01:00
Sam
be2e7d4c99 Always hide standard controls (Fixes #225) 2016-05-23 21:19:53 +01:00
Sam
7238eab737 Merge branch 'master' of https://github.com/Selz/plyr 2016-05-23 21:11:54 +01:00
Sam
3c2921b994 Restore scroll position when exiting fullscreen (fixes #236) 2016-05-23 21:11:43 +01:00
179c6fca0b Update readme.md 2016-05-23 19:21:43 +01:00
Sam
69194915d4 Sprite loading improvements, touch controls
- SVG sprite loading automatically for an easier setup
- Touch devices now show controls on touch rather than pausing playback
2016-05-23 19:16:48 +01:00
341fd59cf6 Update readme.md 2016-05-23 21:34:57 +05:30
a6c8b7e506 Update readme.md
thang was a less common word , keeping it simple by using 'thing' is I think good , also there were SASS support so why not add that too.
2016-05-22 16:36:30 +05:30
98e4c5acea Decreased sensitivity and inverted scroll on volume slider (scroll up to increase, down to decrease) 2016-05-19 12:06:51 +10:00
1496b21c83 Version bump 2016-05-19 11:59:52 +10:00
ac0061b83e Bug fix for no buffer 2016-05-19 11:56:24 +10:00
0b7dc51bd1 Merge branch 'master' into develop
# Conflicts:
#	dist/plyr.css
#	dist/plyr.js
2016-05-19 11:32:14 +10:00
126f80ed78 Reverted LESS structure for now 2016-05-19 11:31:27 +10:00
e0ef7482c6 Merge pull request #227 from igoradamenko/scroll-on-volume-slider
Add scroll listener on volume slider
2016-05-19 10:43:22 +10:00
6ffb971226 Add scroll listener on volume slider 2016-05-19 02:11:41 +03:00
72187a89dd Update readme.md 2016-05-19 08:47:42 +10:00
a461500ab9 Update readme.md 2016-05-17 12:38:52 +10:00
c830af492c Merge pull request #216 from IonicaBizauKitchen/fix
Removed "Node Package Manager" in readme.md
2016-05-17 08:30:25 +10:00
1f6f841fcb Removed "Node Package Manager" in readme.md
`npm` does not stand for "Node Package Manager" because `npm` is not an acronym. It is a bacronymic abbreviation for "npm is not an acronym".

https://www.quora.com/I-keep-hearing-NPM-doesnt-stand-for-Node-Package-Manager-what-does-it-stand-for
2016-05-16 17:59:37 +03:00
99960c0dc5 Fix for Vimeo fullscreen (fixes #214) 2016-05-16 12:28:28 +10:00
Sam
4a69ef3874 Merge branch 'master' into develop
# Conflicts:
#	dist/plyr.css
#	src/less/plyr.less
2016-05-11 22:47:27 +10:00
d351f9f172 Merge branch 'master' into develop
# Conflicts:
#	dist/plyr.css
#	src/less/plyr.less
2016-05-10 10:01:29 +10:00
3f20462943 Restore simplicity to LESS file structure 2016-05-10 09:35:19 +10:00
3470d5f5e6 Merge branch 'master' into develop
# Conflicts:
#	src/less/plyr.less
2016-05-09 19:11:57 +10:00
bb976ccf4b Merge pull request #200 from shakeelmohamed/feature/youtube-onstatuschange-event
Add event for YouTube onStateChange
2016-05-02 07:31:29 +10:00
f02cb5635f Add event for YouTube onStateChange 2016-05-01 10:24:25 -07:00
fad3f41ca7 Prep work for theming 2016-05-01 19:27:53 +10:00
37 changed files with 591 additions and 320 deletions

View File

@ -10,14 +10,14 @@
"plyr.js": ["src/js/plyr.js"]
}
},
"docs": {
"demo": {
"less": {
"docs.css": ["docs/src/less/docs.less"]
"demo.css": ["demo/src/less/demo.less"]
},
"js": {
"docs.js": [
"docs/src/js/lib/classlist.js",
"docs/src/js/docs.js"
"demo.js": [
"demo/src/js/lib/classlist.js",
"demo/src/js/main.js"
]
}
}

View File

@ -1,5 +1,45 @@
# Changelog
# v1.7.0
- SASS cleanup (fixes #265)
- Docs tidy up to help quick start (fixes #253)
- Fix for issues with data attribute options passing (fixes #257)
- Removed the requirement for a wrapper div to setup Plyr and removed the dependency on the `plyr` classname as a JS hook. By default it will now look for `<video>`, `<audio>` and `[data-type]` elements. If you are just calling `setup()` with a `<div class="plyr">` you may want to give it a good test after upgrading. You can probably remove the wrapper div. The reason behind this is to make setup easier for newcomers and prevent the styling being used on unsupported players (because the plyr classname was used as a CSS and JS hook - which isn't ideal)
- Renamed the 'docs' folder to `demo` to avoid confusion. The readme is the docs after all.
## v1.6.20
- Fix for multiple sprites being requested (fixes #259)
## v1.6.19
- Fix for scroll direction issues on volume control (fixes #258)
## v1.6.18
- Reduced rounding of seek value from 1 decimal point to 4 (fixes #242)
## v1.6.17
- Added `disableContextMenu` option to hide the right click context menu (fixes #248 and #225)
## v1.6.16
- Always hide standard controls (fixes #225)
- Fix for Tooltips overflowing (fixes #230)
## v1.6.15
- Restore scroll position when exiting full screen (fixes #236)
## v1.6.14
- SVG sprite loading automatically for an easier setup
- Touch devices now show controls on touch rather than pausing playback
## v1.6.13
- Decreased sensitivity and inverted scroll on volume slider (scroll up to increase, down to decrease)
## v1.6.12
- Fix for undefined buffer error
- Add scroll listener on volume slider (PR #227 bty @igoradamenko)
## v1.6.11
- Fix for Vimeo fullscreen (fixes #214)
## v1.6.10
- Changed default icon prefix from 'icon' to 'plyr' to avoid clashes
@ -68,18 +108,18 @@
- Docs fixes inc controls HTML (fixes #180)
## v1.5.17
- Expose YouTube and Vimeo API (docs update required) (Fixes #176)
- Expose YouTube and Vimeo API (docs update required) (fixes #176)
- Auto set title based on YouTube getVideoData() title property
- Bug fix for Vimeo API change (Uncaught TypeError: Cannot read property 'value' of undefined) due to a change their end
## v1.5.16
- Cancel requests on source change (Fixes #174)
- Cancel requests on source change (fixes #174)
## v1.5.15
- Fix for CustomEvent polyfill and related bug (See #172)
- Fix for CustomEvent polyfill and related bug (see #172)
## v1.5.14
- Volume storage fix (Fixes #171)
- Volume storage fix (fixes #171)
## v1.5.13
- Fix for manual caption rendering
@ -182,11 +222,11 @@
## v1.2.3
- Fix for YouTube on iPhone or unsupported browsers (fallback to YouTube native)
- Docs tidy up
- Fullscreen for Safari fix (Fixes #96)
- Fullscreen for Safari fix (fixes #96)
## v1.2.2
- Fix for :focus keyboard vs mouse (Fixes #61)
- Fix for caption positioning in full screen (Fixes #92)
- Fix for :focus keyboard vs mouse (fixes #61)
- Fix for caption positioning in full screen (fixes #92)
## v1.2.1
- Tooltip bug fix
@ -213,7 +253,7 @@
- Bug fix for 1.1.8
## v1.1.8
- setVolume API method improvements (Fixes #83)
- setVolume API method improvements (fixes #83)
## v1.1.7
- Restore classname on destroy()
@ -222,7 +262,7 @@
- New API methods (fixes #77), Fix for non strict mode (fixes #78)
## v1.1.5
- Fix for incorrect `isFullscreen()` return value in Mozilla (Fixes #38)
- Fix for incorrect `isFullscreen()` return value in Mozilla (fixes #38)
## v1.1.4
- Minor bug fixes
@ -246,17 +286,17 @@
- Display duration on `metadataloaded`
## v1.0.30
- Fixed bug with media longer than 60 minutes (Fixes #69)
- Fixed bug with media longer than 60 minutes (fixes #69)
## v1.0.29
- Added option to hide controls on fullscreen (default `true`) while palying, after 1s. Pause, mouse hover on progress, or focus on a child control re-shows the controls. On touch a tap of the video (which plays/pauses the video by default) is required. (Fixes #47)
- Added option to hide controls on fullscreen (default `true`) while palying, after 1s. Pause, mouse hover on progress, or focus on a child control re-shows the controls. On touch a tap of the video (which plays/pauses the video by default) is required. (fixes #47)
- Fixed a bug with caption toggle in 1.0.28
## v1.0.28
- Added API support for browsers that don't have full plyr support (pretty much <=IE9 and `<video>` on iPhone/iPod)
## v1.0.27
- Keyboard accessibility improvements (Fixes #66)
- Keyboard accessibility improvements (fixes #66)
## v1.0.26
- Fixes for SASS (cheers @brunowego)
@ -267,29 +307,29 @@
- Classnames for left/right controls changed
## v1.0.24
- Added tooltip option to display labels as tooltips (Fixes #50)
- Added tooltip option to display labels as tooltips (fixes #50)
## v1.0.23
- Handling loading states in the UI (Fixes #36)
- Handling loading states in the UI (fixes #36)
## v1.0.22
- Added support() API method for checking mimetype support
- Added source() API method for setting media source(s) (Fixes #44)
- Added source() API method for setting media source(s) (fixes #44)
- Added poster() API method for setting poster source
- Refactored captions logic for manual captions
## v1.0.21
- Added an <input type="range"> for seeking to improve experience (and support dragging) (Fixes #40, #42)
- Icons for restart and captions improved (and some IDs changed) (Fixes #49)
- Added an <input type="range"> for seeking to improve experience (and support dragging) (fixes #40, #42)
- Icons for restart and captions improved (and some IDs changed) (fixes #49)
## v1.0.20
- Default controls included (Fixes #45)
- Volume changes on `input` as well as `change` (Fixes #43)
- Volume changes on `input` as well as `change` (fixes #43)
- Fix for undefined Play text
- License changed to MIT
## v1.0.19
- Fixed firefox fullscreen issue (Fixes #38)
- Fixed firefox fullscreen issue (fixes #38)
## v1.0.18
- Added CDN references
@ -313,7 +353,7 @@
- Minor tweaks
## v1.0.12
- Handle native events (Issue #34)
- Handle native events (issue #34)
## v1.0.11
- Bug fixes for fullscreen mode

1
demo/dist/demo.css vendored Normal file

File diff suppressed because one or more lines are too long

1
demo/dist/demo.js vendored Normal file
View File

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

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -11,7 +11,7 @@
<link rel="stylesheet" href="../dist/plyr.css">
<!-- Docs styles -->
<link rel="stylesheet" href="dist/docs.css">
<link rel="stylesheet" href="dist/demo.css">
</head>
<body>
<header>
@ -51,19 +51,17 @@
</ul>
</nav>
<section>
<div class="js-media-player">
<video poster="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg" controls crossorigin>
<!-- Video files -->
<source src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4" type="video/mp4">
<source src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.webm" type="video/webm">
<video poster="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg" controls crossorigin>
<!-- Video files -->
<source src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4" type="video/mp4">
<source src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.webm" type="video/webm">
<!-- Text track file -->
<track kind="captions" label="English" srclang="en" src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt" default>
<!-- Text track file -->
<track kind="captions" label="English" srclang="en" src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt" default>
<!-- Fallback for browsers that don't support the <video> element -->
<a href="https://cdn.selz.com/plyr/1.0/movie.mp4">Download</a>
</video>
</div>
<!-- Fallback for browsers that don't support the <video> element -->
<a href="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4" download>Download</a>
</video>
<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>
@ -74,52 +72,11 @@
</section>
</main>
<!-- Load SVG defs -->
<!-- You should bundle all SVG/Icons into one file using a build tool such as gulp and svg store -->
<script>
(function() {
[
'../dist/plyr.svg',
'dist/docs.svg'
]
.forEach(function(u) {
var x = new XMLHttpRequest(),
b = document.body;
// Check for CORS support
// If you're loading from same domain, you can remove the whole if/else statement
// XHR for Chrome/Firefox/Opera/Safari/IE10+
if ('withCredentials' in x) {
x.open('GET', u, true);
}
// XDomainRequest for IE8 & IE9
else if (typeof XDomainRequest == 'function') {
x = new XDomainRequest();
x.open('GET', u);
}
else { return; }
// Inject hidden div with sprite on load
x.onload = function() {
var c = document.createElement('div');
c.setAttribute('hidden', '');
c.innerHTML = x.responseText;
b.insertBefore(c, b.childNodes[0]);
}
// Timeout for IE9
setTimeout(function () {
x.send();
}, 0);
});
})();
</script>
<!-- Plyr core script -->
<script src="../dist/plyr.js"></script>
<!-- Docs script -->
<script src="dist/docs.js"></script>
<script src="dist/demo.js"></script>
<!-- Rangetouch to fix <input type="range"> on touch devices (see https://rangetouch.com) -->
<script src="https://cdn.rangetouch.com/0.0.9/rangetouch.js"></script>

View File

@ -1,23 +1,32 @@
// ==========================================================================
// Docs example
// Plyr.io demo
// This code is purely for the plyr.io website
// Please see readme.md in the root or github.com/selz/plyr
// ==========================================================================
/*global plyr*/
// Setup the player
plyr.setup('.js-media-player', {
debug: true,
title: 'Video demo',
tooltips: {
controls: true
},
captions: {
defaultActive: true
}
});
// General functions
(function() {
;(function() {
// 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];
// Setup type toggle
var buttons = document.querySelectorAll('[data-source]'),
types = {
video: 'video',
@ -88,9 +97,6 @@ plyr.setup('.js-media-player', {
return;
}
// Get plyr instance
var player = document.querySelector('.js-media-player').plyr;
switch(type) {
case types.video:
player.source({

View File

@ -1,5 +1,5 @@
// ==========================================================================
// HTML5 Video Player Demo Page
// Plyr.io Demo Page
// ==========================================================================
// CSS Reset

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 981 B

After

Width:  |  Height:  |  Size: 981 B

View File

Before

Width:  |  Height:  |  Size: 779 B

After

Width:  |  Height:  |  Size: 779 B

View File

Before

Width:  |  Height:  |  Size: 739 B

After

Width:  |  Height:  |  Size: 739 B

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

1
docs/dist/docs.css vendored

File diff suppressed because one or more lines are too long

1
docs/dist/docs.js vendored
View File

@ -1 +0,0 @@
"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,n=arguments.length;for(i=0;n>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",n=e.Element[i],o=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+/):[],n=0,o=i.length;o>n;n++)this.push(i[n]);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,n=t.length,o=!1;do e=t[i]+"",-1===c(this,e)&&(this.push(e),o=!0);while(++i<n);o&&this._updateClassName()},u.remove=function(){var e,t,i=arguments,n=0,o=i.length,s=!1;do for(e=i[n]+"",t=c(this,e);-1!==t;)this.splice(t,1),s=!0,t=c(this,e);while(++n<o);s&&this._updateClassName()},u.toggle=function(e,t){e+="";var i=this.contains(e),n=i?t!==!0&&"remove":t!==!1&&"add";return n&&this[n](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(n,t,p)}catch(h){-2146823252===h.number&&(p.enumerable=!1,o.defineProperty(n,t,p))}}else o[i].__defineGetter__&&n.__defineGetter__(t,d)}}(self)),plyr.setup(".js-media-player",{debug:!0,title:"Video demo",tooltips:{controls:!0},captions:{defaultActive:!0}}),function(){function e(e,t,i){if(e)if(e.classList)e.classList[i?"add":"remove"](t);else{var n=(" "+e.className+" ").replace(/\s+/g," ").replace(" "+t+" ","");e.className=n+(i?" "+t:"")}}function t(t,s){if(t in n&&(s||t!=o)&&(o.length||t!=n.video)){var r=document.querySelector(".js-media-player").plyr;switch(t){case n.video:r.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:r.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:r.source({type:"video",title:"View From A Blue Moon",sources:[{src:"bTqVqk7FSmY",type:"youtube"}]});break;case n.vimeo:r.source({type:"video",title:"View From A Blue Moon",sources:[{src:"143418951",type:"vimeo"}]})}o=t;for(var a=i.length-1;a>=0;a--)e(i[a].parentElement,"active",!1);e(document.querySelector('[data-source="'+t+'"]').parentElement,"active",!0)}}for(var i=document.querySelectorAll("[data-source]"),n={video:"video",audio:"audio",youtube:"youtube",vimeo:"vimeo"},o=window.location.hash.replace("#",""),s=window.history&&window.history.pushState,r=i.length-1;r>=0;r--)i[r].addEventListener("click",function(){var e=this.getAttribute("data-source");t(e),s&&history.pushState({type:e},"","#"+e)});if(window.addEventListener("popstate",function(e){e.state&&"type"in e.state&&t(e.state.type)}),s){var a=!o.length;a&&(o=n.video),o in n&&history.replaceState({type:o},"",a?"":"#"+o),o!==n.video&&t(o,!0)}}(),document.domain.indexOf("plyr.io")>-1&&(!function(e,t,i,n,o,s,r){e.GoogleAnalyticsObject=o,e[o]=e[o]||function(){(e[o].q=e[o].q||[]).push(arguments)},e[o].l=1*new Date,s=t.createElement(i),r=t.getElementsByTagName(i)[0],s.async=1,s.src=n,r.parentNode.insertBefore(s,r)}(window,document,"script","//www.google-analytics.com/analytics.js","ga"),ga("create","UA-40881672-11","auto"),ga("send","pageview"));

View File

@ -37,19 +37,19 @@ paths = {
// Output paths
output: path.join(root, "dist/")
},
docs: {
demo: {
// Source paths
src: {
less: path.join(root, "docs/src/less/**/*"),
js: path.join(root, "docs/src/js/**/*"),
sprite: path.join(root, "docs/src/sprite/**/*")
less: path.join(root, "demo/src/less/**/*"),
js: path.join(root, "demo/src/js/**/*"),
sprite: path.join(root, "demo/src/sprite/**/*")
},
// Output paths
output: path.join(root, "docs/dist/"),
// Docs
root: path.join(root, "docs/")
output: path.join(root, "demo/dist/"),
// Demo
root: path.join(root, "demo/")
},
upload: [path.join(root, "dist/**"), path.join(root, "docs/dist/**")]
upload: [path.join(root, "dist/**"), path.join(root, "demo/dist/**")]
},
// Task arrays
@ -178,10 +178,10 @@ build.less(bundles.plyr.less, "plyr");
build.scss(bundles.plyr.scss, "plyr");
build.sprite("plyr");
// Docs files
build.less(bundles.docs.less, "docs");
build.js(bundles.docs.js, "docs");
build.sprite("docs");
// Demo files
build.less(bundles.demo.less, "demo");
build.js(bundles.demo.js, "demo");
build.sprite("demo");
// Build all JS
gulp.task("js", function(){
@ -200,10 +200,10 @@ gulp.task("watch", function () {
gulp.watch(paths.plyr.src.less, tasks.less);
gulp.watch(paths.plyr.src.sprite, tasks.sprite);
// Docs
gulp.watch(paths.docs.src.js, tasks.js);
gulp.watch(paths.docs.src.less, tasks.less);
gulp.watch(paths.docs.src.sprite, tasks.sprite);
// Demo
gulp.watch(paths.demo.src.js, tasks.js);
gulp.watch(paths.demo.src.less, tasks.less);
gulp.watch(paths.demo.src.sprite, tasks.sprite);
});
// Default gulp task
@ -211,7 +211,7 @@ gulp.task("default", function(){
run(tasks.js, tasks.less, tasks.sprite, "watch");
});
// Publish a version to CDN and docs
// Publish a version to CDN and demo
// --------------------------------------------
// Some options
@ -225,7 +225,7 @@ options = {
"Vary": "Accept-Encoding"
}
},
docs: {
demo: {
headers: {
"Cache-Control": "no-cache, no-store, must-revalidate, max-age=0",
"Vary": "Accept-Encoding"
@ -264,12 +264,13 @@ gulp.task("cdn", function () {
.pipe(rename(function (path) {
path.dirname = path.dirname.replace(".", version);
}))
.pipe(replace(localPath, versionPath))
.pipe(s3(aws.cdn, options.cdn));
});
// Publish to Docs bucket
gulp.task("docs", function () {
console.log("Uploading " + version + " docs to " + aws.docs.bucket + "...");
// Publish to demo bucket
gulp.task("demo", function () {
console.log("Uploading " + version + " demo to " + aws.demo.bucket + "...");
// Replace versioned files in readme.md
gulp.src([root + "/readme.md"])
@ -279,21 +280,22 @@ gulp.task("docs", function () {
// Replace versioned files in plyr.js
gulp.src(path.join(root, "src/js/plyr.js"))
.pipe(replace(semver, "v" + version))
.pipe(replace(cdnpath, aws.cdn.bucket + "/" + version))
.pipe(gulp.dest(path.join(root, "src/js/")));
// Replace local file paths with remote paths in docs
// Replace local file paths with remote paths in demo HTML
// e.g. "../dist/plyr.js" to "https://cdn.plyr.io/x.x.x/plyr.js"
gulp.src([paths.docs.root + "*.html"])
gulp.src([paths.demo.root + "*.html"])
.pipe(replace(localPath, versionPath))
.pipe(s3(aws.docs, options.docs));
.pipe(s3(aws.demo, options.demo));
// Upload error.html to cdn (as well as docs site)
return gulp.src([paths.docs.root + "error.html"])
// Upload error.html to cdn (as well as demo site)
return gulp.src([paths.demo.root + "error.html"])
.pipe(replace(localPath, versionPath))
.pipe(s3(aws.cdn, options.docs));
.pipe(s3(aws.cdn, options.demo));
});
// Open the docs site to check it's sweet
// Open the demo site to check it's sweet
gulp.task("symlinks", function () {
console.log("Updating symlinks...");
@ -316,20 +318,20 @@ gulp.task("symlinks", function () {
}));
});
// Open the docs site to check it's sweet
// Open the demo site to check it's sweet
gulp.task("open", function () {
console.log("Opening " + aws.docs.bucket + "...");
console.log("Opening " + aws.demo.bucket + "...");
// A file must be specified or gulp will skip the task
// Doesn't matter which file since we set the URL above
// Weird, I know...
return gulp.src([paths.docs.root + "index.html"])
return gulp.src([paths.demo.root + "index.html"])
.pipe(open("", {
url: "http://" + aws.docs.bucket
url: "http://" + aws.demo.bucket
}));
});
// Do everything
gulp.task("publish", function () {
run(tasks.js, tasks.less, tasks.sprite, "cdn", "docs", "symlinks");
run(tasks.js, tasks.less, tasks.sprite, "cdn", "demo", "symlinks");
});

View File

@ -1,6 +1,6 @@
{
"name": "plyr",
"version": "1.6.10",
"version": "1.7.0",
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
"homepage": "http://plyr.io",
"main": "src/js/plyr.js",
@ -38,7 +38,7 @@
"url": "https://github.com/selz/plyr/issues"
},
"directories": {
"doc": "docs"
"doc": "readme.md"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"

239
readme.md
View File

@ -21,6 +21,7 @@ We wanted a lightweight, accessible and customizable media player that supports
- **[Fullscreen](#fullscreen)** - supports native fullscreen with fallback to "full window" modes
- **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
Oh and yes, it works with Bootstrap.
@ -37,22 +38,15 @@ Check out the [changelog](changelog.md) to see what's new with Plyr.
If you have any cool ideas or features, please let me know by [creating an issue](https://github.com/Selz/plyr/issues/new) or, of course, forking and sending a pull request.
## Implementation
Check `docs/index.html` and `docs/dist/docs.js` for an example setup.
## Using package managers
**Heads up:** the example `index.html` file needs to be served from a webserver (such as Apache, Nginx, IIS or similar) unless you change the file sources to include http or https. e.g. change `//cdn.plyr.io/1.6.10/plyr.js` to `https://cdn.plyr.io/1.6.10/plyr.js`
### Node Package Manager (NPM)
Using NPM, you can grab Plyr:
### npm
```
npm install plyr
```
[https://www.npmjs.com/package/plyr](https://www.npmjs.com/package/plyr)
### Bower
If bower is your thang, you can grab Plyr using:
```
bower install plyr
```
@ -67,55 +61,87 @@ ember addon:install ember-cli-plyr
```
More info is on [npm](https://www.npmjs.com/package/ember-cli-plyr) and [GitHub](https://github.com/louisrudner/ember-cli-plyr)
### CDN
If you want to use our CDN, you can use the following:
## Quick setup
Here's a quick run through on getting up and running.
### HTML
Plyr extends upon the standard HTML5 markup so that's all you need for those types.
#### HTML5 Video
```html
<link rel="stylesheet" href="https://cdn.plyr.io/1.6.10/plyr.css">
<script src="https://cdn.plyr.io/1.6.10/plyr.js"></script>
<video poster="/path/to/poster.jpg" controls>
<source src="/path/to/video.mp4" type="video/mp4">
<source src="/path/to/video.webm" type="video/webm">
<!-- Captions are optional -->
<track kind="captions" label="English captions" src="/path/to/captions.vtt" srclang="en" default>
</video>
```
The SVG sprite/defs file can be found here: `https://cdn.plyr.io/1.6.10/plyr.svg`.
### CSS & Styling
If you want to use the default css, add the `plyr.css` file from `/dist` into your head, or even better use `plyr.less` or `plyr.scss` file included in `/src` in your build to save a request.
#### HTML5 Audio
```html
<link rel="stylesheet" href="dist/plyr.css">
<audio controls>
<source src="/path/to/audio.mp3" type="audio/mp3">
<source src="/path/to/audio.ogg" type="audio/ogg">
</audio>
```
The default setup uses the BEM methodology with `plyr` as the block, e.g. `.plyr__controls`. You can change the class hooks in the options. Check out the source for more on this.
For YouTube and Vimeo, Plyr uses the standard YouTube API markup (an empty `<div>`):
#### YouTube embed
```html
<div data-type="youtube" data-video-id="bTqVqk7FSmY"></div>
```
#### Vimeo embed
```html
<div data-type="vimeo" data-video-id="143418951"></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).
```html
<script src="path/to/plyr.js"></script>
<script>plyr.setup();</script>
```
If you want to use our CDN for the JavaScript, you can use the following:
```html
<script src="https://cdn.plyr.io/1.7.0/plyr.js"></script>
```
### CSS
Include the `plyr.css` stylsheet into your `<head>`
```html
<link rel="stylesheet" href="path/to/plyr.css">
```
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.7.0/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.7.0/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.
### SVG
The SVG sprite for the controls icons can be loaded two ways:
- By passing the *relative* path to the sprite as the `iconUrl` option; or
- Using AJAX, injecting the sprite into a hidden div.
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).
#### Using the `iconUrl` option
This method requires the SVG sprite to be hosted on the *same domain* as your page hosting the player. Currently no browser supports cross origin SVG sprites due to XSS issues. Fingers crossed this will come soon though. An example value for this option would be:
```
/path/to/plyr.svg
```
#### Using AJAX
Using AJAX means you can load the sprite from a different origin. Avoiding the issues above. This is an example script to load an SVG sprite best added before the closing `</body>`, before any other scripts.
```html
<script>
(function(d, p){
var a = new XMLHttpRequest(),
b = d.body;
a.open('GET', p, true);
a.send();
a.onload = function() {
var c = d.createElement('div');
c.setAttribute('hidden', '');
c.innerHTML = a.responseText;
b.insertBefore(c, b.childNodes[0]);
};
})(document, 'https://cdn.plyr.io/1.6.10/plyr.svg');
</script>
```
You can however specify your own `iconUrl` option and Plyr will determine if the url is absolute and requires loading by AJAX/CORS due to current browser limitations or if it's a relative path, just use the path directly.
If you're using the `<base>` tag on your site, you may need to use something like this:
[svgfixer.js](https://gist.github.com/leonderijke/c5cf7c5b2e424c0061d2)
@ -125,91 +151,36 @@ More info on SVG sprites here:
and the AJAX technique here:
[http://css-tricks.com/ajaxing-svg-sprite/](http://css-tricks.com/ajaxing-svg-sprite/)
### HTML
The only extra markup that's needed to use plyr is a `<div>` wrapper. Replace the source, poster and captions with urls for your media.
```html
<div class="plyr">
<video poster="/path/to/poster.jpg" controls>
<!-- Video files -->
<source src="/path/to/video.mp4" type="video/mp4">
<source src="/path/to/video.webm" type="video/webm">
<!-- Text track file -->
<track kind="captions" label="English captions" src="/path/to/captions.vtt" srclang="en" default>
<!-- Fallback for browsers that don't support the <video> element -->
<a href="/path/to/movie.mp4">Download</a>
</video>
</div>
```
And the same for `<audio>`
```html
<div class="plyr">
<audio controls>
<!-- Audio files -->
<source src="/path/to/audio.mp3" type="audio/mp3">
<source src="/path/to/audio.ogg" type="audio/ogg">
<!-- Fallback for browsers that don't support the <audio> element -->
<a href="/path/to/audio.mp3">Download</a>
</audio>
</div>
```
For YouTube and Vimeo, Plyr uses the standard YouTube API markup (an empty `<div>`):
```html
<div class="plyr">
<div data-video-id="bTqVqk7FSmY" data-type="youtube"></div>
</div>
```
```html
<div class="plyr">
<div data-video-id="143418951" data-type="vimeo"></div>
</div>
```
#### Cross Origin (CORS)
You'll notice the `crossorigin` attribute on the example `<video>` and `<audio>` elements. This is because the media is loaded from another domain. If your media is hosted on another domain, you may need to add this attribute.
More info on CORS here:
### Cross Origin (CORS)
You'll notice the `crossorigin` attribute on the example `<video>` elements. This is because the TextTrack captions are loaded from another domain. If your TextTrack captions are also hosted on another domain, you will need to add this attribute and make sure your host has the correct headers setup. For more info on CORS checkout the MDN docs:
[https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS)
### Captions
WebVTT captions are supported. To add a caption track, check the HTML example above and look for the `<track>` element.
Be sure to [validate your caption files](https://quuz.org/webvtt/)
WebVTT captions are supported. To add a caption track, check the HTML example above and look for the `<track>` element. Be sure to [validate your caption files](https://quuz.org/webvtt/).
### JavaScript
#### Quick setup
#### Initialising
Here's an example of a default setup:
```html
<script src="https://cdn.plyr.io/1.6.10/plyr.js"></script>
<script>plyr.setup();</script>
```
This will look for all elements with the specified container classname (default is `plyr`) and setup plyr on each element found. You can specify other options, including a different selector hook below. The container classname will be added to the specified element(s) if it is not already present (for the CSS).
By default, Plyr looks for all `<video>`, `<audio>` and `[data-type]` elements and initialises on any found. You can specify other options, including a different selector hook below. The container classname will be added to the specified element(s) if it is not already present (for the CSS).
You can initialize the player a few other ways:
Passing a [NodeList](https://developer.mozilla.org/en-US/docs/Web/API/NodeList):
```javascript
plyr.setup(document.querySelectorAll('.js-plyr'), options);
plyr.setup(document.querySelectorAll('.js-player'), options);
```
Passing a [HTMLElement](https://developer.mozilla.org/en/docs/Web/API/HTMLElement):
```javascript
plyr.setup(document.querySelector('.js-plyr'), options);
plyr.setup(document.querySelector('.js-player'), options);
```
Passing a [string selector](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll):
```javascript
plyr.setup('.js-plyr', options);
plyr.setup('.js-player', options);
```
This can be the target `<video>`, `<audio>` or `[data-type]` elements or a container element.
Passing just the options object:
```javascript
@ -221,7 +192,13 @@ Some touch browsers (particularly Mobile Safari on iOS) seem to have issues with
#### Options
Options must be passed as an object to the `setup()` method as above or as JSON in `data-plyr` attribute on each of your target elements (e.g. data-plyr='{ title: "testing" }') - note the single quotes encapsulating the JSON.
Options must be passed as an object to the `setup()` method as above or as JSON in `data-plyr` attribute on each of your target elements:
```html
<video data-plyr='{ title: "testing" }'></video>
```
Note the single quotes encapsulating the JSON and double quotes on the object keys.
<table class="table" width="100%">
<thead>
@ -258,16 +235,22 @@ Options must be passed as an object to the `setup()` method as above or as JSON
<td>Used for internationalization (i18n) of the tooltips/labels within the buttons.</td>
</tr>
<tr>
<td><code>iconPrefix</code></td>
<td>String</td>
<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 defs file but with the default controls. Most people can ignore this option.</td>
<td><code>loadSprite</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Load the SVG sprite specified as the <code>iconUrl</code> option (if a URL). If <code>false</code>, it is assumed you are handling sprite loading yourself.</td>
</tr>
<tr>
<td><code>iconUrl</code></td>
<td>String</td>
<td><code>null</code></td>
<td>Specify a relative path to the SVG sprite, hosted on the *same domain* as the page the player is hosted on. Using this menthod means no requirement for the AJAX sprite loading script. See the <a href="#svg">SVG section</a> for more info.</td>
<td>Specify a URL or path to the SVG sprite. See the <a href="#svg">SVG section</a> for more info.</td>
</tr>
<tr>
<td><code>iconPrefix</code></td>
<td>String</td>
<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>debug</code></td>
@ -299,6 +282,12 @@ Options must be passed as an object to the `setup()` method as above or as JSON
<td><code>true</code></td>
<td>Click (or tap) of the video container will toggle pause/play.</td>
</tr>
<tr>
<td><code>disableContextMenu</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Disable right click menu on video to <em>help</em> as very primitive obfuscation to prevent downloads of content.</td>
</tr>
<tr>
<td><code>hideControls</code></td>
<td>Boolean</td>
@ -410,19 +399,19 @@ Options must be passed as an object to the `setup()` method as above or as JSON
#### Fetching 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.
There are two ways to access the instance, firstly you re-query the element container you used for setup (e.g. `.js-plyr`) like so:
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:
```javascript
var player = document.querySelector('.js-plyr').plyr;
var player = document.querySelector('.js-player').plyr;
```
Or you can use the returned object from your call to the setup method:
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:
```javascript
var player = plyr.setup('.js-plyr')[0];
var player = plyr.setup('.js-player')[0];
```
This will return an array of plyr instances setup, so you need to specify the index of the instance you want. This is less useful if you are setting up mutliple instances. You can listen for the `setup` [event](#events) documented below which will return each instance one by one, as they are setup (in the `plyr` key of the event object).
This will return an array of plyr instances setup, so you need to specify the index of the instance you want. This is less useful if you are setting up multiple instances. You can listen for the `setup` [event](#events) documented below which will return each instance one by one, as they are setup (in the `plyr` key of the event object).
Once you have your instance, you can use the API methods below on it. For example to pause it:
@ -654,7 +643,7 @@ Some more details on the object parameters
## Events
You can listen for events on the element you setup Plyr on. 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.
<table class="table" width="100%">
<thead>
@ -788,7 +777,7 @@ Details borrowed from: [https://developer.mozilla.org/en-US/docs/Web/Guide/Event
Here's an example of binding an event listener:
```javascript
document.querySelector('.js-plyr').addEventListener('ready', function() {
document.querySelector('.js-plyr').addEventListener('ready', function(event) {
var player = event.target.plyr;
});
```
@ -802,7 +791,7 @@ Plyr references a custom version of the Vimeo Froogaloop API as Vimeo have negle
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() {
document.querySelector('.js-plyr').addEventListener('ready', function(event) {
var player = event.target.plyr;
// YouTube
@ -848,7 +837,7 @@ Fullscreen in Plyr is supported for all browsers that [currently support it](htt
</tbody>
</table>
&sup1; Mobile Safari on the iPhone forces the native player for `<video>` so no useful customisation is possible. `<audio>` elements have volume controls disabled.
&sup1; Mobile Safari on the iPhone forces the native player for `<video>` so no useful customization is possible. `<audio>` elements have volume controls disabled.
&sup2; Native player used (no support for `<progress>` or `<input type="range">`) but the API is supported (v1.0.28+)

View File

@ -1,6 +1,6 @@
// ==========================================================================
// Plyr
// plyr.js v1.6.10
// plyr.js v1.7.0
// https://github.com/selz/plyr
// License: The MIT License (MIT)
// ==========================================================================
@ -26,28 +26,36 @@
/*global YT,$f*/
// Globals
var fullscreen, api = {};
var fullscreen,
scroll = { x: 0, y: 0 },
// Default config
var defaults = {
defaults = {
enabled: true,
debug: false,
autoplay: false,
loop: false,
seekTime: 10,
volume: 5,
volumeMin: 0,
volumeMax: 10,
volumeStep: 1,
duration: null,
displayDuration: true,
loadSprite: true,
iconPrefix: 'plyr',
iconUrl: '',
iconUrl: 'https://cdn.plyr.io/1.7.0/plyr.svg',
clickToPlay: true,
hideControls: true,
showPosterOnEnd: false,
disableContextMenu: true,
tooltips: {
controls: false,
seek: true
},
selectors: {
html5: 'video, audio',
embed: '[data-type]',
container: '.plyr',
controls: {
container: null,
@ -194,7 +202,7 @@
else if ((verOffset=nAgt.indexOf('Safari')) !== -1) {
name = 'Safari';
fullVersion = nAgt.substring(verOffset + 7);
if ((verOffset=nAgt.indexOf('Version')) !== -1) {
if ((verOffset = nAgt.indexOf('Version')) !== -1) {
fullVersion = nAgt.substring(verOffset + 8);
}
}
@ -317,6 +325,8 @@
else {
parent.appendChild(child);
}
return child;
}
}
@ -398,6 +408,17 @@
return false;
}
// Element matches selector
function _matches(element, selector) {
var p = Element.prototype;
var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) {
return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
};
return f.call(element, selector);
}
// Bind event
function _on(element, events, callback, useCapture) {
if (element) {
@ -654,11 +675,20 @@
}
}
// Get icon URL
function _getIconUrl() {
return {
url: config.iconUrl,
external: (config.iconUrl.indexOf("http") === 0)
};
}
// Build the default HTML
function _buildControls() {
// Create html array
var html = [],
iconPath = config.iconUrl + '#' + config.iconPrefix;
var html = [],
iconUrl = _getIconUrl(),
iconPath = (!iconUrl.external ? iconUrl.url : '') + '#' + config.iconPrefix;
// Larger overlaid play button
if (_inArray(config.controls, 'play-large')) {
@ -773,8 +803,8 @@
html.push(
'<span class="plyr__volume">',
'<label for="volume{id}" class="plyr__sr-only">' + config.i18n.volume + '</label>',
'<input id="volume{id}" class="plyr__volume--input" type="range" min="0" max="10" value="5" data-plyr="volume">',
'<progress class="plyr__volume--display" max="10" value="0" role="presentation"></progress>',
'<input id="volume{id}" class="plyr__volume--input" type="range" min="' + config.volumeMin + '" max="' + config.volumeMax + '" value="' + config.volume + '" data-plyr="volume">',
'<progress class="plyr__volume--display" max="' + config.volumeMax + '" value="' + config.volumeMin + '" role="presentation"></progress>',
'</span>'
);
}
@ -1159,6 +1189,20 @@
// Insert controls
function _injectControls() {
// Sprite
if (config.loadSprite) {
var iconUrl = _getIconUrl();
// Only load external sprite using AJAX
if (iconUrl.external) {
_log('Loading external SVG sprite');
loadSprite(iconUrl.url, "sprite-plyr");
}
else {
_log('Sprite will be used inline');
}
}
// Make a copy of the html
var html = config.html;
@ -1390,7 +1434,7 @@
window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];
// Add to queue
window.onYouTubeReadyCallbacks.push(function() { _youTubeReady(mediaId, container) });
window.onYouTubeReadyCallbacks.push(function() { _youTubeReady(mediaId, container); });
// Set callback to process queue
window.onYouTubeIframeAPIReady = function () {
@ -1410,8 +1454,6 @@
_setAttributes(vimeo, {
'src': 'https://player.vimeo.com/video/' + mediaId + '?player_id=' + id + '&api=1&badge=0&byline=0&portrait=0&title=0',
'id': id,
'webkitallowfullscreen': '',
'mozallowfullscreen': '',
'allowfullscreen': '',
'frameborder': 0
});
@ -1610,6 +1652,10 @@
_triggerEvent(plyr.media, 'pause');
break;
}
_triggerEvent(plyr.container, 'statechange', false, {
code: event.data
});
}
}
});
@ -1857,7 +1903,7 @@
// Set the current time
// Try/catch incase the media isn't set and we're calling seek() from source() and IE moans
try {
plyr.media.currentTime = targetTime.toFixed(1);
plyr.media.currentTime = targetTime.toFixed(4);
}
catch(e) {}
@ -1922,6 +1968,19 @@
_toggleControls(plyr.media.paused);
}
// Save scroll position
function _saveScrollPosition() {
scroll = {
x: window.pageXOffset || 0,
y: window.pageYOffset || 0
};
}
// Restore scroll position
function _restoreScrollPosition() {
window.scrollTo(scroll.x, scroll.y);
}
// Toggle fullscreen
function _toggleFullscreen(event) {
// Check for native support
@ -1935,6 +1994,10 @@
else if (nativeSupport) {
// Request fullscreen
if (!fullscreen.isFullScreen(plyr.container)) {
// Save scroll position
_saveScrollPosition();
// Request full screen
fullscreen.requestFullScreen(plyr.container);
}
// Bail from fullscreen
@ -1979,6 +2042,11 @@
// Trigger an event
_triggerEvent(plyr.container, plyr.isFullscreen ? 'enterfullscreen' : 'exitfullscreen');
// Restore scroll position
if (!plyr.isFullscreen && nativeSupport) {
_restoreScrollPosition();
}
}
// Bail from faux-fullscreen
@ -2016,11 +2084,11 @@
break;
case 'vimeo':
plyr.embed.api('setVolume', plyr.media.muted ? 0 : parseFloat(config.volume / 10));
plyr.embed.api('setVolume', plyr.media.muted ? 0 : parseFloat(config.volume / config.volumeMax));
break;
case 'soundcloud':
plyr.embed.setVolume(plyr.media.muted ? 0 : parseFloat(config.volume / 10));
plyr.embed.setVolume(plyr.media.muted ? 0 : parseFloat(config.volume / config.volumeMax));
break;
}
@ -2031,6 +2099,9 @@
// Set volume
function _setVolume(volume) {
var max = config.volumeMax,
min = config.volumeMin;
// Use default if no value specified
if (typeof volume === 'undefined') {
volume = config.volume;
@ -2049,17 +2120,17 @@
volume = config.volume;
}
// Maximum is 10
if (volume > 10) {
volume = 10;
// Maximum is volumeMax
if (volume > max) {
volume = max;
}
// Minimum is 0
if (volume < 0) {
volume = 0;
// Minimum is volumeMin
if (volume < min) {
volume = min;
}
// Set the player volume
plyr.media.volume = parseFloat(volume / 10);
plyr.media.volume = parseFloat(volume / max);
// Set the display
if (plyr.volume.display) {
@ -2093,10 +2164,24 @@
}
}
// Increase volume
function _increaseVolume() {
var volume = plyr.media.muted ? 0 : (plyr.media.volume * config.volumeMax);
_setVolume(volume + (config.volumeStep / 5));
}
// Decrease volume
function _decreaseVolume() {
var volume = plyr.media.muted ? 0 : (plyr.media.volume * config.volumeMax);
_setVolume(volume - (config.volumeStep / 5));
}
// Update volume UI and storage
function _updateVolume() {
// Get the current volume
var volume = plyr.media.muted ? 0 : (plyr.media.volume * 10);
var volume = plyr.media.muted ? 0 : (plyr.media.volume * config.volumeMax);
// Update the <input type="range"> if present
if (plyr.supported.full) {
@ -2221,9 +2306,14 @@
if (typeof value === 'undefined') {
value = 0;
}
// Default to buffer
// Default to buffer or bail
if (typeof progress === 'undefined') {
progress = plyr.progress.buffer;
if (plyr.progress && plyr.progress.buffer) {
progress = plyr.progress.buffer;
}
else {
return;
}
}
// One progress element passed
@ -2403,7 +2493,7 @@
}
}
else {
show = false;
show = !_hasClass(plyr.container, config.classes.hideControls);
}
}
@ -2414,21 +2504,26 @@
if (show || plyr.media.paused) {
_toggleClass(plyr.container, config.classes.hideControls, false);
// Always show controls when paused
// Always show controls when paused or if touch
if (plyr.media.paused) {
return;
}
// Delay for hiding on touch
if (plyr.browser.touch) {
delay = 3000;
}
}
// If toggle is false or if we're playing (regardless of toggle), then
// set the timer to hide the controls
// If toggle is false or if we're playing (regardless of toggle),
// then set the timer to hide the controls
if (!show || !plyr.media.paused) {
plyr.timers.hover = window.setTimeout(function() {
// If the mouse is over the controls (and not entering fullscreen), bail
if (plyr.controls.active && !isEnterFullscreen) {
return;
}
_toggleClass(plyr.container, config.classes.hideControls, true);
}, delay);
}
@ -2525,7 +2620,7 @@
}
// Check for support
plyr.supported = api.supported(plyr.type);
plyr.supported = supported(plyr.type);
// Create new markup
switch(plyr.type) {
@ -2684,6 +2779,7 @@
}
}
}
_on(window, 'keyup', function(event) {
var code = (event.keyCode ? event.keyCode : event.which);
@ -2755,6 +2851,35 @@
// Focus in/out on controls
_on(plyr.controls, 'focus blur', _toggleControls, true);
}
// Adjust volume on scroll
_on(plyr.volume.input, 'wheel', function(event) {
event.preventDefault();
// Detect "natural" scroll - suppored on OS X Safari only
// Other browsers on OS X will be inverted until support improves
var inverted = event.webkitDirectionInvertedFromDevice;
// Scroll down (or up on natural) to decrease
if (event.deltaY < 0 || event.deltaX > 0) {
if (inverted) {
_decreaseVolume();
}
else {
_increaseVolume();
}
}
// Scroll up (or down on natural) to increase
if (event.deltaY > 0 || event.deltaX < 0) {
if (inverted) {
_increaseVolume();
}
else {
_decreaseVolume();
}
}
});
}
// Listen for media events
@ -2818,6 +2943,11 @@
// On click play, pause ore restart
_on(wrapper, 'click', function() {
if (plyr.browser.touch && !plyr.media.paused) {
_toggleControls(true);
return;
}
if (plyr.media.paused) {
_play();
}
@ -2831,6 +2961,11 @@
});
}
// Disable right click
if (config.disableContextMenu) {
_on(plyr.media, 'contextmenu', function(event) { event.preventDefault(); });
}
// Proxy events to container
_on(plyr.media, config.events.join(' '), function(event) {
_triggerEvent(plyr.container, event.type, true);
@ -2925,7 +3060,7 @@
// Get the div placeholder for YouTube and Vimeo
if (!plyr.media) {
plyr.media = plyr.container.querySelectorAll('div')[0];
plyr.media = plyr.container.querySelectorAll('[data-type]')[0];
}
// Bail if nothing to setup
@ -2955,7 +3090,7 @@
}
// Check for support
plyr.supported = api.supported(plyr.type);
plyr.supported = supported(plyr.type);
// Add style hook
_toggleStyleHook();
@ -3085,6 +3220,7 @@
toggleMute: _toggleMute,
toggleCaptions: _toggleCaptions,
toggleFullscreen: _toggleFullscreen,
toggleControls: _toggleControls,
isFullscreen: function() { return plyr.isFullscreen || false; },
support: function(mimeType) { return _supportMime(plyr, mimeType); },
destroy: _destroy,
@ -3092,8 +3228,39 @@
};
}
// Load a sprite
function loadSprite(url, id) {
var x = new XMLHttpRequest();
// If the id is set and sprite exists, bail
if (typeof id === 'string' && document.querySelector('#' + id) !== null) {
return;
}
// Check for CORS support
if ('withCredentials' in x) {
x.open('GET', url, true);
}
else {
return;
}
// Inject hidden div with sprite on load
x.onload = function() {
var c = document.createElement('div');
c.setAttribute('hidden', '');
if (typeof id === 'string') {
c.setAttribute('id', id);
}
c.innerHTML = x.responseText;
document.body.insertBefore(c, document.body.childNodes[0]);
}
x.send();
}
// Check for support
api.supported = function(type) {
function supported(type) {
var browser = _browserSniff(),
oldIE = (browser.name === 'IE' && browser.version <= 9),
iPhone = /iPhone|iPod/i.test(navigator.userAgent),
@ -3128,12 +3295,13 @@
basic: basic,
full: full
};
};
}
// Expose setup function
api.setup = function(elements, options) {
// Setup function
function setup(elements, options) {
// Get the players
var instances = [];
var instances = [],
selector = [defaults.selectors.html5, defaults.selectors.embed].join(',');
// Select the elements
// Assume elements is a NodeList by default
@ -3152,12 +3320,12 @@
}
// Use default selector
elements = document.querySelectorAll(defaults.selectors.container);
elements = document.querySelectorAll(selector);
}
// Bail if disabled or no basic support
// You may want to disable certain UAs etc
if (!api.supported().basic || !elements.length) {
if (!supported().basic || !elements.length) {
return false;
}
@ -3166,14 +3334,23 @@
// Get the current element
var element = elements[i];
// Custom settings passed as data attribute
var settings = element.getAttribute("data-plyr");
// Wrap each media element if needed
if (_matches(element, selector)) {
// Wrap in a <div>
element = _wrap(element, document.createElement('div'));
}
// Setup a player instance and add to the element
if (typeof element.plyr === 'undefined') {
// Create instance-specific config
var config = _extend(defaults, options, JSON.parse(element.getAttribute("data-plyr")));
var config = _extend({}, defaults, options, JSON.parse(settings));
// Bail if not enabled
if (!config.enabled) {
return;
return null;
}
// Create new instance
@ -3191,9 +3368,13 @@
}
return instances;
};
}
return api;
return {
setup: setup,
supported: supported,
loadSprite: loadSprite
};
}));
// Custom event polyfill

View File

@ -20,6 +20,7 @@
max-width: 100%;
min-width: 200px;
font-family: Avenir, "Avenir Next", "Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif;
direction: ltr;
& when (@plyr-border-box = true) {
// border-box everything
@ -177,7 +178,6 @@
padding-bottom: 56.25%; /* 16:9 */
height: 0;
overflow: hidden;
border-radius: inherit;
iframe {
position: absolute;
@ -246,6 +246,11 @@
// Controls
// --------------------------------------------------------------
// Hide native controls
.plyr ::-webkit-media-controls {
display: none;
}
// Playback controls
.plyr__controls {
display: flex;
@ -280,7 +285,7 @@
flex-shrink: 0;
overflow: visible; // IE11
vertical-align: middle;
padding: (@plyr-control-spacing * .7);
padding: @plyr-control-padding;
border: 0;
background: transparent;
border-radius: 3px;
@ -289,8 +294,8 @@
color: inherit;
svg {
width: 18px;
height: 18px;
width: @plyr-control-icon-size;
height: @plyr-control-icon-size;
display: block;
fill: currentColor;
}
@ -375,7 +380,7 @@
border-radius: 100%;
box-shadow: 0 1px 1px fade(@plyr-video-controls-bg, 15%);
color: @plyr-video-control-color;
transition: opacity .3s ease, visibility .3s ease;
transition: all .3s ease;
svg {
position: relative;
@ -480,6 +485,40 @@
z-index: 3;
}
// First tooltip
.plyr__controls button:first-child .plyr__tooltip {
left: 0;
transform: translate(0, 10px) scale(.8);
transform-origin: 0 100%;
&::before {
left: (@plyr-control-icon-size / 2) + @plyr-control-padding;
}
}
// Last tooltip
.plyr__controls button:last-child .plyr__tooltip {
right: 0;
transform: translate(0, 10px) scale(.8);
transform-origin: 100% 100%;
&::before {
left: auto;
right: (@plyr-control-icon-size / 2) + @plyr-control-padding;
transform: translateX(50%);
}
}
.plyr__controls button:first-child,
.plyr__controls button:last-child {
&:hover .plyr__tooltip,
&.tab-focus:focus .plyr__tooltip,
.plyr__tooltip--visible {
transform: translate(0, 0) scale(1);
}
}
// Playback progress
// --------------------------------------------------------------
// <progress> element
@ -699,4 +738,11 @@
left: 0;
right: 0;
}
// Vimeo requires some different styling
&.plyr--vimeo .plyr__video-wrapper {
height: 0;
top: 50%;
transform: translateY(-50%);
}
}

View File

@ -16,14 +16,16 @@
@plyr-font-size-base: 16px;
// Captions
@plyr-captions-bg: fade(#000, 70%);
@plyr-captions-color: #fff;
@plyr-captions-bg: fade(#000, 70%);
@plyr-captions-color: #fff;
@plyr-font-size-captions-base: @plyr-font-size-base;
@plyr-font-size-captions-medium: ceil(@plyr-font-size-base * 1.5);
@plyr-font-size-captions-large: (@plyr-font-size-base * 2);
// Controls
@plyr-control-icon-size: 18px;
@plyr-control-spacing: 10px;
@plyr-control-padding: (@plyr-control-spacing * .7);
@plyr-video-controls-bg: #000;
@plyr-video-control-color: #fff;
@plyr-video-control-color-hover: #fff;
@ -37,7 +39,7 @@
// Tooltips
@plyr-tooltip-bg: fade(#000, 70%);
@plyr-tooltip-color: #fff;
@plyr-tooltip-color: #fff;
@plyr-tooltip-padding: (@plyr-control-spacing / 2);
@plyr-tooltip-arrow-size: 4px;
@plyr-tooltip-radius: 3px;
@ -62,7 +64,7 @@
@plyr-range-thumb-active-scale: 1.25;
@plyr-video-range-track-bg: @plyr-video-progress-buffered-bg;
@plyr-audio-range-track-bg: @plyr-audio-progress-buffered-bg;
@plyr-range-selected-bg: @plyr-color-main;
@plyr-range-selected-bg: @plyr-color-main;
// Breakpoints
@plyr-bp-screen-sm: 480px;

View File

@ -20,6 +20,7 @@
max-width: 100%;
min-width: 200px;
font-family: Avenir, "Avenir Next", "Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif;
direction: ltr;
@if $plyr-border-box == true {
// border-box everything
@ -245,6 +246,11 @@
// Controls
// --------------------------------------------------------------
// Hide native controls
.plyr ::-webkit-media-controls {
display: none;
}
// Playback controls
.plyr__controls {
display: flex;
@ -288,8 +294,8 @@
color: inherit;
svg {
width: 18px;
height: 18px;
width: $plyr-control-icon-size;
height: $plyr-control-icon-size;
display: block;
fill: currentColor;
}
@ -374,7 +380,7 @@
border-radius: 100%;
box-shadow: 0 1px 1px transparentize($plyr-video-controls-bg, .85);
color: $plyr-video-control-color;
transition: opacity .3s ease, visibility .3s ease;
transition: all .3s ease;
svg {
position: relative;
@ -479,6 +485,39 @@
z-index: 3;
}
// First tooltip
.plyr__controls button:first-child .plyr__tooltip {
left: 0;
transform: translate(0, 10px) scale(.8);
transform-origin: 0 100%;
&::before {
left: ($plyr-control-icon-size / 2) + $plyr-control-padding;
}
}
// Last tooltip
.plyr__controls button:last-child .plyr__tooltip {
right: 0;
transform: translate(0, 10px) scale(.8);
transform-origin: 100% 100%;
&::before {
left: auto;
right: ($plyr-control-icon-size / 2) + $plyr-control-padding;
transform: translateX(50%);
}
}
.plyr__controls button:first-child,
.plyr__controls button:last-child {
&:hover .plyr__tooltip,
&.tab-focus:focus .plyr__tooltip,
.plyr__tooltip--visible {
transform: translate(0, 0) scale(1);
}
}
// Playback progress
// --------------------------------------------------------------
// <progress> element
@ -698,4 +737,11 @@
left: 0;
right: 0;
}
// Vimeo requires some different styling
&.plyr--vimeo .plyr__video-wrapper {
height: 0;
top: 50%;
transform: translateY(-50%);
}
}

View File

@ -17,14 +17,16 @@ $plyr-font-size-small: 14px !default;
$plyr-font-size-base: 16px !default;
// Captions
$plyr-captions-bg: transparentize(#000, .3) !default;
$plyr-captions-color: #fff !default;
$plyr-captions-bg: transparentize(#000, .3) !default;
$plyr-captions-color: #fff !default;
$plyr-font-size-captions-base: $plyr-font-size-base !default;
$plyr-font-size-captions-medium: ceil($plyr-font-size-base * 1.5) !default;
$plyr-font-size-captions-large: ($plyr-font-size-base * 2) !default;
// Controls
$plyr-control-icon-size: 18px !default;
$plyr-control-spacing: 10px !default;
$plyr-control-padding: ($plyr-control-spacing * .7) !default;
$plyr-video-controls-bg: #000 !default;
$plyr-video-control-color: #fff !default;
$plyr-video-control-color-hover: #fff !default;
@ -63,7 +65,7 @@ $plyr-range-thumb-active-bg: $plyr-video-control-bg-hover !default;
$plyr-range-thumb-active-scale: 1.25 !default;
$plyr-video-range-track-bg: $plyr-video-progress-buffered-bg !default;
$plyr-audio-range-track-bg: $plyr-audio-progress-buffered-bg !default;
$plyr-range-selected-bg: $plyr-color-main !default;
$plyr-range-selected-bg: $plyr-color-main !default;
// Breakpoints
$plyr-bp-screen-sm: 480px !default;