Compare commits

...

97 Commits

Author SHA1 Message Date
34c9bdc84c Readme 2015-08-08 14:37:28 +10:00
38a206892b YouTube, Captions and Control improvements
- Controls improvements (Fixes #103)
- YouTube bug fixes (Fixes #105)
- Internationalization support (Fixes #101)
- Captions legibility improvements
2015-08-08 14:37:12 +10:00
12a737a49e Merge branch 'master' of github.com:selz/plyr 2015-08-08 11:14:19 +10:00
e7946189c6 Icon updates 2015-08-08 11:14:11 +10:00
850720d8f2 Merge pull request #106 from calvintam236/master
Fixed certain YouTube player issues
2015-08-08 11:13:03 +10:00
b130a13c8a Merge pull request #107 from ChristianPV/patch-1
Update plyr.scss - Make it work V3!
2015-08-07 11:50:01 +10:00
75c090e8b9 Update plyr.scss - Make it work V3! 2015-08-06 14:21:36 -03:00
f983f0771b Revert "Eliminated running try catch when player.type="youtube""
This reverts commit 5fcfd5fa4f.
2015-08-05 20:36:48 -07:00
9f1e5a55f4 Disabled YouTube embed player keyboard control to match with plyr's control 2015-08-05 20:33:04 -07:00
5fcfd5fa4f Eliminated running try catch when player.type="youtube" 2015-08-05 20:09:05 -07:00
e135309670 Fixed youtube video cannot seek before video started with controls 2015-08-05 19:57:24 -07:00
e97b616811 Fixed events are not fired in YouTube embed player 2015-08-05 19:55:30 -07:00
c504ecffe6 Merge pull request #104 from ChristianPV/patch-1
Update plyr.scss - Make it work V2!
2015-08-01 00:35:21 +10:00
9534db823d Update plyr.scss - Make it work V2!
Hi, thanks for accepting my previous pull request. I made this request because the variables control-color and control-color-hover weren't being set inside the mixin so i took them out and it's working now again. I hope you can merge this as it isnt completly working yet and sorry for the delay. Thanks again! :)
2015-07-31 10:59:03 -03:00
1ba1bec066 Merge branch 'master' of github.com:selz/plyr
# Conflicts:
#	src/sass/plyr.scss
2015-07-31 21:34:07 +10:00
aad4a720dc Tooltip fix for NVDA 2015-07-31 21:32:12 +10:00
a978348123 Version bump 2015-07-28 11:31:32 +10:00
00cf797c20 Restored !default and fullscreen logic in SASS 2015-07-28 11:29:49 +10:00
6b0f58dab2 Merge pull request #102 from ChristianPV/patch-1
Update plyr.scss - Make it work
2015-07-28 10:13:47 +10:00
04cf5dfda1 Update plyr.scss - Make it work
There were some things that needed to be changed for the sass preprocessor to work. There were some variables declared as @ that need to be declared with the right syntax: $. Also sass evaluation is eager, while less evaluation is _lazy_ that means in sass, mixins should be declared before they are use. I hope you can accept this change as it's currently not working. Thanks!
2015-07-27 13:04:02 -03:00
fe1989dea1 gulp 2015-07-25 22:06:13 +10:00
5d19b43888 Tooltip tweak 2015-07-25 21:35:12 +10:00
06ed345f29 YouTube quality tweak 2015-07-25 21:11:17 +10:00
e0cd34c996 Fix for omitted kind attribute on <track> (fixes #88) 2015-07-25 20:45:11 +10:00
06641d5709 Docs 2015-07-25 20:29:54 +10:00
a0d2d5cd24 Minor tweaks 2015-07-25 20:29:19 +10:00
e9cdbfb8da Safari fix (fixes #96), YouTube tweaks, docs 2015-07-25 19:51:32 +10:00
df64fdac9e Tab focus and caption position fixes (fixes #61, fixes #92) 2015-07-25 18:30:47 +10:00
4dbbbd04cc Merge pull request #99 from ChristianPV/patch-1
Update bower.json - fix sass file name
2015-07-25 10:59:56 +10:00
c9c3ee9014 Update bower.json - fix sass file name
I installed this package with bower and encountered an error while checking for existence of main bower files. I changed the filename to the correct one. Please take a look. Thanks!
2015-07-24 11:51:16 -03:00
67191c2a75 Merge branch 'master' of github.com:selz/plyr 2015-07-22 11:36:35 +10:00
8ba4522b3e Docs 2015-07-22 11:36:24 +10:00
52eaf62b58 Update readme.md 2015-07-21 12:30:41 +10:00
8d43f412ac Docs CSS 2015-07-21 10:48:31 +10:00
e9ea90f527 Update readme.md 2015-07-21 10:38:48 +10:00
5dc0d84300 Version bump 2015-07-21 08:51:44 +10:00
ec8923ef08 Merge branch 'master' of github.com:selz/plyr 2015-07-21 08:51:25 +10:00
5a414572f9 Tooltip fix (Fixes #97) 2015-07-21 08:51:14 +10:00
7f40307b0a Update readme.md 2015-07-20 23:11:11 +10:00
a12485d10f Update readme.md 2015-07-20 23:09:57 +10:00
4695bbf483 Merge branch 'master' of github.com:selz/plyr 2015-07-20 23:04:13 +10:00
20ee77a55e Docs tweak 2015-07-20 23:03:24 +10:00
78a0ac8674 Update readme.md 2015-07-20 22:51:33 +10:00
e49c417e54 Version bump 2015-07-20 22:32:29 +10:00
b39961ec49 Tidying 2015-07-20 22:28:27 +10:00
8894b4c7b9 Merge branch 'master' into develop
# Conflicts:
#	changelog.md
#	dist/plyr.js
2015-07-20 22:25:31 +10:00
cdf3deb458 YouTube playback, docs update 2015-07-20 22:24:06 +10:00
b5fc21239b Version bump 2015-07-20 14:45:32 +10:00
93cc9edd9a Added icon prefix option for when using default controls 2015-07-20 14:44:51 +10:00
dcd9ca3a93 Started on source swap 2015-07-12 23:57:36 +10:00
c202cc1ffb More work on YouTube 2015-07-12 23:41:56 +10:00
093af22942 More work on YouTube playback 2015-07-12 21:17:56 +10:00
9d966e41b1 Built 2015-06-27 16:21:54 +10:00
240aa7aa5f Merge branch 'master' into develop
# Conflicts:
#	dist/plyr.css
#	dist/plyr.js
2015-06-27 16:21:38 +10:00
654e9cd623 Docs tweaks 2015-06-08 22:12:08 +10:00
73c3888309 Removed log 2015-06-08 21:50:04 +10:00
4f0633fdc1 SASS for previous change 2015-06-08 21:46:47 +10:00
f41854ebe7 Minor tweak to hiding controls in fullscreen 2015-06-08 21:43:49 +10:00
f398266206 Chrome Canary Fix 2015-06-07 23:20:33 +10:00
4c17f98520 TogglePlay API method (Fixes #86), Volume border (Fixes #87), Chrome Subs (Fixes #90) 2015-06-07 23:00:26 +10:00
398815857f Merge branch 'develop' of github.com:selz/plyr into develop
# Conflicts:
#	.gitignore
2015-05-23 19:58:53 +10:00
4c5020a396 Ignore test video 2015-05-23 19:58:06 +10:00
df84ce6e90 Docs 2015-05-18 15:11:16 +10:00
7161378da1 Bug fix 2015-05-18 15:10:40 +10:00
224b612ae7 Bug fix 2015-05-18 14:46:21 +10:00
19d7522722 Fixes bug with 1.1.8 volume 2015-05-18 14:43:45 +10:00
ceace2a678 setVolume() API method improvements (Fixes #83) 2015-05-18 13:50:44 +10:00
d627454b2a Restore classname on destroy 2015-05-17 17:33:46 +10:00
7ccbfad6ad New API methods (fixes #77), Fix for non strict mode (fixes #78) 2015-05-17 17:23:09 +10:00
91f8a158d2 Update index.html 2015-04-19 23:47:46 +10:00
8925dcde01 Update readme.md 2015-04-19 23:45:25 +10:00
3d1a586314 Working on YouTube playback 2015-04-15 23:50:03 +10:00
d04b278802 Merge branch 'master' into develop
# Conflicts:
#	src/js/plyr.js
2015-04-15 21:51:59 +10:00
7345f656c1 Started on plugin setup 2015-04-15 21:47:50 +10:00
530abac3a7 Update readme.md 2015-04-15 01:15:05 +10:00
e702d9a881 Update readme.md 2015-04-15 01:14:36 +10:00
b0aeccb793 Update readme.md 2015-04-11 11:19:19 +10:00
43d8d748ce Merge pull request #76 from robinpoort/feature/sass-variables
Make SCSS variables optional
2015-04-11 09:29:04 +10:00
b43ea5c7d3 adding !default to variables so they are easily overwritable 2015-04-10 15:13:02 +02:00
f56759222d Update readme.md 2015-04-10 13:38:49 +10:00
c8b7bb570c Update readme.md 2015-04-10 13:37:55 +10:00
d536b29550 Update readme.md 2015-04-10 13:36:51 +10:00
ecbda018c5 Merge branch 'master' of github.com:selz/plyr
# Conflicts:
#	src/js/plyr.js
2015-04-10 07:17:23 +10:00
5187311ff0 Bug fix for isFullscreen() in Mozilla (Fixes #38) 2015-04-10 07:16:53 +10:00
d9a94ac7b0 Version bump 2015-04-08 13:42:34 +10:00
3526e322ef Minor bug fixes 2015-04-06 19:42:26 +10:00
99cabd545d Fix for generated IDs for controls, UI tweak for audio 2015-04-06 13:25:36 +10:00
1f7f7b10de Docs tweak 2015-04-06 12:06:34 +10:00
b2421b592a Merge branch 'master' of github.com:selz/plyr 2015-04-06 11:47:43 +10:00
5322f4c62f Fullscreen API methods (Fixes #74), onSetup callback 2015-04-06 11:47:23 +10:00
7ab8647fc8 Merge pull request #75 from franks921/fs-fix-localstorage-volume-settings
fix: use custom localStorage key for volume setting
2015-04-05 21:39:08 +10:00
50c76f3d7e fix: use custom localStorage key for volume setting 2015-04-05 13:26:17 +02:00
2f4c56176d Updated screenshot 2015-04-04 12:58:09 +11:00
7c5f38311b Bug fixes for controls changes 2015-04-04 12:51:24 +11:00
e568bc9c8d Controls improvements
- Added an option to toggle which controls display
- Better handle missing controls
2015-04-04 12:32:37 +11:00
c2c4172634 Clarified the option 2015-03-30 21:04:38 +11:00
73de5b5773 Added displayDuration option, small bug fix
- Using the native VTT cues, sometimes cues would not disappear
2015-03-30 21:03:48 +11:00
44 changed files with 2386 additions and 907 deletions

2
.gitignore vendored
View File

@ -4,4 +4,4 @@ node_modules
.DS_Store
aws.json
docs/index.dev.html
*.mp4
*.mp4

View File

@ -17,7 +17,7 @@
"dist/plyr.js",
"dist/sprite.svg",
"src/less/plyr.less",
"src/sass/plyr.sass",
"src/sass/plyr.scss",
"src/js/plyr.js"
],
"ignore": [
@ -30,4 +30,4 @@
"url": "git://github.com/selz/plyr.git"
},
"license": "MIT"
}
}

View File

@ -17,6 +17,7 @@
"js": {
"docs.js": [
"docs/src/js/lib/hogan-3.0.2.mustache.js",
"docs/src/js/lib/classlist.js",
"docs/dist/templates.js",
"docs/src/js/docs.js"
]

View File

@ -1,5 +1,86 @@
# Changelog
# v1.3.0
- Internationalization support (i18n) using default controls (required markup changes to controls)
- ARIA enhancements for controls (required markup changes to controls)
- Captions legibility improvements
- YouTube bug fixes
## v1.2.6
- SASS updates and fixes (cheers @ChristianPV)
## v1.2.5
- Fix for YouTube quality (let them decide quality)
## v1.2.4
- Fix for omitted kind attribute on <track> (fixes #88)
## v1.2.3
- Fix for YouTube on iPhone or unsupported browsers (fallback to YouTube native)
- Docs tidy up
- 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)
## v1.2.1
- Tooltip bug fix
# v1.2.0
- Added YouTube support
## v1.1.13
- Added icon prefix option for when using default controls
## v1.1.13
- Logic tweaks for hiding controls in fullscreen
## v1.1.12
- Bug fix for Chrome Canary
## v1.1.11
- Bug fix
## v1.1.10
- Bug fix
## v1.1.9
- Bug fix for 1.1.8
## v1.1.8
- setVolume API method improvements (Fixes #83)
## v1.1.7
- Restore classname on destroy()
## v1.1.6
- 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)
## v1.1.4
- Minor bug fixes
## v1.1.3
- Fixes for random id used in controls with multiple instances and one call to setup
- Audio player UI improvements
## v1.1.2
- Added an onSetup callback option
- Added fullscreen API methods `toggleFullscreen()` (must be user iniated), and `isFullscreen()`
## v1.1.1
- Fix for unsupported browser handling
- Fix for config.controls having no effect
## v1.1.0
- Added config option to set which controls are shown (if using the default controls html) and better handling of missing controls
## v1.0.31
- Display duration on `metadataloaded`
## v1.0.30
- Fixed bug with media longer than 60 minutes (Fixes #69)
@ -110,4 +191,4 @@
- Return instances of Plyr to the element
## v1.0.0
- Initial release
- Initial release

View File

@ -1,10 +1,36 @@
# Controls HTML
# Controls
This is the markup that is rendered for the Plyr controls. You can use the default controls or provide a customized version of markup based on your needs.
The demo Plyr setup uses a Hogan template. This purely to allow for localization at a later date. Check out `controls.html` in `/src/templates` to get an idea of how the default html is structured. Alternatively check out the `plyr.js` source.
## Internationalization using default controls
## Requirements
You can provide an `i18n` object as one of your options when initialising the plugin which we be used when rendering the controls.
### Example
```javascript
i18n: {
restart: "Restart",
rewind: "Rewind {seektime} secs",
play: "Play",
pause: "Pause",
forward: "Forward {seektime} secs",
played: "played",
buffered: "buffered",
currentTime: "Current time",
duration: "Duration",
volume: "Volume",
toggleMute: "Toggle Mute",
toggleCaptions: "Toggle Captions",
toggleFullscreen: "Toggle Fullscreen"
}
```
Note: `{seektime}` will be replaced with your configured seek time or the default. For example "Forward {seektime} secs" would render as "Forward 10 secs".
## Using custom HTML
The example on [plyr.io](http://plyr.io) setup uses a Hogan template. Check out `controls.html` in `/src/templates` to get an idea of how the default html is structured.
The classes and data attributes used in your template should match the `selectors` option.
@ -13,11 +39,11 @@ You need to add several placeholders to your html template that are replaced whe
- `{id}` - the dynamically generated ID for the player (for form controls)
- `{seektime}` - the seek time specified in options for fast forward and rewind
Currently all buttons and inputs need to be present for Plyr to work but later we'll make it more dynamic so if you omit a button or input, it'll still work.
You can include only the controls you need when specifying custom html.
## Default
### Example
This is the default `html` option from `plyr.js`.
This is an example `html` option with all controls.
```javascript
["<div class='player-controls'>",
@ -53,25 +79,27 @@ This is the default `html` option from `plyr.js`.
"<span class='sr-only'>Forward {seektime} secs</span>",
"</button>",
"<span class='player-time'>",
"<span class='sr-only'>Time</span>",
"<span class='sr-only'>Current time</span>",
"<span class='player-current-time'>00:00</span>",
"</span>",
"<span class='player-time'>",
"<span class='sr-only'>Duration</span>",
"<span class='player-duration'>00:00</span>",
"</span>",
"</span>",
"<span class='player-controls-right'>",
"<input class='inverted sr-only' id='mute{id}' type='checkbox' data-player='mute'>",
"<label id='mute{id}' for='mute{id}'>",
"<button type="button" data-player="mute">",
"<svg class='icon-muted'><use xlink:href='#icon-muted'></use></svg>",
"<svg><use xlink:href='#icon-volume'></use></svg>",
"<span class='sr-only'>Toggle Mute</span>",
"</label>",
"</button>",
"<label for='volume{id}' class='sr-only'>Volume</label>",
"<input id='volume{id}' class='player-volume' type='range' min='0' max='10' value='5' data-player='volume'>",
"<input class='sr-only' id='captions{id}' type='checkbox' data-player='captions'>",
"<label for='captions{id}'>",
"<button type="button" data-player="captions">",
"<svg class='icon-captions-on'><use xlink:href='#icon-captions-on'></use></svg>",
"<svg><use xlink:href='#icon-captions-off'></use></svg>",
"<span class='sr-only'>Toggle Captions</span>",
"</label>",
"</button>",
"<button type='button' data-player='fullscreen'>",
"<svg class='icon-exit-fullscreen'><use xlink:href='#icon-exit-fullscreen'></use></svg>",
"<svg><use xlink:href='#icon-enter-fullscreen'></use></svg>",

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

2
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

2
dist/sprite.svg vendored

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

2
docs/dist/docs.css vendored

File diff suppressed because one or more lines are too long

2
docs/dist/docs.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
var templates = {};
templates['controls'] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div class=\"player-controls\">");t.b("\n" + i);t.b(" <div class=\"player-progress\">");t.b("\n" + i);t.b(" <label for=\"seek{id}\" class=\"sr-only\">Seek</label>");t.b("\n" + i);t.b(" <input id=\"seek{id}\" class=\"player-progress-seek\" type=\"range\" min=\"0\" max=\"100\" step=\"0.5\" value=\"0\" data-player=\"seek\">");t.b("\n" + i);t.b(" <progress class=\"player-progress-played\" max=\"100\" value=\"0\">");t.b("\n" + i);t.b(" <span>0</span>% played");t.b("\n" + i);t.b(" </progress>");t.b("\n" + i);t.b(" <progress class=\"player-progress-buffer\" max=\"100\" value=\"0\">");t.b("\n" + i);t.b(" <span>0</span>% buffered");t.b("\n" + i);t.b(" </progress>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" <span class=\"player-controls-left\">");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"restart\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-restart\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Restart</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"rewind\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-rewind\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Rewind {seektime} secs</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"play\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-play\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Play</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"pause\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-pause\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Pause</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"fast-forward\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-fast-forward\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Forward {seektime} secs</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <span class=\"player-time\">");t.b("\n" + i);t.b(" <span class=\"sr-only\">Time</span>");t.b("\n" + i);t.b(" <span class=\"player-duration\">00:00</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" <span class=\"player-controls-right\">");t.b("\n" + i);t.b(" <input class=\"inverted sr-only\" id=\"mute{id}\" type=\"checkbox\" data-player=\"mute\">");t.b("\n" + i);t.b(" <label id=\"mute{id}\" for=\"mute{id}\">");t.b("\n" + i);t.b(" <svg class=\"icon-muted\"><use xlink:href=\"#icon-muted\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-volume\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle Mute</span>");t.b("\n" + i);t.b(" </label>");t.b("\n");t.b("\n" + i);t.b(" <label for=\"volume{id}\" class=\"sr-only\">Volume</label>");t.b("\n" + i);t.b(" <input id=\"volume{id}\" class=\"player-volume\" type=\"range\" min=\"0\" max=\"10\" step=\"0.5\" value=\"0\" data-player=\"volume\">");t.b("\n");t.b("\n" + i);t.b(" <input class=\"sr-only\" id=\"captions{id}\" type=\"checkbox\" data-player=\"captions\">");t.b("\n" + i);t.b(" <label for=\"captions{id}\">");t.b("\n" + i);t.b(" <svg class=\"icon-captions-on\"><use xlink:href=\"#icon-captions-on\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-captions-off\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle Captions</span>");t.b("\n" + i);t.b(" </label>");t.b("\n");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"fullscreen\">");t.b("\n" + i);t.b(" <svg class=\"icon-exit-fullscreen\"><use xlink:href=\"#icon-exit-fullscreen\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-enter-fullscreen\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle Fullscreen</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b("</div>");return t.fl(); },partials: {}, subs: { }});
templates['controls'] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div class=\"player-controls\">");t.b("\n" + i);t.b(" <div class=\"player-progress\">");t.b("\n" + i);t.b(" <label for=\"seek{id}\" class=\"sr-only\">Seek</label>");t.b("\n" + i);t.b(" <input id=\"seek{id}\" class=\"player-progress-seek\" type=\"range\" min=\"0\" max=\"100\" step=\"0.5\" value=\"0\" data-player=\"seek\">");t.b("\n" + i);t.b(" <progress class=\"player-progress-played\" max=\"100\" value=\"0\">");t.b("\n" + i);t.b(" <span>0</span>% played");t.b("\n" + i);t.b(" </progress>");t.b("\n" + i);t.b(" <progress class=\"player-progress-buffer\" max=\"100\" value=\"0\">");t.b("\n" + i);t.b(" <span>0</span>% buffered");t.b("\n" + i);t.b(" </progress>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" <span class=\"player-controls-left\">");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"restart\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-restart\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Restart</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"rewind\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-rewind\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Rewind {seektime} secs</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"play\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-play\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Play</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"pause\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-pause\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Pause</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"fast-forward\">");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-fast-forward\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Forward {seektime} secs</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <span class=\"player-time\">");t.b("\n" + i);t.b(" <span class=\"sr-only\">Current time</span>");t.b("\n" + i);t.b(" <span class=\"player-current-time\">00:00</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" <span class=\"player-time\">");t.b("\n" + i);t.b(" <span class=\"sr-only\">Duration</span>");t.b("\n" + i);t.b(" <span class=\"player-duration\">00:00</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" <span class=\"player-controls-right\">");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"mute\">");t.b("\n" + i);t.b(" <svg class=\"icon-muted\"><use xlink:href=\"#icon-muted\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-volume\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle Mute</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <label for=\"volume{id}\" class=\"sr-only\">Volume</label>");t.b("\n" + i);t.b(" <input id=\"volume{id}\" class=\"player-volume\" type=\"range\" min=\"0\" max=\"10\" step=\"0.5\" value=\"0\" data-player=\"volume\">");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"captions\">");t.b("\n" + i);t.b(" <svg class=\"icon-captions-on\"><use xlink:href=\"#icon-captions-on\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-captions-off\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle Captions</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" <button type=\"button\" data-player=\"fullscreen\">");t.b("\n" + i);t.b(" <svg class=\"icon-exit-fullscreen\"><use xlink:href=\"#icon-exit-fullscreen\"></use></svg>");t.b("\n" + i);t.b(" <svg><use xlink:href=\"#icon-enter-fullscreen\"></use></svg>");t.b("\n" + i);t.b(" <span class=\"sr-only\">Toggle Fullscreen</span>");t.b("\n" + i);t.b(" </button>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b("</div>");return t.fl(); },partials: {}, subs: { }});

View File

@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Docs styles -->
<link rel="stylesheet" href="//cdn.plyr.io/1.0.30/docs.css">
<link rel="stylesheet" href="//cdn.plyr.io/1.3.0/docs.css">
</head>
<body>
<main>

View File

@ -8,62 +8,76 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Styles -->
<link rel="stylesheet" href="//cdn.plyr.io/1.0.30/plyr.css">
<link rel="stylesheet" href="https://cdn.plyr.io/1.3.0/plyr.css?3">
<!-- Docs styles -->
<link rel="stylesheet" href="//cdn.plyr.io/1.0.30/docs.css">
<link rel="stylesheet" href="https://cdn.plyr.io/1.3.0/docs.css?1">
</head>
<body>
<header>
<h1>Plyr</h1>
<p>A simple HTML5 media player with custom controls and WebVTT captions.</p>
<a href="https://github.com/selz/plyr" target="_blank" class="btn">Download on GitHub</a>
<p>A simple HTML5 media player with custom controls and WebVTT captions by <a href="https://twitter.com/sam_potts" target="_blank">@sam_potts</a></p>
<nav>
<ul>
<li>
<a href="https://github.com/selz/plyr" target="_blank" class="btn btn-primary">Download on GitHub</a>
<span class="btn-count js-stargazers-count">&hellip;</span>
</li>
<li>
<a href="https://twitter.com/intent/tweet?text=A+simple+HTML5+media+player+with+custom+controls+and+WebVTT+captions.&url=http%3A%2F%2Fplyr.io&via=Sam_Potts" target="_blank" class="btn js-popup" data-window-height="250" data-window-width="500">Tweet</a>
<span class="btn-count js-tweet-count">&hellip;</span>
</li>
</ul>
</nav>
</header>
<main>
<section class="example-video">
<div class="player">
<video poster="//cdn.selz.com/plyr/1.0/poster.jpg" controls crossorigin>
<!-- Video files -->
<source src="//cdn.selz.com/plyr/1.0/movie.mp4" type="video/mp4">
<source src="//cdn.selz.com/plyr/1.0/movie.webm" type="video/webm">
<!-- Text track file -->
<track kind="captions" label="English" srclang="en" src="//cdn.selz.com/plyr/1.0/en.vtt" default>
<!-- Fallback for browsers that don't support the <video> element -->
<div>
<a href="//cdn.selz.com/plyr/1.0/movie.mp4">Download</a>
</div>
</video>
</div>
<small>Big Buck Bunny. More info can be found at <a href="https://peach.blender.org" target="_blank">peach.blender.org</a>.</small>
</section>
<section class="example-audio">
<div class="player">
<audio controls>
<!-- Audio files -->
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3" type="audio/mp3">
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.ogg" type="audio/ogg">
<!-- Fallback for browsers that don't support the <audio> element -->
<div>
<main role="main" id="main">
<nav class="btn-bar nav-panel">
<ul>
<li><a href="#video" class="btn active btn-small">Video</a></li>
<li><a href="#youtube" class="btn btn-small">YouTube</a></li>
<li><a href="#audio" class="btn btn-small">Audio</a></li>
</ul>
</nav>
<div class="panels">
<section class="panel example-video active" id="video">
<div class="player">
<video poster="https://cdn.plyr.io/static/poster.jpg" controls crossorigin>
<!-- Video files -->
<source src="https://cdn.selz.com/plyr/1.0/movie.mp4" type="video/mp4">
<source src="https://cdn.selz.com/plyr/1.0/movie.webm" type="video/webm">
<!-- Text track file -->
<track kind="captions" label="English" srclang="en" src="https://cdn.selz.com/plyr/1.0/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>
<small>Big Buck Bunny. More info can be found at <a href="https://peach.blender.org" target="_blank">peach.blender.org</a>.</small>
</section>
<section class="panel example-video" id="youtube">
<div class="player">
<div data-video-id="Au87oAJ2jeE" data-type="youtube"></div>
</div>
<small>Envato's "Made By" interview of <a href="https://www.youtube.com/watch?v=Au87oAJ2jeE" target="_blank">Dan Cederholm</a> from <a href="https://dribbble.com" target="_blank">Dribbble</a>.</small>
</section>
<section class="panel example-audio" id="audio">
<div class="player">
<audio controls>
<!-- Audio files -->
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3" type="audio/mp3">
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.ogg" type="audio/ogg">
<!-- Fallback for browsers that don't support the <audio> element -->
<a href="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3">Download</a>
</div>
</audio>
</div>
<small>"96" by Logistics, which can be purchased from <a href="https://www.hospitalrecords.com/shop/artist/logistics" target="_blank">Hospital Records</a>.</small>
</section>
</audio>
</div>
<small>"96" by Logistics, which can be purchased from <a href="https://www.hospitalrecords.com/shop/artist/logistics" target="_blank">Hospital Records</a>.</small>
</section>
</div>
</main>
<footer>
<p>Used by &hellip;</p>
<a href="https://selz.com" target="_blank" class="logo">
<img src="https://d33i624pw6jj68.cloudfront.net/static/img/logos/selz.svg" alt="Selz">
</a>
</footer>
<!-- Load SVG defs -->
<!-- You should bundle all SVG/Icons into one file using a build tool such as gulp and svg store -->
<script>
@ -78,18 +92,18 @@
a.send();
a.onload = function(){
var c = d.createElement("div");
c.style.display="none";
c.setAttribute("hidden", "");
c.innerHTML = a.responseText;
b.insertBefore(c, b.childNodes[0]);
}
}
})(document, "https://cdn.plyr.io/1.0.30/sprite.svg");
})(document, "https://cdn.plyr.io/1.3.0/sprite.svg");
</script>
<!-- Plyr core script -->
<script src="//cdn.plyr.io/1.0.30/plyr.js"></script>
<script src="https://cdn.plyr.io/1.3.0/plyr.js?1"></script>
<!-- Docs script -->
<script src="//cdn.plyr.io/1.0.30/docs.js"></script>
<script src="https://cdn.plyr.io/1.3.0/docs.js?1"></script>
</body>
</html>
</html>

View File

@ -7,13 +7,170 @@
// Setup the player
plyr.setup({
debug: true,
volume: 9,
title: "Video demo",
html: templates.controls.render({}),
tooltips: true,
captions: {
defaultActive: true
},
onSetup: function() {
if(!("media" in this)) {
return;
}
var player = this,
type = player.media.tagName.toLowerCase(),
toggle = document.querySelector("[data-toggle='fullscreen']");
console.log("✓ Setup done for <" + type + ">");
if(type === "video" && toggle) {
toggle.addEventListener("click", player.toggleFullscreen, false);
}
}
});
// General functions
(function() {
// Popup
function popup(event) {
// Prevent the link opening
if(event.target.nodeName.toLowerCase() == "a") {
if(event.preventDefault) {
event.preventDefault();
}
else {
event.returnValue = false;
}
}
var link = event.target,
url = link.href,
width = link.getAttribute("data-window-width") || 600,
height = link.getAttribute("data-window-height") || 600,
name = link.getAttribute("data-window-name") || "popup";
// If window exists, just focus it
if(window["window-"+name] && !window["window-"+name].closed) {
window["window-"+name].focus();
}
else {
// Get position
var left = window.screenLeft !== undefined ? window.screenLeft : screen.left;
var top = window.screenTop !== undefined ? window.screenTop : screen.top;
// Open in the centre of the screen
var x = (screen.width / 2) - (width / 2) + left,
y = (screen.height / 2) - (height / 2) + top;
// Open that window
window["window-"+name] = window.open(url, name, "top=" + y +",left="+ x +",width=" + width + ",height=" + height);
// Focus new window
window["window-"+name].focus();
}
}
// Trigger popups
document.querySelector(".js-popup").addEventListener("click", popup);
// Get JSONP
function getJSONP(url, callback) {
var name = "jsonp_callback_" + Math.round(100000 * Math.random());
// Cleanup to prevent memory leaks and hit original callback
window[name] = function(data) {
delete window[name];
document.body.removeChild(script);
callback(data);
};
// Create a faux script
var script = document.createElement("script");
script.setAttribute("src", url + (url.indexOf("?") >= 0 ? "&" : "?") + "callback=" + name);
// Inject to the body
document.body.appendChild(script);
}
// Get star count
var storageSupported = ("sessionStorage" in window),
selectors = {
github: ".js-stargazers-count",
twitter: ".js-tweet-count"
};
// Display the count next to the button
function displayCount(selector, count) {
document.querySelector(selector).innerHTML = count;
}
// Add star
function formatGitHubCount(count) {
return "&#9733; " + count;
}
// Check if it's in session storage first
if(storageSupported && "github_stargazers" in window.sessionStorage) {
displayCount(selectors.github, formatGitHubCount(window.sessionStorage.github_stargazers));
}
else {
getJSONP("https://api.github.com/repos/selz/plyr?access_token=a46ac653210ba6a6be44260c29c333470c3fbbf5", function (json) {
if (json && typeof json.data.stargazers_count !== "undefined") {
// Update UI
displayCount(selectors.github, formatGitHubCount(json.data.stargazers_count));
// Store in session storage
window.sessionStorage.github_stargazers = json.data.stargazers_count;
}
});
}
// Get tweet count
if(storageSupported && "tweets" in window.sessionStorage) {
displayCount(selectors.twitter, window.sessionStorage.tweets);
}
else {
getJSONP("https://cdn.api.twitter.com/1/urls/count.json?url=plyr.io", function (json) {
if (json && typeof json.count !== "undefined") {
// Update UI
displayCount(selectors.twitter, json.count);
// Store in session storage
window.sessionStorage.tweets = json.count;
}
});
}
// Tabs
var tabs = document.querySelectorAll(".nav-panel a"),
panels = document.querySelectorAll(".panels > .panel"),
activeClass = "active";
for (var i = tabs.length - 1; i >= 0; i--) {
tabs[i].addEventListener("click", togglePanel);
}
function togglePanel(event) {
event.preventDefault();
var tab = event.target,
panel = document.querySelector(tab.getAttribute("href"));
for (var i = panels.length - 1; i >= 0; i--) {
panels[i].classList.remove(activeClass);
}
for (var x = tabs.length - 1; x >= 0; x--) {
tabs[x].classList.remove(activeClass);
}
panel.classList.add(activeClass);
event.target.classList.add(activeClass);
}
})();
// Google analytics
// For demo site (http://[www.]plyr.io) only
if(document.domain.indexOf("plyr.io") > -1) {

View File

@ -0,0 +1,237 @@
/*
* classList.js: Cross-browser full element.classList implementation.
* 1.1.20150312
*
* By Eli Grey, http://eligrey.com
* License: Dedicated to the public domain.
* See https://github.com/eligrey/classList.js/blob/master/LICENSE.md
*/
/*global self, document, DOMException */
/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */
if ("document" in self) {
// Full polyfill for browsers with no classList support
if (!("classList" in document.createElement("_"))) {
(function (view) {
"use strict";
if (!('Element' in view)) return;
var
classListProp = "classList"
, protoProp = "prototype"
, elemCtrProto = view.Element[protoProp]
, objCtr = Object
, strTrim = String[protoProp].trim || function () {
return this.replace(/^\s+|\s+$/g, "");
}
, arrIndexOf = Array[protoProp].indexOf || function (item) {
var
i = 0
, len = this.length
;
for (; i < len; i++) {
if (i in this && this[i] === item) {
return i;
}
}
return -1;
}
// Vendors: please allow content code to instantiate DOMExceptions
, DOMEx = function (type, message) {
this.name = type;
this.code = DOMException[type];
this.message = message;
}
, checkTokenAndGetIndex = function (classList, token) {
if (token === "") {
throw new DOMEx(
"SYNTAX_ERR"
, "An invalid or illegal string was specified"
);
}
if (/\s/.test(token)) {
throw new DOMEx(
"INVALID_CHARACTER_ERR"
, "String contains an invalid character"
);
}
return arrIndexOf.call(classList, token);
}
, ClassList = function (elem) {
var
trimmedClasses = strTrim.call(elem.getAttribute("class") || "")
, classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
, i = 0
, len = classes.length
;
for (; i < len; i++) {
this.push(classes[i]);
}
this._updateClassName = function () {
elem.setAttribute("class", this.toString());
};
}
, classListProto = ClassList[protoProp] = []
, classListGetter = function () {
return new ClassList(this);
}
;
// Most DOMException implementations don't allow calling DOMException's toString()
// on non-DOMExceptions. Error's toString() is sufficient here.
DOMEx[protoProp] = Error[protoProp];
classListProto.item = function (i) {
return this[i] || null;
};
classListProto.contains = function (token) {
token += "";
return checkTokenAndGetIndex(this, token) !== -1;
};
classListProto.add = function () {
var
tokens = arguments
, i = 0
, l = tokens.length
, token
, updated = false
;
do {
token = tokens[i] + "";
if (checkTokenAndGetIndex(this, token) === -1) {
this.push(token);
updated = true;
}
}
while (++i < l);
if (updated) {
this._updateClassName();
}
};
classListProto.remove = function () {
var
tokens = arguments
, i = 0
, l = tokens.length
, token
, updated = false
, index
;
do {
token = tokens[i] + "";
index = checkTokenAndGetIndex(this, token);
while (index !== -1) {
this.splice(index, 1);
updated = true;
index = checkTokenAndGetIndex(this, token);
}
}
while (++i < l);
if (updated) {
this._updateClassName();
}
};
classListProto.toggle = function (token, force) {
token += "";
var
result = this.contains(token)
, method = result ?
force !== true && "remove"
:
force !== false && "add"
;
if (method) {
this[method](token);
}
if (force === true || force === false) {
return force;
} else {
return !result;
}
};
classListProto.toString = function () {
return this.join(" ");
};
if (objCtr.defineProperty) {
var classListPropDesc = {
get: classListGetter
, enumerable: true
, configurable: true
};
try {
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
} catch (ex) { // IE 8 doesn't support enumerable:true
if (ex.number === -0x7FF5EC54) {
classListPropDesc.enumerable = false;
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
}
}
} else if (objCtr[protoProp].__defineGetter__) {
elemCtrProto.__defineGetter__(classListProp, classListGetter);
}
}(self));
} else {
// There is full or partial native classList support, so just check if we need
// to normalize the add/remove and toggle APIs.
(function () {
"use strict";
var testElement = document.createElement("_");
testElement.classList.add("c1", "c2");
// Polyfill for IE 10/11 and Firefox <26, where classList.add and
// classList.remove exist but support only one argument at a time.
if (!testElement.classList.contains("c2")) {
var createMethod = function(method) {
var original = DOMTokenList.prototype[method];
DOMTokenList.prototype[method] = function(token) {
var i, len = arguments.length;
for (i = 0; i < len; i++) {
token = arguments[i];
original.call(this, token);
}
};
};
createMethod('add');
createMethod('remove');
}
testElement.classList.toggle("c3", false);
// Polyfill for IE 10 and Firefox <24, where classList.toggle does not
// support the second argument.
if (testElement.classList.contains("c3")) {
var _toggle = DOMTokenList.prototype.toggle;
DOMTokenList.prototype.toggle = function(token, force) {
if (1 in arguments && !this.contains(token) === !force) {
return force;
} else {
return _toggle.call(this, token);
}
};
}
testElement = null;
}());
}
}

View File

@ -0,0 +1,52 @@
// ==========================================================================
// Base layout
// ==========================================================================
// BORDER-BOX ALL THE THINGS!
// http://paulirish.com/2012/box-sizing-border-box-ftw/
*, *::after, *::before {
box-sizing: border-box;
}
// Hidden
[hidden] {
display: none;
}
// Base
html {
height: 100%;
font-size: 100%;
background: linear-gradient(#fff, @body-background) fixed;
}
body {
font-family: "Avenir", "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.5;
text-align: center;
color: @gray;
.font-smoothing(on);
padding: 0 (@padding-base / 2);
}
// Header
header {
padding: @padding-base;
margin-bottom: @padding-base;
p {
.font-size(18);
}
@media (min-width: @screen-sm) {
padding-top: (@padding-base * 3);
padding-bottom: (@padding-base * 3);
}
}
// Sections
section {
padding-bottom: @padding-base;
@media (min-width: @screen-sm) {
padding-bottom: (@padding-base * 2);
}
}

View File

@ -0,0 +1,146 @@
// ==========================================================================
// Buttons
// ==========================================================================
nav {
ul {
list-style: none;
margin: 0;
padding: 0;
font-size: 0;
}
li {
display: inline-block;
margin-top: (@padding-base / 2);
.font-size();
white-space: nowrap;
}
li + li {
margin-left: @padding-base;
}
}
// Tabs
.btn-bar {
position: relative;
margin: 0 auto @padding-base;
max-width: @example-width-video;
white-space: nowrap;
&::before {
content: "";
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background: @gray-lighter;
}
ul {
position: relative;
z-index: 1;
display: inline-block;
user-select: none;
}
li {
margin: 0;
&:first-child .btn {
border-radius: 4px 0 0 4px;
}
&:last-child .btn {
border-radius: 0 4px 4px 0;
}
& + li .btn {
margin-left: -1px;
}
}
.btn {
display: block;
border-radius: 0;
}
.active {
&:extend(.btn-primary);
}
.btn.active {
box-shadow: inset 0 1px 1px rgba(0,0,0, .2);
position: relative;
z-index: 1;
}
@media (min-width: 560px) {
margin-bottom: (@padding-base * 2);
}
}
// Shared
.btn,
.btn-count {
display: inline-block;
vertical-align: middle;
border-radius: @border-radius-base;
font-weight: 600;
user-select: none;
}
// Buttons
.btn {
padding: (@padding-base / 2) @padding-base;
background: @body-background;
border: 1px solid @gray-light;
box-shadow: inset 0 1px 0 #fff, 0 1px 1px rgba(0,0,0, .05);
text-shadow: 0 1px 1px #fff;
color: @gray;
&:hover,
&:focus {
background-color: #fff;
border-color: darken(@gray-light, 5%);
color: @link-color;
outline: 0;
}
}
.btn-primary {
background-image: linear-gradient(@link-color, darken(@link-color, 3%));
background-color: @link-color;
border-color: darken(@link-color, 10%);
box-shadow: 0 1px 1px rgba(0,0,0, .15);
text-shadow: 0 1px 1px rgba(0,0,0, .1);
color: #fff;
&:hover,
&:focus {
color: #fff;
border-color: darken(@link-color, 20%);
}
}
.btn-small {
padding-top: ceil(@padding-base / 3);
padding-bottom: ceil(@padding-base / 3);
}
// Count bubble
.btn-count {
position: relative;
margin-left: 6px;
padding: ((@padding-base / 2) - 1px);
background: #fff;
border: 1px solid @gray-light;
&::before {
content: "";
position: absolute;
display: block;
width: @arrow-size;
height: @arrow-size;
left: 1px;
top: 50%;
margin-top: -(@arrow-size / 2);
background: inherit;
border: inherit;
border-width: 1px 0 0 1px;
transform: rotate(-45deg) translate(-50%, -50%);
}
}

View File

@ -0,0 +1,19 @@
// ==========================================================================
// Errors (AWS pages)
// ==========================================================================
// Error page
html.error,
.error body {
height: 100%;
}
.error body {
width: 100%;
display: table;
table-layout: fixed;
}
.error main {
display: table-cell;
width: 100%;
vertical-align: middle;
}

View File

@ -0,0 +1,61 @@
// ==========================================================================
// Examples
// ==========================================================================
// Example players
.example-audio .player,
.example-video .player {
margin: 0 auto @padding-base;
&-controls {
border-radius: 0 0 @border-radius-base @border-radius-base;
}
}
.example-audio .player {
max-width: @example-width-audio;
&-controls {
border-radius: @border-radius-base;
}
&-progress {
border-radius: @border-radius-base @border-radius-base 0 0;
overflow: hidden;
}
}
// Base styles
.example-video .player {
max-width: @example-width-video;
video,
iframe {
border-radius: @border-radius-base;
}
iframe {
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
}
}
// Style full supported player
.example-video .player-video,
.example-video .player-youtube {
video,
iframe {
border-radius: @border-radius-base @border-radius-base 0 0;
}
iframe {
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
}
&-fullscreen,
&.fullscreen-active {
max-width: none;
.player-controls,
video,
iframe {
border-radius: 0;
}
iframe {
-webkit-mask-image: none;
}
}
}

View File

@ -0,0 +1,13 @@
// ==========================================================================
// Panels
// ==========================================================================
// Panels
.panel {
display: none;
&.active {
display: block;
animation: fade-in .3s ease;
}
}

View File

@ -0,0 +1,47 @@
// ==========================================================================
// Typography
// ==========================================================================
// Headings
h1,
h2 {
letter-spacing: -.025em;
color: #2E3C44;
margin: 0 0 (@padding-base / 2);
line-height: 1.2;
.font-smoothing();
}
h1 {
.font-size(64);
color: #3498DB;
}
// Paragraph and small
p,
small {
margin: 0 0 @padding-base;
}
small {
display: block;
padding: 0 (@padding-base / 2);
.font-size(14);
}
// Links
a {
text-decoration: none;
color: @link-color;
border-bottom: 1px solid currentColor;
transition: background .3s ease, color .3s ease;
&:hover,
&:focus {
color: @gray-dark;
}
&:focus {
.tab-focus();
}
&.logo {
border: 0;
}
}

View File

@ -2,163 +2,33 @@
// HTML5 Video Player Demo Page
// ==========================================================================
// Reset
// CSS Reset
@import "lib/normalize.less";
// Mixins
@import "lib/mixins.less";
// Fonts - docs only!
@import "lib/fontface.less";
// Variables
// ---------------------------------------
// Colors
@blue: #3498DB;
@gray-dark: #343f4a;
@gray: #565d64;
@gray-light: #cbd0d3;
@import "variables.less";
// Elements
@link-color: @blue;
@padding-base: 20px;
// Animation
@import "lib/animation.less";
// Breakpoints
@screen-md: 768px;
// BORDER-BOX ALL THE THINGS!
// http://paulirish.com/2012/box-sizing-border-box-ftw/
*, *::after, *::before {
box-sizing: border-box;
}
// Base
body {
font-family: "Avenir", "Helvetica Neue", Helvetica, Arial, sans-serif;
background: #fff;
line-height: 1.5;
text-align: center;
color: #6D797F;
}
// Error page
html.error,
.error body {
height: 100%;
}
.error body {
width: 100%;
display: table;
table-layout: fixed;
}
.error main {
display: table-cell;
width: 100%;
vertical-align: middle;
}
// Base layout
@import "components/base.less";
// Type
h1,
h2 {
letter-spacing: -.025em;
color: #2E3C44;
margin: 0 0 (@padding-base / 2);
line-height: 1.2;
.font-smoothing();
}
h1 {
.font-size(64);
color: #3498DB;
}
p,
small {
margin: 0 0 @padding-base;
}
small {
display: block;
padding: 0 (@padding-base / 2);
.font-size(14);
}
@import "lib/fontface.less";
@import "components/type.less";
// Header
header {
padding: @padding-base;
margin-bottom: @padding-base;
// Buttons
@import "components/buttons.less";
p {
.font-size(18);
}
@media (min-width: 560px) {
padding-top: (@padding-base * 3);
padding-bottom: (@padding-base * 3);
}
}
// Panels
@import "components/panels.less";
// Sections
section {
padding-bottom: @padding-base;
// Error
@import "components/error.less";
@media (min-width: 560px) {
padding-bottom: (@padding-base * 2);
}
}
// Links & Buttons
a {
text-decoration: none;
color: @link-color;
border-bottom: 1px solid currentColor;
transition: all .3s ease;
&:hover,
&:focus {
color: #000;
}
&:focus {
.tab-focus();
}
&.logo {
border: 0;
}
}
.btn {
display: inline-block;
padding: (@padding-base / 2) (@padding-base * 1.5);
background: @link-color;
border: 0;
color: #fff;
.font-smoothing(on);
font-weight: 600;
border-radius: 3px;
user-select: none;
&:hover,
&:focus {
color: #fff;
background: darken(@link-color, 5%);
}
}
// Players
.example-audio .player {
max-width: 480px;
}
.example-video .player {
max-width: 1200px;
}
.example-audio .player,
.example-video .player {
margin: 0 auto @padding-base;
&-fullscreen,
&.fullscreen-active {
max-width: none;
}
}
// Footer
footer {
margin-bottom: @padding-base;
p {
margin-bottom: (@padding-base / 2);
}
}
// Examples
@import "components/examples.less";

View File

@ -0,0 +1,9 @@
// ==========================================================================
// Animations
// ==========================================================================
// Fade
@keyframes fade-in {
0% { opacity: 0 }
100% { opacity: 1 }
}

View File

@ -1,16 +1,18 @@
// ==========================================================================
// Fonts
// ==========================================================================
@font-face {
font-family: "Avenir";
src: url("//cdn.plyr.io/fonts/avenir-medium.woff2") format("woff2"),
url("//cdn.plyr.io/fonts/avenir-medium.woff") format("woff"),
url("//cdn.plyr.io/fonts/avenir-medium.ttf") format("truetype");
url("//cdn.plyr.io/fonts/avenir-medium.woff") format("woff");
font-style: normal;
font-weight: 400;
}
@font-face {
font-family: "Avenir";
src: url("//cdn.plyr.io/fonts/avenir-bold.woff2") format("woff2"),
url("//cdn.plyr.io/fonts/avenir-bold.woff") format("woff"),
url("//cdn.plyr.io/fonts/avenir-bold.ttf") format("truetype");
url("//cdn.plyr.io/fonts/avenir-bold.woff") format("woff");
font-style: normal;
font-weight: 600;
}

View File

@ -17,7 +17,6 @@
// Default
outline: thin dotted @gray-dark;
// Webkit
//outline: 5px auto -webkit-focus-ring-color;
outline-offset: 1px;
}
@ -25,7 +24,7 @@
// Leave <body> at 100%/16px
// ---------------------------------------
.font-size(@font-size: 16){
@rem: round((@font-size / 16), 1);
@rem: round((@font-size / 16), 3);
font-size: (@font-size * 1px);
font-size: ~"@{rem}rem";
}

View File

@ -0,0 +1,30 @@
// ==========================================================================
// Variables
// ==========================================================================
// Colors
@blue: #3498db;
@gray-dark: #343f4a;
@gray: #55646b;
@gray-light: #cbd0d3;
@gray-lighter: #dbe3e8;
@off-white: #f2f5f7;
// Base
@body-background: @off-white;
// Elements
@link-color: @blue;
@padding-base: 20px;
@arrow-size: 8px;
// Breakpoints
@screen-sm: 480px;
@screen-md: 768px;
// Radii
@border-radius-base: 4px;
// Examples
@example-width-audio: 520px;
@example-width-video: 1200px;

View File

@ -31,28 +31,27 @@
<span class="sr-only">Forward {seektime} secs</span>
</button>
<span class="player-time">
<span class="sr-only">Time</span>
<span class="sr-only">Current time</span>
<span class="player-current-time">00:00</span>
</span>
<span class="player-time">
<span class="sr-only">Duration</span>
<span class="player-duration">00:00</span>
</span>
</span>
<span class="player-controls-right">
<input class="inverted sr-only" id="mute{id}" type="checkbox" data-player="mute">
<label id="mute{id}" for="mute{id}">
<button type="button" data-player="mute">
<svg class="icon-muted"><use xlink:href="#icon-muted"></use></svg>
<svg><use xlink:href="#icon-volume"></use></svg>
<span class="sr-only">Toggle Mute</span>
</label>
</button>
<label for="volume{id}" class="sr-only">Volume</label>
<input id="volume{id}" class="player-volume" type="range" min="0" max="10" step="0.5" value="0" data-player="volume">
<input class="sr-only" id="captions{id}" type="checkbox" data-player="captions">
<label for="captions{id}">
<button type="button" data-player="captions">
<svg class="icon-captions-on"><use xlink:href="#icon-captions-on"></use></svg>
<svg><use xlink:href="#icon-captions-off"></use></svg>
<span class="sr-only">Toggle Captions</span>
</label>
</button>
<button type="button" data-player="fullscreen">
<svg class="icon-exit-fullscreen"><use xlink:href="#icon-exit-fullscreen"></use></svg>
<svg><use xlink:href="#icon-enter-fullscreen"></use></svg>

View File

@ -165,11 +165,6 @@ build.templates();
build.less(bundles.docs.less, "docs");
build.js(bundles.docs.js, "docs");
// Default gulp task
gulp.task("default", function(){
run("templates", tasks.js, tasks.less, "sprite");
});
// Build all JS (inc. templates)
gulp.task("js", function(){
run("templates", tasks.js);
@ -185,12 +180,17 @@ gulp.task("watch", function () {
// Plyr core
gulp.watch(paths.plyr.src.js, tasks.js);
gulp.watch(paths.plyr.src.less, tasks.less);
gulp.watch(paths.plyr.src.sprite, "sprite");
gulp.watch(paths.plyr.src.sprite, ["sprite"]);
// Docs
gulp.watch(paths.docs.src.js, tasks.js);
gulp.watch(paths.docs.src.less, tasks.less);
gulp.watch(paths.docs.src.templates, "js");
gulp.watch(paths.docs.src.templates, ["js"]);
});
// Default gulp task
gulp.task("default", function(){
run("templates", tasks.js, tasks.less, "sprite", "watch");
});
// Publish a version to CDN and docs
@ -203,7 +203,7 @@ maxAge = 31536000, // seconds 1 year
options = {
cdn: {
headers: {
"Cache-Control": "max-age=" + maxAge + ", no-transform, public",
"Cache-Control": "max-age=" + maxAge,
"Vary": "Accept-Encoding"
},
gzippedOnly: true
@ -272,5 +272,5 @@ gulp.task("open", function () {
// Do everything
gulp.task("publish", function () {
run("templates", tasks.js, tasks.less, "sprite", "cdn", "docs", "open");
run("templates", tasks.js, tasks.less, "sprite", "cdn", "docs");
});

View File

@ -1,18 +1,18 @@
{
"name": "plyr",
"version": "1.0.30",
"version": "1.3.0",
"description": "A simple HTML5 media player using custom controls",
"homepage": "http://plyr.io",
"main": "gulpfile.js",
"dependencies": {},
"devDependencies": {
"gulp": "~3.8.6",
"gulp": "^3.8.6",
"gulp-autoprefixer": "^0.0.8",
"gulp-concat": "~2.3.3",
"gulp-concat": "^2.3.3",
"gulp-gzip": "^1.0.0",
"gulp-hogan-compile": "^0.4.1",
"gulp-less": "~1.3.1",
"gulp-minify-css": "~0.3.6",
"gulp-less": "^1.3.1",
"gulp-minify-css": "^0.3.6",
"gulp-open": "^0.3.2",
"gulp-rename": "^1.2.0",
"gulp-replace": "^0.5.3",
@ -21,8 +21,8 @@
"gulp-size": "^1.2.1",
"gulp-svgmin": "^1.0.0",
"gulp-svgstore": "^5.0.0",
"gulp-uglify": "~0.3.1",
"gulp-util": "~2.2.20",
"gulp-uglify": "^0.3.1",
"gulp-util": "^2.2.20",
"run-sequence": "^0.3.6"
},
"scripts": {

193
readme.md
View File

@ -3,20 +3,22 @@ A simple, accessible HTML5 media player.
[Checkout the demo](http://plyr.io)
[![Image of Plyr](https://cdn.plyr.io/static/plyr.png?1)](http://plyr.io)
[![Image of Plyr](https://cdn.plyr.io/static/plyr.jpg)](http://plyr.io)
## Why?
We wanted a lightweight, accessible and customisable media player that just supports *modern* browsers. Sure, there are many other players out there but we wanted to keep things simple, using the right elements for the job.
We wanted a lightweight, accessible and customisable media player that just 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.
## Features
- **Accessible** - full support for captions and screen readers.
- **Lightweight** - just 6KB minified and gzipped.
- **Customisable** - make the player look how you want with the markup you want.
- **Accessible** - full support for VTT captions and screen readers.
- **Lightweight** - just 8KB 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.
- **Audio & Video** - support for both formats.
- **API** - toggle playback, volume, seeking, and more.
- **Fullscreen** - supports native fullscreen with fallback to "full window" modes.
- **[Embedded Video](#embeds)** - support for YouTube (Vimeo soon).
- **[API](#api)** - toggle playback, volume, seeking, and more.
- **[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.
Oh and yes, it works with Bootstrap.
@ -25,11 +27,11 @@ Oh and yes, it works with Bootstrap.
Check out [the changelog](changelog.md)
## Planned development
- Accept a string selector, a node, or a nodelist for the `container` property of `selectors`.
- Playlists
- ~~YouTube~~ and Vimeo support
- Playback speed
- Multiple language captions (with selection)
- Playlists (audio and video)
- Set source by API
- Tooltip option (for seeking and controls)
- Audio captions
... and whatever else has been raised in [issues](https://github.com/Selz/plyr/issues)
If you have any cool ideas or features, please let me know by [creating an issue](https://github.com/Selz/plyr/issues/new) or of course, forking and sending a pull request.
@ -38,7 +40,7 @@ If you have any cool ideas or features, please let me know by [creating an issue
Check `docs/index.html` and `docs/dist/docs.js` for an example setup.
**Heads up**, the example `index.html` file needs to be served from a webserver (such as Apache, Nginx, IIS or similar) unless you change the file sources to include http or https. e.g. change `//cdn.plyr.io/1.0.30/plyr.js` to `https://cdn.plyr.io/1.0.30/plyr.js`
**Heads up**, the example `index.html` file needs to be served from a webserver (such as Apache, Nginx, IIS or similar) unless you change the file sources to include http or https. e.g. change `//cdn.plyr.io/1.3.0/plyr.js` to `https://cdn.plyr.io/1.3.0/plyr.js`
### Bower
If bower is your thang, you can grab Plyr using:
@ -47,15 +49,22 @@ bower install plyr
```
More info on setting up dependencies can be found in the [Bower Docs](http://bower.io/docs/creating-packages/#maintaining-dependencies)
### Ember
The awesome [@louisrudner](https://twitter.com/louisrudner) has created an ember component, available by running:
```
ember addon:install ember-cli-plyr
```
More info is on [npm](https://www.npmjs.com/package/ember-cli-plyr) and [GitHub](https://github.com/louisrudner/ember-cli-plyr)
### CDN
If you want to use our CDN, you can use the following. HTTPS (SSL) is supported.
If you want to use our CDN, you can use the following:
```html
<link rel="stylesheet" href="//cdn.plyr.io/1.0.30/plyr.css">
<script src="//cdn.plyr.io/1.0.30/plyr.js"></script>
<link rel="stylesheet" href="https://cdn.plyr.io/1.3.0/plyr.css">
<script src="https://cdn.plyr.io/1.3.0/plyr.js"></script>
```
You can also access the `sprite.svg` file at `//cdn.plyr.io/1.0.30/sprite.svg`.
You can also access the `sprite.svg` file at `https://cdn.plyr.io/1.3.0/sprite.svg`.
### CSS
If you want to use the default css, add the `plyr.css` file from /dist into your head, or even better use `plyr.less` or `plyr.sass` file included in `/src` in your build to save a request.
@ -69,18 +78,18 @@ The SVG sprite for the controls icons is loaded in by AJAX to help with performa
```html
<script>
(function(d,p){
var a=new XMLHttpRequest(),
b=d.body;
a.open("GET",p,!0);
(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.style.display="none";
c.innerHTML=a.responseText;
b.insertBefore(c,b.childNodes[0])
a.onload = function(){
var c = d.createElement("div");
c.style.display = "none";
c.innerHTML = a.responseText;
b.insertBefore(c, b.childNodes[0]);
}
})(document,"dist/sprite.svg");
})(document, "dist/sprite.svg");
</script>
```
More info on SVG sprites here:
@ -92,18 +101,16 @@ and the AJAX technique here:
The only extra markup that's needed to use plyr is a `<div>` wrapper. Replace the source, poster and captions with urls for your media.
```html
<div class="player">
<video poster="//cdn.selz.com/plyr/1.0/poster.jpg" controls crossorigin>
<video poster="https://cdn.selz.com/plyr/1.0/poster.jpg" controls crossorigin>
<!-- Video files -->
<source src="//cdn.selz.com/plyr/1.0/movie.mp4" type="video/mp4">
<source src="//cdn.selz.com/plyr/1.0/movie.webm" type="video/webm">
<source src="https://cdn.selz.com/plyr/1.0/movie.mp4" type="video/mp4">
<source src="https://cdn.selz.com/plyr/1.0/movie.webm" type="video/webm">
<!-- Text track file -->
<track kind="captions" label="English captions" src="//cdn.selz.com/plyr/1.0/movie_captions_en.vtt" srclang="en" default>
<track kind="captions" label="English captions" src="https://cdn.selz.com/plyr/1.0/movie_captions_en.vtt" srclang="en" default>
<!-- Fallback for browsers that don't support the <video> element -->
<div>
<a href="//cdn.selz.com/plyr/1.0/movie.mp4">Download</a>
</div>
<a href="https://cdn.selz.com/plyr/1.0/movie.mp4">Download</a>
</video>
</div>
```
@ -113,38 +120,40 @@ And the same for `<audio>`
<div class="player">
<audio controls>
<!-- Audio files -->
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3" type="audio/mp3">
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.ogg" type="audio/ogg">
<source src="https://cdn.selz.com/plyr/1.0/logistics-96-sample.mp3" type="audio/mp3">
<source src="https://cdn.selz.com/plyr/1.0/logistics-96-sample.ogg" type="audio/ogg">
<!-- Fallback for browsers that don't support the <audio> element -->
<div>
<a href="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3">Download</a>
</div>
<a href="https://cdn.selz.com/plyr/1.0/logistics-96-sample.mp3">Download</a>
</audio>
</div>
```
For YouTube, Plyr uses the standard YouTube API markup (an empty `<div>`):
```html
<div class="player">
<div data-video-id="L1h9xxCU20g" data-type="youtube"></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:
[https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS)
###JavaScript
Much of the behaviour of the player is configurable when initialising the library. Below is an example of a default instance.
### JavaScript
Much of the behaviour of the player is configurable when initialising the library. Here's an example of a default setup:
```html
<script src="dist/plyr.js"></script>
<script>
plyr.setup({
*options*
});
</script>
<script>plyr.setup();</script>
```
#### Options
You can pass the following options to the setup method.
You can pass the following options to the setup method using `plyr.setup({...})`.
<table class="table" width="100%">
<thead>
@ -168,6 +177,24 @@ You can pass the following options to the setup method.
<td><code><a href="controls.md">See controls.md</a></code></td>
<td>See <a href="controls.md">controls.md</a> for more info on how the html needs to be structured.</td>
</tr>
<tr>
<td><code>controls</code></td>
<td>Array</td>
<td><code>["restart", "rewind", "play", "fast-forward", "current-time", "duration", "mute", "volume", "captions", "fullscreen"]</code></td>
<td>Toggle which control elements you would like to display when using the default controls html. If you specify a <code>html</code> option, this is redundant. The default value is to display everything.</td>
</tr>
<tr>
<td><code>i18n</code></td>
<td>Object</td>
<td><code><a href="controls.md">See controls.md</a></code></td>
<td>Used for internationalisation (i18n) of the tooltips/labels within the buttons.</td>
</tr>
<tr>
<td><code>iconPrefix</code></td>
<td>String</td>
<td><code>icon</code></td>
<td>Specify the id prefix for the icons used in the default controls (e.g. "icon-play" would be "icon"). 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>
</tr>
<tr>
<td><code>debug</code></td>
<td>Boolean</td>
@ -197,6 +224,12 @@ You can pass the following options to the setup method.
<td>Boolean</td>
<td><code>false</code></td>
<td>Display control labels as tooltips on :hover &amp; :focus (by default, the labels are screen reader only).</td>
</tr>
<tr>
<td><code>displayDuration</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Displays the duration of the media on the "metadataloaded" event (on startup) in the current time display. This will only work if the `preload` attribute is not set to `none` (or is not set at all) and you choose not to display the duration (see <code>controls</code> option).</td>
</tr>
<tr>
<td><code>selectors</code></td>
@ -228,6 +261,12 @@ You can pass the following options to the setup method.
<td>&mdash;</td>
<td>Two properties; <code>enabled</code> which toggles if local storage should be enabled (if the browser supports it). The default value is `true`. This enables storing user settings, currently it only stores volume but more will be added later. The second property <code>key</code> is the key used for the local storage. The default is <code>plyr_volume</code> until more settings are stored.</td>
</tr>
<tr>
<td><code>onSetup</code></td>
<td>Function</td>
<td>&mdash;</td>
<td>This callback function is called on every new plyr instance created. The context (<code>this</code>) is the plyr instance itself.</td>
</tr>
</tbody>
</table>
@ -285,6 +324,11 @@ Here's a list of the methods supported:
<td>Number</td>
<td>Sets the player volume to the provided parameter. The value should be between 0 (muted) and 10 (loudest). If no parameter is provided, the default volume is used (5). Values over 10 are ignored.</td>
</tr>
<tr>
<td><code>togglePlay()</code></td>
<td>Boolean</td>
<td>Toggles playback for the player based on either the boolean argument or it's current state.</td>
</tr>
<tr>
<td><code>toggleMute()</code></td>
<td>&mdash;</td>
@ -295,10 +339,20 @@ Here's a list of the methods supported:
<td>&mdash;</td>
<td>Toggles whether captions are enabled.</td>
</tr>
<tr>
<td><code>toggleFullscreen()</code></td>
<td>Event</td>
<td>Toggles fullscreen. This can only be initiated by a user gesture due to browser security, i.e. a user event such as click.</td>
</tr>
<tr>
<td><code>isFullscreen()</code></td>
<td>&mdash;</td>
<td>Boolean returned if the player is in fullscreen.</td>
</tr>
<tr>
<td><code>support(...)</code></td>
<td>String</td>
<td>Determine if a player supports a certain MIME type.</td>
<td>Determine if a player supports a certain MIME type. This is not supported for embedded content (YouTube).</td>
</tr>
<tr>
<td><code>source(...)</code></td>
@ -313,13 +367,26 @@ Here's a list of the methods supported:
<strong>array</strong><br>
<code>.source([{ src: "/path/to/video.webm", type: "video/webm", ...more attributes... }, { src: "/path/to/video.mp4", type: "video/mp4", ...more attributes... }])`</code><br>
This will inject a child `source` element for every element in the array with the specified attributes. `src` is the only required attribute although adding `type` is recommended as it helps the browser decide which file to download and play.
<br><br>
<strong>YouTube</strong><br>
Currently this API method only accepts a YouTube ID when used with a YouTube player. I will add URL support soon, along with being able to swap between types (e.g. YouTube to Audio or Video and vice versa.)
</td>
</tr>
<tr>
<tr>
<td><code>poster(...)</code></td>
<td>String</td>
<td>Set the poster url. This is supported for the <code>video</code> element only.</td>
</tr>
<tr>
<td><code>destroy()</code></td>
<td>&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>
</tr>
<tr>
<td><code>restore()</code></td>
<td>&mdash;</td>
<td>Reverses the effects of the <code>destroy()</code> method, restoring the UI and listeners.</td>
</tr>
</tbody>
</table>
@ -337,12 +404,33 @@ media.addEventListener("playing", function() {
A complete list of events can be found here:
[Media Events - W3.org](http://www.w3.org/2010/05/video/mediaevents.html)
## Embeds
Currently only YouTube is supported. Vimeo will be coming soon. Some HTML5 media events are triggered on the `media` property of the `plyr` object:
- `play`
- `pause`
- `timeupdate`
- `progress`
Due to the way the YouTube API works, the `timeupdate` and `progress` events are triggered by polling every 200ms so the event may trigger without an actual value change. Buffering progress is `media.buffered` in the `plyr` object. It is a a number between 0 and 1 that specifies the percentage of the video that the player shows as buffered.
```javascript
document.querySelector(".player").plyr.media.addEventListener("play", function() {
console.log("play");
});
```
The `.source()` API method can also be used but the video id must be passed as the argument.
Currently caption control is not supported but I will work on this.
## Fullscreen
Fullscreen in Plyr is supported for all browsers that [currently support it](http://caniuse.com/#feat=fullscreen). If you're using the default CSS, you can also use a "full browser" mode which will use the full browser window by adding the `player-fullscreen` class to your container.
## Browser support
<table width="100%" style="text-align: center;">
<table width="100%" style="text-align: center">
<thead>
<tr>
<td>Safari</td>
@ -380,11 +468,14 @@ If a User Agent is disabled but supports `<video>` and `<audio>` natively, it wi
Any unsupported browsers will display links to download the media if the correct html is used.
### Checking for support
There's an API method for checking support. You can call `plyr.supported()` and optionally pass a type to it, e.g. `plyr.supported("video")`. It will return an object with two keys; `basic` meaning there's basic support for that media type (or both if no type is passed) and `full` meaning there's full support for plyr.
## Issues
If you find anything weird with Plyr, please let us know using the GitHub issues tracker.
## Author
Plyr is developed by Sam Potts ([@sam_potts](https://twitter.com/sam_potts)) ([sampotts.me](http://sampotts.me))
Plyr is developed by [@sam_potts](https://twitter.com/sam_potts) / [sampotts.me](http://sampotts.me) with help from the awesome [contributors](https://github.com/Selz/plyr/graphs/contributors)
## Mentions
- [The Changelog](http://thechangelog.com/plyr-simple-html5-media-player-custom-controls-webvtt-captions/)
@ -412,4 +503,4 @@ Also these links helped created Plyr:
- [Styling the `<progress>` element - hongkiat.com](http://www.hongkiat.com/blog/html5-progress-bar/)
## Copyright and License
[The MIT license](license.md).
[The MIT license](license.md).

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +1,39 @@
// ==========================================================================
// HTML5 Media Player
// Plyr styles
// https://github.com/selz/plyr
// ==========================================================================
// Variables
// -------------------------------
// Colors
@blue: #3498DB;
@gray-dark: #343f4a;
@gray: #565d64;
@gray-light: #cbd0d3;
@gray-dark: #343F4A;
@gray: #565D64;
@gray-light: #6B7D86;
@gray-lighter: #CBD0D3;
@off-white: #D6DADD;
// Font sizes
@font-size-small: 14px;
@font-size-base: 16px;
@font-size-large: ceil((@font-size-base * 1.5));
// Captions
@font-size-captions-base: ceil(@font-size-base * 1.25);
@font-size-captions-medium: ceil(@font-size-base * 1.5);
@font-size-captions-large: (@font-size-base * 2);
// Controls
@control-spacing: 10px;
@controls-bg: @gray-dark;
@controls-bg: #fff;
@control-bg-hover: @blue;
@control-color: @gray-light;
@control-color-inactive: @gray;
@control-color-hover: #fff;
.contrast-control-color(@controls-bg);
.contrast-control-color-hover(@control-bg-hover);
// Tooltips
@tooltip-bg: @controls-bg;
@tooltip-color: #fff;
@tooltip-border-color: @off-white;
@tooltip-color: @control-color;
@tooltip-padding: @control-spacing;
@tooltip-arrow-size: 5px;
@tooltip-radius: 3px;
@ -39,7 +47,7 @@
// Volume
@volume-track-height: 6px;
@volume-track-bg: @gray;
@volume-track-bg: darken(@controls-bg, 10%);
@volume-thumb-height: (@volume-track-height * 2);
@volume-thumb-width: (@volume-track-height * 2);
@volume-thumb-bg: @control-color;
@ -49,18 +57,40 @@
@bp-control-split: 560px; // When controls split into left/right
@bp-captions-large: 768px; // When captions jump to the larger font size
// Utility classes & mixins
// -------------------------------
// Screen reader only
.sr-only {
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px);
padding: 0 !important;
border: 0 !important;
height: 1px !important;
width: 1px !important;
overflow: hidden;
// Animation
// ---------------------------------------
@keyframes progress {
to { background-position: @progress-loading-size 0; }
}
// Mixins
// -------------------------------
// Contrast
.contrast-control-color(@color: "") when (lightness(@color) >= 65%) {
@control-color: @gray-light;
}
.contrast-control-color(@color: "") when (lightness(@color) < 65%) {
@control-color: @gray-lighter;
}
.contrast-control-color-hover(@color: "") when (lightness(@color) >= 65%) {
@control-color-hover: @gray;
}
.contrast-control-color-hover(@color: "") when (lightness(@color) < 65%) {
@control-color-hover: #fff;
}
// Font smoothing
.font-smoothing(@mode: on) when (@mode = on) {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
.font-smoothing(@mode: on) when (@mode = off) {
-moz-osx-font-smoothing: auto;
-webkit-font-smoothing: subpixel-antialiased;
}
// Contain floats: nicolasgallagher.com/micro-clearfix-hack/
.clearfix() {
zoom: 1;
@ -74,14 +104,7 @@
outline-offset: 0;
}
// Animation
// ---------------------------------------
@keyframes progress {
to { background-position: @progress-loading-size 0; }
}
// <input type="range"> styling
// ---------------------------------------
.volume-thumb() {
height: @volume-thumb-height;
width: @volume-thumb-width;
@ -108,15 +131,16 @@
border: 0;
}
// Font smoothing
// ---------------------------------------
.font-smoothing(@mode: on) when (@mode = on) {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
.font-smoothing(@mode: on) when (@mode = off) {
-moz-osx-font-smoothing: auto;
-webkit-font-smoothing: subpixel-antialiased;
// Screen reader only
// -------------------------------
.sr-only {
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px);
padding: 0 !important;
border: 0 !important;
height: 1px !important;
width: 1px !important;
overflow: hidden;
}
// Styles
@ -140,12 +164,28 @@
&-video-wrapper {
position: relative;
}
video {
video,
audio {
width: 100%;
height: auto;
vertical-align: middle;
}
// For embeds
&-video-embed {
padding-bottom: 56.25%; /* 16:9 */
height: 0;
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
}
}
// Captions
&-captions {
display: none;
@ -153,26 +193,31 @@
bottom: 0;
left: 0;
width: 100%;
padding: 20px;
min-height: 2.5em;
padding: (@control-spacing * 2) (@control-spacing * 2) (@control-spacing * 3);
color: #fff;
font-size: @font-size-base;
font-weight: 600;
text-shadow:
-1px -1px 0 @gray,
1px -1px 0 @gray,
-1px 1px 0 @gray,
1px 1px 0 @gray;
font-size: @font-size-captions-base;
text-align: center;
.font-smoothing();
span {
border-radius: 2px;
padding: 3px 10px;
background: rgba(0,0,0, .9);
}
span:empty {
display: none;
}
@media (min-width: @bp-captions-large) {
font-size: @font-size-large;
font-size: @font-size-captions-medium;
}
}
&.captions-active &-captions {
display: block;
}
&.fullscreen-active &-captions {
font-size: @font-size-captions-large;
}
// Player controls
&-controls {
@ -183,6 +228,7 @@
background: @controls-bg;
line-height: 1;
text-align: center;
box-shadow: 0 1px 1px rgba(red(@gray-dark), green(@gray-dark), blue(@gray-dark), .2);
// Layout
&-right {
@ -199,17 +245,20 @@
}
}
input + label,
// Buttons
button {
display: inline-block;
vertical-align: middle;
margin: 0 2px;
padding: (@control-spacing / 2) @control-spacing;
transition: background .3s ease;
overflow: hidden;
border: 0;
background: transparent;
border-radius: 3px;
cursor: pointer;
color: @control-color;
transition: background .3s ease, color .3s ease, opacity .3s ease;
svg {
width: 18px;
height: 18px;
@ -217,39 +266,27 @@
fill: currentColor;
transition: fill .3s ease;
}
}
input + label,
.inverted:checked + label {
color: @control-color-inactive;
}
button,
.inverted + label,
input:checked + label {
color: @control-color;
}
button {
border: 0;
background: transparent;
overflow: hidden;
}
// Specificity for overriding .inverted
button:focus,
button:hover,
[type="checkbox"]:focus + label,
[type="checkbox"] + label:hover {
background: @control-bg-hover;
color: @control-color-hover;
}
button:focus,
input:focus + label {
outline: 0;
// Hover and tab focus
&.tab-focus,
&:hover {
background: @control-bg-hover;
color: @control-color-hover;
}
// Default focus
&:focus {
outline: 0;
}
}
// Hide toggle icons by default
.icon-exit-fullscreen,
.icon-muted,
.icon-captions-on {
display: none;
}
// Player time
.player-time {
display: inline-block;
vertical-align: middle;
@ -259,11 +296,25 @@
font-size: @font-size-small;
.font-smoothing();
}
// Media duration hidden on small screens
.player-time + .player-time {
display: none;
@media (min-width: @bp-control-split) {
display: inline-block;
}
// Add a slash in before
&::before {
content: '\2044';
margin-right: @control-spacing;
}
}
}
// Tooltips
&-tooltip {
visibility: hidden;
position: absolute;
z-index: 2;
bottom: 100%;
@ -272,39 +323,38 @@
opacity: 0;
background: @tooltip-bg;
border: 1px solid @tooltip-border-color;
border-radius: @tooltip-radius;
color: @tooltip-color;
font-size: @font-size-small;
line-height: 1.5;
font-weight: 600;
transform: translate(-50%, (@tooltip-padding * 3));
transition: transform .2s .2s ease, opacity .2s .2s ease;
transform: translate(-50%, (@tooltip-padding * 3)) scale(0);
transform-origin: 50% 100%;
transition: transform .2s .1s ease, opacity .2s .1s ease;
// Arrow
&::after {
content: "";
display: block;
content: '';
position: absolute;
z-index: 1;
top: 100%;
left: 50%;
bottom: -@tooltip-arrow-size;
margin-left: -@tooltip-arrow-size;
width: 0;
height: 0;
transition: inherit;
border-style: solid;
border-width: @tooltip-arrow-size @tooltip-arrow-size 0 @tooltip-arrow-size;
border-color: @controls-bg transparent transparent;
display: block;
width: 10px;
height: 10px;
background: @tooltip-bg;
transform: translate(-50%, -50%) rotate(45deg) translateY(1px);
border: 1px solid @tooltip-border-color;
border-width: 0 1px 1px 0;
}
}
label:hover .player-tooltip,
input:focus + label .player-tooltip,
button:hover .player-tooltip,
button:focus .player-tooltip {
visibility: visible;
button.tab-focus:focus .player-tooltip {
opacity: 1;
transform: translate(-50%, 0);
transform: translate(-50%, 0) scale(1);
}
label:hover .player-tooltip,
button:hover .player-tooltip {
z-index: 3;
}
@ -322,7 +372,7 @@
&-buffer[value],
&-played[value],
&-seek[type=range] {
&-seek[type='range'] {
position: absolute;
left: 0;
top: 0;
@ -362,7 +412,7 @@
// Seek control
// <input[type='range']> element
// Specificity is for bootstrap compatibility
&-seek[type=range] {
&-seek[type='range'] {
z-index: 4;
cursor: pointer;
outline: 0;
@ -437,7 +487,7 @@
// Volume control
// <input[type='range']> element
// Specificity is for bootstrap compatibility
&-volume[type=range] {
&-volume[type='range'] {
display: inline-block;
vertical-align: middle;
-webkit-appearance: none;
@ -446,7 +496,8 @@
margin: 0 @control-spacing 0 0;
padding: 0;
cursor: pointer;
background: none;
background: transparent;
border: none;
// Webkit
&::-webkit-slider-runnable-track {
@ -502,7 +553,6 @@
// https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html
&.ios &-volume,
&.ios [data-player='mute'],
&.ios [data-player='mute'] + label,
&-audio.ios &-controls-right {
display: none;
}
@ -511,6 +561,17 @@
float: none;
}
// Audio specific styles
// Position the progress within the container
&-audio .player-controls {
padding-top: (@control-spacing * 2);
}
&-audio .player-progress {
bottom: auto;
top: 0;
background: @off-white;
}
// Full screen mode
&-fullscreen,
&.fullscreen-active {
@ -530,19 +591,7 @@
.player-video-wrapper {
height: 100%;
width: 100%;
.player-captions {
top: auto;
bottom: 90px;
@media (min-width: @bp-control-split) and (max-width: (@bp-captions-large - 1)) {
bottom: 60px;
}
@media (min-width: @bp-captions-large) {
bottom: 80px;
}
}
}
}
.player-controls {
position: absolute;
bottom: 0;
@ -551,13 +600,28 @@
}
// Hide controls when playing in full screen
&.fullscreen-hide-controls.playing .player-controls {
transform: translateY(100%) translateY(@control-spacing / 2);
transition: transform .3s 1s ease;
&.hover {
&.fullscreen-hide-controls.playing {
.player-controls {
transform: translateY(100%) translateY(@control-spacing / 2);
transition: transform .3s .2s ease;
}
&.player-hover .player-controls {
transform: translateY(0);
transition-delay: 0;
}
.player-captions {
bottom: (@control-spacing / 2);
transition: bottom .3s .2s ease;
}
}
// Captions
.player-captions,
&.fullscreen-hide-controls.playing.player-hover .player-captions {
top: auto;
bottom: 90px;
@media (min-width: @bp-control-split) {
bottom: 60px;
}
}
}
@ -575,15 +639,11 @@
// Some options are hidden by default
[data-player='captions'],
[data-player='captions'] + label,
[data-player='fullscreen'],
[data-player='fullscreen'] + label {
[data-player='fullscreen'] {
display: none;
}
&.captions-enabled [data-player='captions'],
&.captions-enabled [data-player='captions'] + label,
&.fullscreen-enabled [data-player='fullscreen'],
&.fullscreen-enabled [data-player='fullscreen'] + label {
&.fullscreen-enabled [data-player='fullscreen'] {
display: inline-block;
}
}

View File

@ -1,72 +1,99 @@
// ==========================================================================
// HTML5 Media Player
// Plyr styles
// https://github.com/selz/plyr
// ==========================================================================
// Variables
// -------------------------------
// Colors
$blue: #3498DB;
$gray-dark: #343f4a;
$gray: #565d64;
$gray-light: #cbd0d3;
$blue: #3498DB !default;
$gray-dark: #343F4A !default;
$gray: #565D64 !default;
$gray-light: #6B7D86 !default;
$gray-lighter: #CBD0D3 !default;
$off-white: #D6DADD !default;
// Font sizes
$font-size-small: 14px;
$font-size-base: 16px;
$font-size-large: ceil(($font-size-base * 1.5));
$font-size-small: 14px !default;
$font-size-base: 16px !default;
// Captions
$font-size-captions-base: ceil(@font-size-base * 1.25) !default;
$font-size-captions-medium: ceil(@font-size-base * 1.5) !default;
$font-size-captions-large: (@font-size-base * 2) !default;
// Controls
$control-spacing: 10px;
$controls-bg: $gray-dark;
$control-bg-hover: $blue;
$control-color: $gray-light;
$control-color-inactive: $gray;
$control-color-hover: #fff;
$control-spacing: 10px !default;
$controls-bg: #fff !default;
$control-bg-hover: $blue !default;
$control-color: null !default;
$control-color-hover: null !default;
// Contrast
@if lightness($controls-bg) >= 65% {
$control-color: $gray-light;
} @else {
$control-color: $gray-lighter;
}
@if lightness($control-bg-hover) >= 65% {
$control-color-hover: $gray;
} @else {
$control-color-hover: #fff;
}
// Tooltips
$tooltip-bg: $controls-bg;
$tooltip-color: #fff;
$tooltip-padding: $control-spacing;
$tooltip-arrow-size: 5px;
$tooltip-radius: 3px;
$tooltip-bg: $controls-bg !default;
$tooltip-color: $control-color !default;
$tooltip-padding: $control-spacing !default;
$tooltip-arrow-size: 5px !default;
$tooltip-radius: 3px !default;
// Progress
$progress-bg: rgba(red($gray), green($gray), blue($gray), .2);
$progress-playing-bg: $blue;
$progress-buffered-bg: rgba(red($gray), green($gray), blue($gray), .25);
$progress-loading-size: 40px;
$progress-loading-bg: rgba(0,0,0, .15);
$progress-bg: rgba(red($gray), green($gray), blue($gray), .2) !default;
$progress-playing-bg: $blue !default;
$progress-buffered-bg: rgba(red($gray), green($gray), blue($gray), .25) !default;
$progress-loading-size: 40px !default;
$progress-loading-bg: rgba(0,0,0, .15) !default;
// Volume
$volume-track-height: 6px;
$volume-track-bg: $gray;
$volume-thumb-height: ($volume-track-height * 2);
$volume-thumb-width: ($volume-track-height * 2);
$volume-thumb-bg: $control-color;
$volume-thumb-bg-focus: $control-bg-hover;
$volume-track-height: 6px !default;
$volume-track-bg: darken($controls-bg, 10%) !default;
$volume-thumb-height: ($volume-track-height * 2) !default;
$volume-thumb-width: ($volume-track-height * 2) !default;
$volume-thumb-bg: $control-color !default;
$volume-thumb-bg-focus: $control-bg-hover !default;
// Breakpoints
$bp-control-split: 560px; // When controls split into left/right
$bp-captions-large: 768px; // When captions jump to the larger font size
$bp-control-split: 560px !default; // When controls split into left/right
$bp-captions-large: 768px !default; // When captions jump to the larger font size
// Utility classes & mixins
// -------------------------------
// Screen reader only
.sr-only {
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px);
padding: 0 !important;
border: 0 !important;
height: 1px !important;
width: 1px !important;
overflow: hidden;
// Animation
// ---------------------------------------
@keyframes progress {
to { background-position: $progress-loading-size 0; }
}
// Font smoothing
@mixin font-smoothing($mode: on)
{
@if ($mode == 'on') {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
@else if ($mode == 'off') {
-moz-osx-font-smoothing: auto;
-webkit-font-smoothing: subpixel-antialiased;
}
}
// Contain floats: nicolasgallagher.com/micro-clearfix-hack/
@mixin clearfix()
{
zoom: 1;
&:before,
&:after { content: ""; display: table; }
&:before,
&:after { content: ''; display: table; }
&:after { clear: both; }
}
// Tab focus styles
@ -76,14 +103,7 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
outline-offset: 0;
}
// Animation
// ---------------------------------------
@keyframes progress {
to { background-position: $progress-loading-size 0; }
}
// <input type="range"> styling
// ---------------------------------------
@mixin volume-thumb()
{
height: $volume-thumb-height;
@ -114,22 +134,21 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
border: 0;
}
// Font smoothing
// ---------------------------------------
@mixin font-smoothing($mode: on)
{
@if $mode == 'on' {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
} @else if $mode == 'off' {
-moz-osx-font-smoothing: auto;
-webkit-font-smoothing: subpixel-antialiased;
}
// Screen reader only
// -------------------------------
.sr-only {
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px);
padding: 0 !important;
border: 0 !important;
height: 1px !important;
width: 1px !important;
overflow: hidden;
}
// Styles
// -------------------------------
// Base
// Base
.player {
position: relative;
max-width: 100%;
@ -140,20 +159,36 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
&,
*,
*::after,
*::before {
box-sizing: border-box;
*::before {
box-sizing: border-box;
}
// For video
&-video-wrapper {
position: relative;
}
video {
video,
audio {
width: 100%;
height: auto;
vertical-align: middle;
}
// For embeds
&-video-embed {
padding-bottom: 56.25%; /* 16:9 */
height: 0;
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
}
}
// Captions
&-captions {
display: none;
@ -161,26 +196,31 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
bottom: 0;
left: 0;
width: 100%;
padding: 20px;
min-height: 2.5em;
padding: ($control-spacing * 2) ($control-spacing * 2) ($control-spacing * 3);
color: #fff;
font-size: $font-size-base;
font-weight: 600;
text-shadow:
-1px -1px 0 $gray,
1px -1px 0 $gray,
-1px 1px 0 $gray,
1px 1px 0 $gray;
font-size: $font-size-captions-base;
text-align: center;
@include font-smoothing();
@media (min-width: $bp-captions-large) {
font-size: $font-size-large;
span {
border-radius: 2px;
padding: 3px 10px;
background: rgba(0,0,0, .9);
}
span:empty {
display: none;
}
@media (min-width: @bp-captions-large) {
font-size: $font-size-captions-medium;
}
}
&.captions-active &-captions {
display: block;
}
&.fullscreen-active &-captions {
font-size: $font-size-captions-large;
}
// Player controls
&-controls {
@ -191,6 +231,7 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
background: $controls-bg;
line-height: 1;
text-align: center;
box-shadow: 0 1px 1px rgba(red($gray-dark), green($gray-dark), blue($gray-dark), .2);
// Layout
&-right {
@ -206,18 +247,21 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
margin-top: 0;
}
}
input + label,
// Buttons
button {
display: inline-block;
vertical-align: middle;
margin: 0 2px;
padding: ($control-spacing / 2) $control-spacing;
transition: background .3s ease;
overflow: hidden;
border: 0;
background: transparent;
border-radius: 3px;
cursor: pointer;
color: $control-color;
transition: background .3s ease, color .3s ease, opacity .3s ease;
svg {
width: 18px;
height: 18px;
@ -225,39 +269,27 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
fill: currentColor;
transition: fill .3s ease;
}
// Hover and tab focus
&.tab-focus,
&:hover {
background: $control-bg-hover;
color: $control-color-hover;
}
// Default focus
&:focus {
outline: 0;
}
}
input + label,
.inverted:checked + label {
color: $control-color-inactive;
}
button,
.inverted + label,
input:checked + label {
color: $control-color;
}
button {
border: 0;
background: transparent;
overflow: hidden;
}
// Specificity for overriding .inverted
button:focus,
button:hover,
[type="checkbox"]:focus + label,
[type="checkbox"] + label:hover {
background: $control-bg-hover;
color: $control-color-hover;
}
button:focus,
input:focus + label {
outline: 0;
}
// Hide toggle icons by default
.icon-exit-fullscreen,
.icon-muted,
.icon-captions-on {
display: none;
}
// Time display
.player-time {
display: inline-block;
vertical-align: middle;
@ -267,18 +299,32 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
font-size: $font-size-small;
@include font-smoothing();
}
// Media duration hidden on small screens
.player-time + .player-time {
display: none;
@media (min-width: $bp-control-split) {
display: inline-block;
}
// Add a slash in before
&::before {
content: '\2044';
margin-right: $control-spacing;
}
}
}
// Tooltips
&-tooltip {
visibility: hidden;
position: absolute;
z-index: 2;
bottom: 100%;
margin-bottom: $tooltip-padding;
padding: $tooltip-padding ($tooltip-padding * 1.5);
opacity: 0;
opacity: 0;
background: $tooltip-bg;
border-radius: $tooltip-radius;
color: $tooltip-color;
@ -286,11 +332,12 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
line-height: 1.5;
font-weight: 600;
transform: translate(-50%, ($tooltip-padding * 3));
transition: transform .2s .2s ease, opacity .2s .2s ease;
transform: translate(-50%, ($tooltip-padding * 3)) scale(0);
transform-origin: 50% 100%;
transition: transform .2s .1s ease, opacity .2s .1s ease;
&::after {
content: "";
content: '';
display: block;
position: absolute;
left: 50%;
@ -304,15 +351,11 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
border-color: $controls-bg transparent transparent;
}
}
label:hover .player-tooltip,
input:focus + label .player-tooltip,
button:hover .player-tooltip,
button:focus .player-tooltip {
visibility: visible;
opacity: 1;
transform: translate(-50%, 0);
transform: translate(-50%, 0) scale(1);
}
label:hover .player-tooltip,
button:hover .player-tooltip {
z-index: 3;
}
@ -330,7 +373,7 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
&-buffer[value],
&-played[value],
&-seek[type=range] {
&-seek[type='range'] {
position: absolute;
left: 0;
top: 0;
@ -346,7 +389,7 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
background: transparent;
}
&-buffer[value],
&-played[value] {
&-played[value] {
&::-webkit-progress-bar {
background: transparent;
}
@ -370,7 +413,7 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
// Seek control
// <input[type='range']> element
// Specificity is for bootstrap compatibility
&-seek[type=range] {
&-seek[type='range'] {
z-index: 4;
cursor: pointer;
outline: 0;
@ -392,7 +435,7 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
-moz-appearance: none;
@include seek-thumb();
}
// Microsoft
&::-ms-track {
color: transparent;
@ -422,15 +465,15 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
background-repeat: repeat-x;
background-color: $progress-buffered-bg;
background-image: linear-gradient(
-45deg,
$progress-loading-bg 25%,
transparent 25%,
transparent 50%,
$progress-loading-bg 50%,
-45deg,
$progress-loading-bg 25%,
transparent 25%,
transparent 50%,
$progress-loading-bg 50%,
$progress-loading-bg 75%,
transparent 75%,
transparent 75%,
transparent);
color: transparent;
color: transparent;
}
// States
@ -445,17 +488,18 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
// Volume control
// <input[type='range']> element
// Specificity is for bootstrap compatibility
&-volume[type=range] {
&-volume[type='range'] {
display: inline-block;
vertical-align: middle;
-webkit-appearance: none;
-moz-appearance: none;
width: 100px;
margin: 0 $control-spacing 0 0;
padding: 0;
padding: 0;
cursor: pointer;
background: none;
background: transparent;
border: none;
// Webkit
&::-webkit-slider-runnable-track {
@include volume-track();
@ -473,7 +517,7 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
&::-moz-range-thumb {
@include volume-thumb();
}
// Microsoft
&::-ms-track {
height: $volume-track-height;
@ -510,7 +554,6 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
// https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html
&.ios &-volume,
&.ios [data-player='mute'],
&.ios [data-player='mute'] + label,
&-audio.ios &-controls-right {
display: none;
}
@ -519,6 +562,17 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
float: none;
}
// Audio specific styles
// Position the progress within the container
&-audio .player-controls {
padding-top: ($control-spacing * 2);
}
&-audio .player-progress {
bottom: auto;
top: 0;
background: $off-white;
}
// Full screen mode
&-fullscreen,
&.fullscreen-active {
@ -538,18 +592,6 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
.player-video-wrapper {
height: 100%;
width: 100%;
.player-captions {
top: auto;
bottom: 90px;
@media (min-width: $bp-control-split) and (max-width: ($bp-captions-large - 1)) {
bottom: 60px;
}
@media (min-width: $bp-captions-large) {
bottom: 80px;
}
}
}
.player-controls {
position: absolute;
@ -559,13 +601,28 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
}
// Hide controls when playing in full screen
&.fullscreen-hide-controls.playing .player-controls {
transform: translateY(100%) translateY($control-spacing / 2);
transition: transform .3s 1s ease;
&.hover {
&.fullscreen-hide-controls.playing {
.player-controls {
transform: translateY(100%) translateY($control-spacing / 2);
transition: transform .3s .2s ease;
}
&.player-hover .player-controls {
transform: translateY(0);
transition-delay: 0;
}
.player-captions {
bottom: ($control-spacing / 2);
transition: bottom .3s .2s ease;
}
}
// Captions
.player-captions,
&.fullscreen-hide-controls.playing.player-hover .player-captions {
top: auto;
bottom: 90px;
@media (min-width: $bp-control-split) {
bottom: 60px;
}
}
}
@ -583,21 +640,11 @@ $bp-captions-large: 768px; // When captions jump to the larger font size
// Some options are hidden by default
[data-player='captions'],
[data-player='captions'] + label,
[data-player='fullscreen'],
[data-player='fullscreen'] + label {
[data-player='fullscreen'] {
display: none;
}
&.captions-enabled [data-player='captions'],
&.captions-enabled [data-player='captions'] + label,
&.fullscreen-enabled [data-player='fullscreen'],
&.fullscreen-enabled [data-player='fullscreen'] + label {
&.fullscreen-enabled [data-player='fullscreen'] {
display: inline-block;
}
// Full browser view hides toggle
&-fullscreen [data-player='fullscreen'],
&-fullscreen [data-player='fullscreen'] + label {
display: none !important;
}
}

View File

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title>icon-captions-off</title>
<desc>Created with Sketch.</desc>
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" sketch:type="MSPage">
<path d="M1,2 C0.448,2 0,2.448 0,3 L0,15 C0,15.552 0.448,16 1,16 L17,16 C17.552,16 18,15.552 18,15 L18,3 C18,2.448 17.552,2 17,2 L1,2 Z M2,14 L2,4 L16,4 L16,14 L2,14 L2,14 Z" id="Shape" sketch:type="MSShapeGroup"></path>

Before

Width:  |  Height:  |  Size: 747 B

After

Width:  |  Height:  |  Size: 562 B

View File

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title>icon-captions-on</title>
<desc>Created with Sketch.</desc>
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" sketch:type="MSPage">
<path d="M1,2 C0.448,2 0,2.448 0,3 L0,15 C0,15.552 0.448,16 1,16 L17,16 C17.552,16 18,15.552 18,15 L18,3 C18,2.448 17.552,2 17,2 L1,2 Z M2,14 L2,4 L16,4 L16,14 L2,14 L2,14 Z" id="Shape" sketch:type="MSShapeGroup"></path>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 863 B

View File

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title>expand</title>
<desc>Created with Sketch.</desc>
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" sketch:type="MSPage">
<g id="expand" sketch:type="MSLayerGroup" transform="translate(-1.000000, -1.000000)">

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title>collapse</title>
<desc>Created with Sketch.</desc>
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1">
<g id="collapse" sketch:type="MSLayerGroup" transform="translate(-1.000000, -1.000000)">

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="18" viewBox="0 0 18 18">
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M17.569 8.246l-10.569-6.246c-0.552 0-1 0.448-1 1v1.954l-5-2.954c-0.552 0-1 0.448-1 1v12c0 0.552 0.448 1 1 1l5-2.955v1.955c0 0.552 0.448 1 1 1l10.569-6.246c0.267-0.158 0.431-0.444 0.431-0.754s-0.164-0.597-0.431-0.754zM6 10.722l-4 2.364v-8.172l4 2.364v3.444zM8 13.086v-8.172l6.915 4.086-6.915 4.086z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 635 B

After

Width:  |  Height:  |  Size: 480 B

View File

@ -1,9 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title>muted</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<g id="Page-1" stroke="none" stroke-width="1" sketch:type="MSPage">
<g id="sound" sketch:type="MSLayerGroup" transform="translate(0.000000, 2.000000)">
<path d="M9.214,0 C9.103,0 8.989,0.032 8.88,0.101 L4.832,2.911 C4.749,2.969 4.65,3 4.549,3 L0.996,3 C0.446,3 1.33226763e-15,3.448 1.33226763e-15,4 L1.33226763e-15,10 C1.33226763e-15,10.552 0.446,11 0.996,11 L4.549,11 C4.651,11 4.749,11.031 4.832,11.089 L8.88,13.899 C8.989,13.968 9.103,14 9.214,14 C9.606,14 9.961,13.6 9.961,13.051 L9.961,0.95 C9.961,0.4 9.606,0.001 9.214,0.001 L9.214,0 Z M7.969,10.834 L5.582,9.177 C5.416,9.062 5.218,8.999 5.016,8.999 L2.491,8.999 C2.216,8.999 1.993,8.775 1.993,8.499 L1.993,5.499 C1.993,5.223 2.216,4.999 2.491,4.999 L5.016,4.999 C5.218,4.999 5.416,4.937 5.582,4.821 L7.969,3.164 L7.969,10.833 L7.969,10.834 Z" id="Shape" sketch:type="MSShapeGroup"></path>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title>pause</title>
<desc>Created with Sketch.</desc>
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" sketch:type="MSPage">
<g id="pause" sketch:type="MSLayerGroup" transform="translate(2.000000, 2.000000)">

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 927 B

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="18" viewBox="0 0 18 18">
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M5 4.914l6.915 4.086-6.915 4.086v-8.172zM4 2c-0.552 0-1 0.448-1 1v12c0 0.552 0.448 1 1 1l10.569-6.246c0.267-0.158 0.431-0.444 0.431-0.754s-0.164-0.597-0.431-0.754l-10.569-6.246z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 515 B

After

Width:  |  Height:  |  Size: 360 B

View File

@ -1,9 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title>icon-restart</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<g id="Page-1" stroke="none" stroke-width="1" sketch:type="MSPage">
<path d="M17,2 C16.448,2 16,2.448 16,3 L16,7.318 L7,2 C6.448,2 6,2.448 6,3 L6,4.954 L1,2 C0.448,2 0,2.448 0,3 L0,15 C0,15.552 0.448,16 1,16 L6,13.045 L6,15 C6,15.552 6.448,16 7,16 L16,10.682 L16,15 C16,15.552 16.448,16 17,16 C17.552,16 18,15.552 18,15 L18,3 C18,2.448 17.552,2 17,2 L17,2 Z M6,10.722 L2,13.086 L2,4.914 L6,7.278 L6,10.722 L6,10.722 Z M8,13.086 L8,4.914 L14.915,9 L8,13.086 L8,13.086 Z" id="Shape" sketch:type="MSShapeGroup" transform="translate(9.000000, 9.000000) scale(-1, 1) translate(-9.000000, -9.000000) "></path>
</g>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 859 B

View File

@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="18px" height="21px" viewBox="0 0 18 21" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title>rewind</title>
<desc>Created with Sketch.</desc>
<svg viewBox="0 0 18 21" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" sketch:type="MSPage">
<path d="M17.569,9.246 L7,3 C6.448,3 6,3.448 6,4 L6,5.954 L1,3 C0.448,3 0,3.448 0,4 L0,16 C0,16.552 0.448,17 1,17 L6,14.045 L6,16 C6,16.552 6.448,17 7,17 L17.569,10.754 C17.836,10.596 18,10.31 18,10 C18,9.69 17.836,9.403 17.569,9.246 L17.569,9.246 Z M6,11.722 L2,14.086 L2,5.914 L6,8.278 L6,11.722 L6,11.722 Z M8,14.086 L8,5.914 L14.915,10 L8,14.086 L8,14.086 Z" id="Shape" sketch:type="MSShapeGroup" transform="translate(9.000000, 10.000000) rotate(-180.000000) translate(-9.000000, -10.000000) "></path>

Before

Width:  |  Height:  |  Size: 1021 B

After

Width:  |  Height:  |  Size: 847 B

View File

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by IcoMoon.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="18" height="18" viewBox="0 0 18 18">
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M10.214 2c-0.111 0-0.225 0.032-0.334 0.101l-4.048 2.81c-0.083 0.058-0.182 0.089-0.283 0.089h-3.553c-0.55 0-0.996 0.448-0.996 1v6c0 0.552 0.446 1 0.996 1h3.553c0.102 0 0.2 0.031 0.283 0.089l4.048 2.81c0.109 0.069 0.223 0.101 0.334 0.101 0.392 0 0.747-0.4 0.747-0.949v-12.101c0-0.55-0.355-0.949-0.747-0.949zM8.969 12.834l-2.387-1.657c-0.166-0.115-0.364-0.178-0.566-0.178h-2.525c-0.275 0-0.498-0.224-0.498-0.5v-3c0-0.276 0.223-0.5 0.498-0.5h2.525c0.202 0 0.4-0.062 0.566-0.178l2.387-1.657v7.669z"></path>
<path d="M16.934 8.799c-0.086-1.748-1.514-2.991-2.507-3.649-0.47-0.312-1.094-0.122-1.325 0.408l-0.038 0.086c-0.188 0.431-0.045 0.939 0.336 1.194 0.706 0.473 1.586 1.247 1.624 2.065 0.032 0.676-0.553 1.468-1.663 2.27-0.398 0.288-0.529 0.839-0.285 1.275l0.042 0.075c0.266 0.475 0.866 0.624 1.3 0.312 1.74-1.251 2.586-2.606 2.516-4.037z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1018 B