Compare commits

...

337 Commits

Author SHA1 Message Date
39a0a38d07 Bug fix for undefined progress bar 2016-05-01 15:04:09 +10:00
a316514ca1 Minor bug fixes 2016-05-01 13:39:53 +10:00
3b69f47590 v1.6.2 2016-05-01 12:52:07 +10:00
8172e2339d Caption change position on controls hidden 2016-05-01 12:49:04 +10:00
44bb6c077c Fixed merge 2016-05-01 12:00:37 +10:00
e11a58a841 Bug fixes 2016-05-01 11:30:51 +10:00
Sam
c4e3b5a242 Bug fixes 2016-05-01 00:35:30 +10:00
f1b44e6da0 Error handling 2016-04-30 19:52:10 +10:00
aa093b6c42 Merge branch 'pr/196' into develop
# Conflicts:
#	dist/plyr.js
2016-04-30 11:08:42 +10:00
Sam
97870a7cdc Merge branch 'master' of https://github.com/Selz/plyr 2016-04-28 23:35:26 +10:00
Sam
9a6433488f Tooltip bug fixes 2016-04-28 23:35:18 +10:00
993617f75f Remove badges (broken since GitHub caching changes) 2016-04-28 22:55:47 +10:00
Sam
e3baa43b22 Docs 2016-04-28 22:24:54 +10:00
Sam
7a332f29ea Typo 2016-04-28 22:22:32 +10:00
Sam
14c21422e7 URL fix 2016-04-28 22:21:03 +10:00
Sam
fe411b1ede Screenshot 2016-04-28 22:17:45 +10:00
Sam
4f02e2d6e7 Docs updates, small tweaks 2016-04-28 22:07:35 +10:00
4719766843 Merge branch 'develop' of github.com:selz/plyr into develop
# Conflicts:
#	dist/plyr.css
2016-04-28 18:35:21 +10:00
85600ef685 Max width on range progress indicators 2016-04-28 18:33:58 +10:00
f7edd84125 Bug fixes 2016-04-28 13:57:01 +10:00
27e3583fbc Merge branch 'develop' of github.com:selz/plyr into develop 2016-04-28 08:36:30 +10:00
12d1a03bc4 Margins 2016-04-28 08:36:23 +10:00
Sam
d3028b9a03 iconUrl option 2016-04-28 00:14:20 +10:00
2385291886 Volume fixes, iOS bug fixes 2016-04-27 22:47:03 +10:00
cb0b22574a Input progress for volume, fixes for playback progress 2016-04-27 22:22:17 +10:00
4a1adf92e2 Color 2016-04-27 08:46:36 +10:00
b077bb9f5f Docs tweaks 2016-04-27 00:34:44 +10:00
Sam
68c4b52dfa Mute volume toggle fixes 2016-04-27 00:15:29 +10:00
81ad9cf6f7 Audio styles, docs tweaks, package updates 2016-04-26 23:06:30 +10:00
Sam
024706f2ff Tab shows controls 2016-04-26 22:24:20 +10:00
Sam
57b3b9e3f6 Audio styles 2016-04-26 21:15:36 +10:00
6c8d118f83 WIP 2016-04-26 19:14:42 +10:00
48399f6364 Merge remote-tracking branch 'org/develop' into develop 2016-04-25 22:43:44 -07:00
Sam
e26694c322 Work on Audio UI 2016-04-25 22:48:40 +10:00
d41249bd90 WIP 2016-04-25 21:24:07 +10:00
Sam
833d3ac36f Tweaks 2016-04-25 20:05:01 +10:00
fdaeecbb06 Merge branch 'master' into develop 2016-04-25 19:11:00 +10:00
70297321c3 Merge branch 'develop' of github.com:selz/plyr into develop
# Conflicts:
#	.gitignore
#	dist/plyr.css
#	dist/plyr.js
#	dist/sprite.svg
#	docs/dist/docs.css
#	docs/dist/docs.js
#	docs/src/less/components/examples.less
#	src/js/plyr.js
#	src/less/plyr.less
#	src/sprite/icon-fast-forward.svg
#	src/sprite/icon-pause.svg
#	src/sprite/icon-play.svg
#	src/sprite/icon-rewind.svg
2016-04-25 19:10:10 +10:00
a02609c3e3 ignore 2016-04-25 19:07:17 +10:00
ffebc7b077 UI tweaks 2016-04-25 19:06:55 +10:00
47e0800f02 Add support for soundcloud 2016-04-17 20:57:55 -07:00
c7c7902769 Merge pull request #179 from prince-0203/update-readme-outdated-contents
Update outdated contents in readme.md
2016-04-18 10:25:23 +10:00
5bb4d70cf7 Merge branch 'master' of github.com:selz/plyr 2016-03-27 18:30:20 +11:00
67b2f2510b Bug fix for embeds: play not being defined (fixes #185 and #186) 2016-03-27 18:29:58 +11:00
ba9434b6f2 Merge pull request #184 from iamvlado/patch-1
fix type error
2016-03-20 15:26:25 +11:00
26469452e1 fix type error 2016-03-19 17:29:15 +02:00
6ae2655923 Version bump 2016-03-14 22:53:11 +11:00
815100cff8 Autoplay bug fixes 2016-03-14 22:50:34 +11:00
33771ef8c0 Merge branch 'master' of github.com:selz/plyr 2016-03-14 22:34:44 +11:00
b51a1684dc Fix for embed property not being set 2016-03-14 22:34:28 +11:00
ba9abdc1d3 Update readme.md 2016-03-13 22:45:47 +11:00
6a8803ec9f Update readme.md 2016-03-13 22:45:27 +11:00
bcb5b981f9 Update readme.md 2016-03-13 22:44:14 +11:00
5ea9e59d71 SASS fixes, docs changes (fixes #180), 'ready' event 2016-03-13 21:45:57 +11:00
01b45e7d97 Merge branch 'master' of github.com:selz/plyr 2016-03-13 21:23:00 +11:00
c41e5320c8 SASS fixes, Default font stack added 2016-03-13 21:22:51 +11:00
426c0f5559 Merge pull request #181 from shakeelmohamed/bugfix/youtube-autoplay
Dynamically set YouTube autoplay from config
2016-03-13 18:29:49 +11:00
c636f0e69e Dynamically set YouTube autoplay from config
The YouTube autoplay doesn't work without this
change.
2016-03-12 14:05:33 -08:00
58342cfae8 Update outdated contents in readme.md 2016-03-12 14:07:37 +09:00
193103cb2d Update readme.md 2016-03-07 23:18:56 +11:00
f9c593d2f9 Update readme.md 2016-03-07 23:16:46 +11:00
87d174ac2c Bug fixes and native APIs exposed for embeds 2016-03-07 22:28:30 +11:00
cd83a2670b Cancel requests on source change (Fixes #174) 2016-02-28 12:50:34 +11:00
1bbc47c64f CustomEvent polyfill (Fixes #172) 2016-02-28 11:22:11 +11:00
7a1a5830aa Remove version from source 2016-02-25 19:36:14 +11:00
1ecbec4044 Volume storage fix (Fixes #171) 2016-02-25 19:35:03 +11:00
ab329b99df Merge branch 'master' of github.com:selz/plyr 2016-02-23 15:11:48 +11:00
54af43dd75 Docs code 2016-02-23 15:11:35 +11:00
188a2e72eb Update readme.md 2016-02-21 14:34:49 +11:00
b7a14be2ac Removed npm log 2016-02-21 14:33:34 +11:00
c99f20d5d8 Fix for manual captions 2016-02-21 14:28:01 +11:00
5b968c97f4 v1.5.12 2016-02-21 14:07:17 +11:00
d538cdcdf6 1.5.12 2016-02-21 14:04:49 +11:00
cad142fe85 Merge branch 'master' of github.com:selz/plyr
# Conflicts:
#	src/js/plyr.js
2016-02-21 14:04:13 +11:00
b18ed03384 WIP on captions bug, manual duration option, reset media object 2016-02-21 13:17:30 +11:00
6a0b3dc823 Merge pull request #168 from gurupras/fix-captions
Fixes for captions
2016-02-21 11:28:15 +11:00
402c45ee2b Updated manual caption split pattern
Previously, Plyr was using a fixed pattern of '\n\n' to split
contents into captions. This does not always work as some VTT files
contain '\r\n'. This commit checks for both.
2016-02-16 20:17:10 -05:00
67f19166ac Some WebVTT fixes to allow manual captions
WebVTT allows additional parameters along with the line that
contains the start and end times. These were not being filtered
out while attempting to manually display captions.
2016-02-16 19:52:08 -05:00
32b7b6b886 Merge pull request #167 from ivanvermeyen/patch-1
Allow player control colors to be overridden #158
2016-02-15 11:50:38 +11:00
96df8fbc85 Update readme.md 2016-02-14 14:04:30 +11:00
e742527e65 Version bump 2016-02-13 22:23:11 +11:00
f426af6e9e 1.5.11 2016-02-13 22:19:48 +11:00
aea86b6124 Merge branch 'master' of github.com:selz/plyr
# Conflicts:
#	dist/plyr.js
2016-02-13 22:19:31 +11:00
ce51344269 iOS fix (Fixes #166), Edge Progress Tip (Fixes #160), SASS fix (Fixes #158) 2016-02-13 22:18:42 +11:00
7d0311fd64 Allow player control colors to be overridden #158 2016-02-12 17:11:07 +01:00
89e000f669 Update readme.md 2016-02-09 14:53:57 +11:00
f341f1264d Update readme.md 2016-02-09 14:53:20 +11:00
c687b867e7 Update readme.md 2016-02-09 14:52:37 +11:00
4ee31ba661 Update readme.md 2016-02-09 14:40:26 +11:00
a9126a4c82 Update readme.md 2016-02-05 00:02:24 +11:00
6b70c4b49a Update readme.md 2016-02-04 14:59:59 +11:00
d8fb876c81 Update readme.md 2016-02-04 14:58:00 +11:00
73e6ad610f Merge pull request #156 from mortonfox/patch-1
Fix the svgfixer.js link
2016-02-02 09:35:31 +11:00
eee7553d09 Fix the svgfixer.js link 2016-02-01 16:14:22 -05:00
130b5ebedf Update readme.md 2016-01-29 10:25:39 +11:00
dae5fb9785 Merge pull request #154 from marvinhagemeister/fix_window_usage
Get the proper reference to window on initialization.
2016-01-28 09:19:25 +11:00
31a0eb8d14 Get the proper window reference on initialization.
The previous code assumed that `this` points to the browsers
window object, which is not the case when using a module bundler.

So we check for the variable `window` first, before falling back
to `this`.

(taken from jQuery's codebase)
2016-01-27 21:27:58 +01:00
b8b611fbb6 Merge pull request #152 from marvinhagemeister/fix_commonjs
Swap CommonJS and AMD module check so that CommonJS is checked first
2016-01-27 08:45:10 +11:00
a285fcc4ec Check for module.exports as well for CommonJS Modules 2016-01-26 17:05:57 +01:00
4fda65c862 Swap CommonJS and AMD module check so that CommonJS is checked first. Fixes Webpack module bundling 2016-01-26 16:53:15 +01:00
a8cea7b5c9 1.5.10 2016-01-26 22:44:09 +11:00
01bdcc2b01 Merge pull request #151 from marvinhagemeister/fix_npm
Fix broken npm require/import
2016-01-26 20:44:44 +11:00
812d2d33f2 NPM package main must always be the main source file. Fixes broken require/import 2016-01-26 10:21:03 +01:00
a59073c5ca Update readme.md 2016-01-26 10:16:02 +11:00
7edc3ccd53 NPM updates and published (fixes #146) 2016-01-26 10:08:19 +11:00
b217e23880 Npm changes 2016-01-26 09:59:17 +11:00
053b6c2e3f Merge pull request #150 from marvinhagemeister/remove_global
Remove global preinstall script
2016-01-26 09:33:49 +11:00
0d426ca479 Remove global preinstall script. Gulp does not have to be globally installed to build plyr 2016-01-25 16:35:54 +01:00
a327056789 Seek fixes for touch 2016-01-25 11:25:32 +11:00
b006b73c69 Fix for control tooltips always showing 2016-01-25 11:02:35 +11:00
3127cea1b2 SASS fix (fixes #149) 2016-01-25 08:36:53 +11:00
a965d8a893 Seek tooltip, bug fixes for SASS, fullscreen and icons 2016-01-24 11:25:31 +11:00
173e651e3f Comment 2016-01-23 12:24:58 +11:00
fa5cb828c0 Update controls.md 2016-01-21 09:49:00 +11:00
5978810b7f Update controls.md 2016-01-21 09:48:46 +11:00
6c251794c8 Merge branch 'master' of github.com:selz/plyr 2016-01-21 09:43:40 +11:00
76917751e3 Small bug fixes 2016-01-21 09:43:27 +11:00
e75a9b89b0 Merge pull request #147 from christianpv/patch-3
Update bundles.json - Fix path to sass dir.
2016-01-21 09:06:08 +11:00
a0fe61011f Update bundles.json - Fix path to sass dir. 2016-01-20 12:40:04 -05:00
84a1b03d7d Docs update 2016-01-19 17:15:50 +11:00
b9177e7892 Minor bug fix for clicking video to play/pause after source change 2016-01-19 11:36:30 +11:00
fd12247a62 Fix for video click 2016-01-19 11:34:04 +11:00
20a71300a5 Controls 2016-01-19 09:54:23 +11:00
70c5b24678 Added reference 2016-01-19 09:35:10 +11:00
a87e87f93c Version bump 2016-01-19 09:32:04 +11:00
1b54ff0ad3 Listen for durationchange 2016-01-19 09:30:37 +11:00
3075e1eda2 Docs 2016-01-19 09:22:39 +11:00
8d1e014a40 Docs 2016-01-19 00:46:00 +11:00
0c52fe0c7c Added events line 2016-01-19 00:43:22 +11:00
bb25f8d02a Removed broken links 2016-01-19 00:41:30 +11:00
42c955c5eb Removed onSetup from docs code 2016-01-19 00:33:22 +11:00
268223ac52 Version bump 2016-01-19 00:31:28 +11:00
b81b8c1d31 Event listeners 2016-01-19 00:30:25 +11:00
5b2a016241 Merge branch 'master' of github.com:selz/plyr 2016-01-18 19:48:20 +11:00
a665121b52 Types enum 2016-01-18 19:48:14 +11:00
02d312f2d2 Style tweaks 2016-01-18 18:27:01 +11:00
c23c150fe9 Merge branch 'master' of https://github.com/Selz/plyr 2016-01-18 17:35:32 +11:00
2e5bdb338e Tidying up, Vimeo fix 2016-01-18 17:35:18 +11:00
c51ef05067 Update readme.md 2016-01-18 11:24:31 +11:00
Sam
dbe152a4c1 LESS/SASS variable name spacing and clean up 2016-01-17 19:22:43 +11:00
3f42e53d95 Don't add video hash 2016-01-17 10:48:26 +11:00
54b0dc5273 Docs tweak 2016-01-17 10:41:13 +11:00
d6b67c3388 Docs pushstate for tabs 2016-01-17 10:39:05 +11:00
Sam
a277224ef4 Reverted docs.js changes 2016-01-17 01:29:34 +11:00
Sam
f87a10ae0b Fix for event listeners being duplicated on source change 2016-01-17 01:25:11 +11:00
f18fb3f26d Update readme.md 2016-01-16 13:51:18 +11:00
71359a3ff2 Merge branch 'master' of github.com:selz/plyr
# Conflicts:
#	readme.md
2016-01-16 13:48:26 +11:00
6edc6ac680 Image 2016-01-16 13:48:11 +11:00
bf2b6c3c96 Update readme.md 2016-01-16 13:46:09 +11:00
b904e640f7 Docs update 2016-01-16 13:45:41 +11:00
1ddb4eb60c HTTPS, docs update 2016-01-16 13:20:50 +11:00
891abd1d4a Final tweaks for v1.5 and IE9 2016-01-16 13:02:04 +11:00
aed7db34ea Comments 2016-01-15 15:19:20 +11:00
90608e9e1a Vimeo iOS fix 2016-01-15 15:11:02 +11:00
70b4b14984 iOS fixes 2016-01-15 15:07:31 +11:00
9fbbb474db Clean up 2016-01-14 23:50:00 +11:00
bc7a6ebdde Keyboard nav fixes (seek & focus trap in fullscreen), SASS updates 2016-01-14 21:20:46 +11:00
353d920e25 Minor tweaks to custom handler stuff 2016-01-14 19:34:09 +11:00
6110098e97 Merge pull request #141 from gurupras/gurupras-develop
Added new configuration option 'handlers'
2016-01-14 19:21:31 +11:00
b5092c338c Added new configuration option 'handlers'
This option allows developers to attach their custom handlers
before internal plyr's handlers. This should enable developers
to have full control over all the buttons including the ability
to stop event propagation if desired.
2016-01-14 03:01:51 -05:00
cce7e9932e Merge for new source api changes 2016-01-14 09:53:58 +11:00
e6c30ec137 Merge branch 'master' into develop
# Conflicts:
#	dist/plyr.js
#	readme.md
#	src/js/plyr.js
2016-01-14 09:42:36 +11:00
9bcd0434db Built JS 2016-01-14 09:39:10 +11:00
debdf112cc Merge pull request #140 from gurupras/gurupras-develop
Updated API function 'plyr.source()' to get media source
2016-01-14 09:35:01 +11:00
533bd173b2 Updated API function 'plyr.source()' to get media source
Currently, there is no simple way of acquiring media source.
This commit updates the 'source' API function to allow developers
to acquire the video source regardless of whether the video
is a youtube-embed or HTML5 video.

Future embeds just need their respective URL fetching code added
to this common function.
2016-01-13 17:19:19 -05:00
e05538e480 Tab focus 2016-01-14 01:19:48 +11:00
38f554b480 Tidying up 2016-01-14 01:14:22 +11:00
7d487553b2 Tab focus tweaks 2016-01-14 00:59:18 +11:00
ca8fd08e81 Use only one index.html for testing locally, fixes for limited controls, larger seek handle 2016-01-14 00:23:57 +11:00
bc67d969cb Froogaloop fixes (custom version), docs sprite, source api changes 2016-01-13 23:12:16 +11:00
c449fc0867 Controls bug fix 2016-01-12 22:31:37 +11:00
18b2d81985 Media paused state for embeds 2016-01-11 08:52:04 +11:00
533af96c4f Merge pull request #134 from gurupras/gurupras-develop
Fixed embedded Plyr not updating plyr.media.paused
2016-01-11 08:49:53 +11:00
be8b4d2735 Fixed embedded Plyr not updating plyr.media.paused 2016-01-10 12:46:56 -05:00
7d077d543b Fullscreen fixes 2016-01-11 00:07:13 +11:00
9b09c9c7a0 Work on v1.5
See changelog.md
2016-01-10 21:40:22 +11:00
Sam
592bcc8d7e Prep for v1.5 2016-01-10 15:08:58 +11:00
Sam
30529ee4e4 New vimeo vid 2015-12-13 22:57:06 +11:00
Sam
ee2cdb2c9b Merge branch 'master' into develop
# Conflicts:
#	dist/plyr.css
#	dist/plyr.js
#	docs/dist/docs.css
#	docs/dist/docs.js
#	docs/index.html
#	docs/src/js/docs.js
#	docs/src/less/components/icons.less
#	docs/src/less/components/type.less
#	docs/src/less/docs.less
#	gulpfile.js
#	package.json
#	src/js/plyr.js
2015-12-13 22:49:02 +11:00
1371c1341f Removed Hogan from Docs (Fixes #128) 2015-12-11 10:41:29 +11:00
05bf08a438 Merge branch 'master' of github.com:selz/plyr 2015-12-11 10:01:12 +11:00
Sam
1e03aa1360 Docs update - removed button counts temporarily 2015-11-26 18:26:26 +11:00
7463e31f95 Merge pull request #123 from ciceropablo/master
Fix typo
2015-11-17 09:40:23 +11:00
83caa3f55a Fix typo 2015-11-16 20:30:29 -02:00
787465d626 Merge pull request #122 from DarthUjj/patch-1
Cleanup README a bit
2015-11-09 09:08:12 +11:00
33357a5992 Cleanup README a bit 2015-11-09 00:06:35 +05:30
cd2532867c Vimeo mute 2015-10-25 12:13:12 +11:00
8f80e4fa65 Fragaloop and docs 2015-10-25 12:02:42 +11:00
125a95e9e1 Audio fullscreen, Tooltip tweaks, Docs 2015-10-25 11:57:52 +11:00
58f8cdd8c8 Sass updated 2015-10-05 16:38:02 +11:00
b164a2f3fb Setup improvements, player -> plyr, docs (WIP) 2015-10-05 16:33:26 +11:00
262c9f9e13 Removed Hogan stuff 2015-10-05 02:01:43 +11:00
2c4c8c58d5 Docs tweaks 2015-10-05 01:39:55 +11:00
daec1baebc Source API changes, Vimeo fixes, still WIP 2015-10-04 19:27:30 +11:00
0674e13bab Icon tweaks, other small tweaks 2015-10-03 10:43:27 +10:00
aee076dc3b Added autoplay option 2015-10-03 08:49:07 +10:00
66969f1a65 Fix for multiple YouTube instances (Fixes #114) 2015-09-13 09:56:59 +10:00
e964c1a298 Docs 2015-09-06 15:34:13 +10:00
941b4c1c20 Merge 2015-08-27 07:36:59 +10:00
95e39e7bd7 Merge branch 'master' into develop
# Conflicts:
#	dist/plyr.css
#	dist/plyr.js
#	docs/dist/docs.css
#	docs/src/less/components/examples.less
#	src/js/plyr.js
2015-08-27 07:36:17 +10:00
0785ca6024 Vimeo 2015-08-27 07:30:14 +10:00
6543fc1e5b Fixed bug with API use on basic supported browsers 2015-08-21 21:36:15 +10:00
9133247cdf Code cleanup 2015-08-13 21:34:17 +10:00
bf7f6f40bd Merge pull request #111 from calvintam236/master
Code cleanup
2015-08-13 21:32:10 +10:00
43a904917f Fixed equal signs 2015-08-13 01:39:13 -07:00
9fe6e5ffcb Converted double quote to single quote 2015-08-13 01:36:20 -07:00
a46e421bf6 Fixed syntax; Fixed some JSHint errors (Not escaped character, etc.) 2015-08-13 01:15:57 -07:00
20090aee03 Fixed missing semicolons mentioned by JSHint 2015-08-13 00:43:11 -07:00
c4ca7fe0d2 Updated tag closing 2015-08-13 00:38:30 -07:00
6b41752415 Use defined function instead of hard coding 2015-08-13 00:13:57 -07:00
2bc53d12ea Use double quote for html strings 2015-08-12 23:38:39 -07:00
2f6dc5279b Removed unnecessary "break"s 2015-08-12 23:13:58 -07:00
c8b2867b1f Removed useless spaces 2015-08-12 23:13:13 -07:00
e56132ae3b Standardized syntax 2015-08-12 22:58:33 -07:00
45d4091c20 Merge branch 'master' of github.com:selz/plyr 2015-08-11 22:38:45 +10:00
60c53a5894 Removed captions being read by screen readers 2015-08-11 22:38:06 +10:00
032c823d3a Merge pull request #108 from ChristianPV/patch-2
Update plyr.scss - Fix new scss!
2015-08-10 23:31:31 +10:00
66f724a3be Update plyr.scss - Fix new scss!
This is a fix the newly added scss.
2015-08-10 10:03:21 -03:00
bf0c81b484 Docs 2015-08-09 09:29:33 +10:00
aa72a17f44 Version bump 2015-08-08 21:02:55 +10:00
8825e82634 Merge branch 'master' of github.com:selz/plyr 2015-08-08 21:01:39 +10:00
f700d50dc8 Fix for voiceover 2015-08-08 21:01:06 +10:00
a585270d21 Update readme.md 2015-08-08 20:38:21 +10:00
7a23dda294 Typo 2015-08-08 18:13:14 +10:00
f3c324038f ARIA improvements for caption reading 2015-08-08 15:16:42 +10:00
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
aa1fed0b16 Fixed bug with media longer than 60 minutes (Fixes #69) 2015-03-30 19:17:27 +11:00
22331ae9f1 Added mention 2015-03-22 23:24:15 +11:00
8b436276bf Fixed bug with caption toggle, hide controls in fullscreen 2015-03-22 21:26:29 +11:00
c61db87fd6 API improvements 2015-03-22 11:05:28 +11:00
388cb4df39 Keyboard accessibility improvements (Fixes #66)
- Enter now works on checkboxes within the controls
2015-03-21 17:00:05 +11:00
9feffb2972 Version bump 2015-03-15 10:18:56 +11:00
acea5cdb24 Built js 2015-03-15 10:14:00 +11:00
55ed577b6a Indentation
Converted to 4 space width tabbing
2015-03-15 10:12:36 +11:00
20b206a161 Merge pull request #62 from brunowego/patch-1
Updated SASS support
2015-03-15 10:00:00 +11:00
9c028a0ecc Updated SASS support 2015-03-14 15:50:32 -03:00
b677c3d7ad Merge branch 'master' of https://github.com/selz/plyr
Conflicts:
	dist/plyr.js
	src/js/plyr.js
2015-03-10 23:57:36 +11:00
aa6bc2df2f Fixes for volume control on iOS 2015-03-10 23:54:52 +11:00
a16579fd21 Fix for repo url 2015-03-09 11:53:26 +11:00
ae5a816df1 Fix for potential issue with .tagName 2015-03-09 11:51:01 +11:00
1532f2ab23 Added tooltip option (Fixes #50) 2015-03-09 00:47:38 +11:00
56 changed files with 6541 additions and 3476 deletions

5
.gitignore vendored
View File

@ -4,3 +4,8 @@ node_modules
.DS_Store
aws.json
docs/index.dev.html
*.mp4
index-dev.html
notes.txt
*.vtt
docs/index.dev.php

View File

@ -9,8 +9,7 @@
"rhino" : false,
"couch" : false,
"wsh" : true, // Windows Scripting Host.
"jquery" : true,
"predef" : [ "jQuery", "$" ],
"jquery" : false,
// Development.
"debug" : false, // Allow debugger statements e.g. browser breakpoints.
@ -51,6 +50,6 @@
"plusplus" : false, // Prohibit use of `++` & `--`.
"sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`.
"trailing" : true, // Prohibit trailing whitespaces.
"white" : false, // Check against strict whitespace and indentation rules.
"indent" : 2 // Specify indentation spacing
"white" : true, // Check against strict whitespace and indentation rules.
"indent" : 4 // Specify indentation spacing
}

View File

@ -1,33 +1,33 @@
{
"name": "plyr",
"description": "A simple HTML5 media player using custom controls",
"homepage": "http://plyr.io",
"keywords": [
"Audio",
"Video",
"HTML5 Audio",
"HTml5 Video"
],
"authors": [
"Sam Potts <me@sampotts.me>"
],
"dependencies": {},
"main": [
"dist/plyr.css",
"dist/plyr.js",
"dist/sprite.svg",
"src/less/plyr.less",
"src/sass/plyr.sass",
"src/js/plyr.js"
],
"ignore": [
"node_modules",
"bower_components",
".gitignore"
],
"repository": {
"type": "git",
"url": "git://github.com/selz/plyr.git"
},
"license": "MIT"
}
"name": "plyr",
"description": "A simple HTML5 media player using custom controls",
"homepage": "http://plyr.io",
"keywords": [
"Audio",
"Video",
"HTML5 Audio",
"HTml5 Video"
],
"authors": [
"Sam Potts <me@sampotts.me>"
],
"dependencies": {},
"main": [
"dist/plyr.css",
"dist/plyr.js",
"dist/sprite.svg",
"src/less/plyr.less",
"src/scss/plyr.scss",
"src/js/plyr.js"
],
"ignore": [
"node_modules",
"bower_components",
".gitignore"
],
"repository": {
"type": "git",
"url": "git://github.com/selz/plyr.git"
},
"license": "MIT"
}

View File

@ -1,25 +1,24 @@
{
"plyr": {
"less": {
"plyr.css": ["src/less/plyr.less"]
},
"sass": {
"plyr.css": ["src/less/plyr.sass"]
},
"js": {
"plyr.js": ["src/js/plyr.js"]
}
},
"docs": {
"less": {
"docs.css": ["docs/src/less/docs.less"]
},
"js": {
"docs.js": [
"docs/src/js/lib/hogan-3.0.2.mustache.js",
"docs/dist/templates.js",
"docs/src/js/docs.js"
]
}
}
}
"plyr": {
"less": {
"plyr.css": ["src/less/plyr.less"]
},
"scss": {
"plyr.css": ["src/scss/plyr.scss"]
},
"js": {
"plyr.js": ["src/js/plyr.js"]
}
},
"docs": {
"less": {
"docs.css": ["docs/src/less/docs.less"]
},
"js": {
"docs.js": [
"docs/src/js/lib/classlist.js",
"docs/src/js/docs.js"
]
}
}
}

View File

@ -1,17 +1,266 @@
# Changelog
## v1.6.4
- Bug fix for undefined progress bar
## v1.6.3
- Seek back to 0 for all media on ended
- Check for HTML5 video on ended reload
- Update to docs for `showPosterOnEnd` option
## v1.6.2
- Fix for tooltip displaying when duration is not set (fixes #177)
- `showPosterOnEnd` option to show poster when HTML5 video ended (fixes #59)
- Error handler for YouTube (fixes #189)
- Initial SoundCloud support (fixes #194)
- Other minor bug fixes
## v1.6.1
- Tooltip changes for accessibility
## v1.6.0
- New, cleaner, UI:
- Controls are now overlaid, maintaining the video's ratio and making sizing easier
- A large play button can now be overlaid over videos
- Default number of control buttons reduced
- New play, pause, rewind and fast forward icons
- Flexbox all the things!
- Tidied up the LESS (and SCSS) as part of the above, variables and mixins in seprate files amking customization and upgrades easier
- Toggle mute bug fix; if a player was muted previously and the user refreshed, unmuting would have meant volume was still zero (effectively muted), now the config default value is used. Not ideal but good for now
- New `iconUrl` option allowing specifying a same origin SVG sprite location. Loading this way means you don't need the AJAX sprite loading JavaScript
- `click` option renamed to `clickToPlay` to make it a bit more self explanatory. Unfortunately cross origin SVG sprites is not supported in any browser yet :-(
- `hideControls` is now a global option, rather than being exclusive to fullscreen. Controls are now hidden after 2 seconds of no mouse movement. Controls are always shown when media is paused or stopped. This is defaulted to true.
- `sass` folder in `src` renamed from to `scss`
## v1.5.21
- Bug fix for embeds: `play` not being defined (fixes #185 and #186)
## v1.5.20
- Bug fix for autoplay option
## v1.5.19
- Fix for accessing `embed` property after `ready` event fired
## v1.5.18
- Added 'ready' event for initial setup complete or source change occurs
- Fixed SASS stylesheet references to transparentize
- Added default font stack to controls
- Docs fixes inc controls HTML (fixes #180)
## v1.5.17
- Expose YouTube and Vimeo API (docs update required) (Fixes #176)
- Auto set title based on YouTube getVideoData() title property
- Bug fix for Vimeo API change (Uncaught TypeError: Cannot read property 'value' of undefined) due to a change their end
## v1.5.16
- Cancel requests on source change (Fixes #174)
## v1.5.15
- Fix for CustomEvent polyfill and related bug (See #172)
## v1.5.14
- Volume storage fix (Fixes #171)
## v1.5.13
- Fix for manual caption rendering
## v1.5.12
- Added a duration option to pass the duration of the file
- Added the ability to set options per element by setting a data-plyr attribute on the target elements (this might be useful for the duration option for example)
- Fixes for Chrome and Safari caption rendering, they now use the default texttrack and cuechange events
- Firefox bug fix for event not defined
## v1.5.11
- iOS embed bug fixes (fixes #166)
- Hide IE/Edge <input type='range'> tooltip (since we have a styled one) (fixes #160)
- SASS bug fix for default values (fixes #158)
## v1.5.9 + v1.5.10
- NPM bug fixes
## v1.5.8
- Fix for touch device seek tooltip
- Seek improvements
## v1.5.7
- Fix for control tooltips always showing
## v1.5.6
- Seek tooltip (option for tooltips changed, please check docs)
- SASS compile error fixes (fixes #148)
- Fullscreen fixes for controls not always hiding/showing (fixes #149)
- Screen reader icon fixes (title was being read twice due to the tooltip/hidden label)
## v1.5.5
- Fixed controls.md example
- Bug fix for docs error page
- Bug fix for controls tooltips
## v1.5.4
- Minor bug fix for clicking video to play/pause after source change
## v1.5.3
- Minor bug fix for occasional display of 0:00 as the media duration
## v1.5.2
- `handlers` option renamed to `listeners`
- Added event listeners for all types to the plyr container (playback, fullscreen, captions etc - see docs)
- Removed onSetup config option (use the 'setup' event instead, plyr element is event.plyr)
- Style bug fixes
- Vimeo seek bug fix (requires whole seconds when seeking)
- Fix for fullscreen player (using class hook, not browser fullscreen)
## v1.5.1
- Fix for event listeners being duplicated on source change
# v1.5.0
- Vimeo support (fixes #8)
- New options for initialization (you can now pass a selector, HTMLElement or NodeList) (fixes #118)
- Switched to BEM methodology (you will need to change CSS and probably HTML)
- Decoupled CSS and JS hooks (fixes #129)
- Custom controls container (fixes #98)
- Fix for private/incognito mode local storage bug (fixes #131)
- UMD module setup (fixes #121)
- Specify iframe title for Vimeo and YouTube (fixes #124)
- Better handling of mission controls (fixes #132)
- Retain classname on source change (fixes #120)
- Increased thumb size on seek (partially fixes #130)
- Passing no argument to `source` api method, now returns current source (by @gurupras)
- Ability to add custom handlers to controls prior to Plyr bindings (by @gurupras)
- Keyboard navigation improvements (focus on seek, focus trap in fullscreen) (fixes #135)
## v1.3.5
- Fixed bug with API use on basic supported browsers
## v1.3.4
- Code cleanup by @calvintam236
## v1.3.3
- Removed captions being read by screen readers
## v1.3.2
- Voiceover fix for captions
## v1.3.1
- ARIA improvements for captions being read
## 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)
## v1.0.29
- Added option to hide controls on fullscreen (default `true`) while palying, after 1s. Pause, mouse hover on progress, or focus on a child control re-shows the controls. On touch a tap of the video (which plays/pauses the video by default) is required. (Fixes #47)
- Fixed a bug with caption toggle in 1.0.28
## v1.0.28
- Added API support for browsers that don't have full plyr support (pretty much <=IE9 and `<video>` on iPhone/iPod)
## v1.0.27
- Keyboard accessibility improvements (Fixes #66)
## v1.0.26
- Fixes for SASS (cheers @brunowego)
- Indentation reset to 4 spaces
## v1.0.25
- Fixes for iOS volume controls (hidden)
- Classnames for left/right controls changed
## v1.0.24
- Added tooltip option to display labels as tooltips (Fixes #50)
## v1.0.23
- Handling loading states in the UI
- Handling loading states in the UI (Fixes #36)
## v1.0.22
- Added support() API method for checking mimetype support
- Added source() API method for setting media source(s)
- Added source() API method for setting media source(s) (Fixes #44)
- Added poster() API method for setting poster source
- Refactored captions logic for manual captions
## v1.0.21
- Added an <input type="range"> for seeking to improve experience (and support dragging)
- Icons for restart and captions improved (and some IDs changed)
- Added an <input type="range"> for seeking to improve experience (and support dragging) (Fixes #40, #42)
- Icons for restart and captions improved (and some IDs changed) (Fixes #49)
## v1.0.20
- Default controls included (Fixes #45)
@ -20,7 +269,7 @@
- License changed to MIT
## v1.0.19
- Fixed firefox fullscreen issue (#38)
- Fixed firefox fullscreen issue (Fixes #38)
## v1.0.18
- Added CDN references
@ -86,4 +335,4 @@
- Return instances of Plyr to the element
## v1.0.0
- Initial release
- Initial release

View File

@ -1,82 +1,112 @@
# 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.
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.
The classes and data attributes used in your template should match the `selectors` option.
### Example
```javascript
i18n: {
restart: "Restart",
rewind: "Rewind {seektime} secs",
play: "Play",
pause: "Pause",
forward: "Forward {seektime} secs",
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
You can specify the HTML for the controls using the `html` option.
The classes and data attributes used in your template should match the `selectors` option.
You need to add several placeholders to your html template that are replaced when rendering:
- `{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'>",
"<div class='player-progress'>",
"<label for='seek{id}' class='sr-only'>Seek</label>",
"<input id='seek{id}' class='player-progress-seek' type='range' min='0' max='100' step='0.5' value='0' data-player='seek'>",
"<progress class='player-progress-played' max='100' value='0'>",
"<span>0</span>% played",
"</progress>",
"<progress class='player-progress-buffer' max='100' value='0'>",
var controls = ["<div class='plyr__controls'>",
"<button type='button' data-plyr='restart'>",
"<svg><use xlink:href='#icon-restart'></use></svg>",
"<span class='plyr__sr-only'>Restart</span>",
"</button>",
"<button type='button' data-plyr='rewind'>",
"<svg><use xlink:href='#icon-rewind'></use></svg>",
"<span class='plyr__sr-only'>Rewind {seektime} secs</span>",
"</button>",
"<button type='button' data-plyr='play'>",
"<svg><use xlink:href='#icon-play'></use></svg>",
"<span class='plyr__sr-only'>Play</span>",
"</button>",
"<button type='button' data-plyr='pause'>",
"<svg><use xlink:href='#icon-pause'></use></svg>",
"<span class='plyr__sr-only'>Pause</span>",
"</button>",
"<button type='button' data-plyr='fast-forward'>",
"<svg><use xlink:href='#icon-fast-forward'></use></svg>",
"<span class='plyr__sr-only'>Forward {seektime} secs</span>",
"</button>",
"<span class='plyr__progress'>",
"<label for='seek{id}' class='plyr__sr-only'>Seek</label>",
"<input id='seek{id}' class='plyr__progress--seek' type='range' min='0' max='100' step='0.1' value='0' data-plyr='seek'>",
"<progress class='plyr__progress--played' max='100' value='0' role='presentation'></progress>",
"<progress class='plyr__progress--buffer' max='100' value='0'>",
"<span>0</span>% buffered",
"</progress>",
"</div>",
"<span class='player-controls-playback'>",
"<button type='button' data-player='restart'>",
"<svg><use xlink:href='#icon-restart'></use></svg>",
"<span class='sr-only'>Restart</span>",
"</button>",
"<button type='button' data-player='rewind'>",
"<svg><use xlink:href='#icon-rewind'></use></svg>",
"<span class='sr-only'>Rewind {seektime} seconds</span>",
"</button>",
"<button type='button' data-player='play'>",
"<svg><use xlink:href='#icon-play'></use></svg>",
"<span class='sr-only'>Play</span>",
"</button>",
"<button type='button' data-player='pause'>",
"<svg><use xlink:href='#icon-pause'></use></svg>",
"<span class='sr-only'>Pause</span>",
"</button>",
"<button type='button' data-player='fast-forward'>",
"<svg><use xlink:href='#icon-fast-forward'></use></svg>",
"<span class='sr-only'>Fast forward {seektime} seconds</span>",
"</button>",
"<span class='player-time'>",
"<span class='sr-only'>Time</span>",
"<span class='player-duration'>00:00</span>",
"</span>",
"<span class='plyr__tooltip'>00:00</span>",
"</span>",
"<span class='player-controls-sound'>",
"<input class='inverted sr-only' id='mute{id}' type='checkbox' data-player='mute'>",
"<label id='mute{id}' for='mute{id}'>",
"<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>",
"<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}'>",
"<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 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>",
"<span class='sr-only'>Toggle fullscreen</span>",
"</button>",
"<span class='plyr__time'>",
"<span class='plyr__sr-only'>Current time</span>",
"<span class='plyr__time--current'>00:00</span>",
"</span>",
"</div>"].join("\n");
```
"<span class='plyr__time'>",
"<span class='plyr__sr-only'>Duration</span>",
"<span class='plyr__time--duration'>00:00</span>",
"</span>",
"<button type='button' data-plyr='mute'>",
"<svg class='icon--muted'><use xlink:href='#icon-muted'></use></svg>",
"<svg><use xlink:href='#icon-volume'></use></svg>",
"<span class='plyr__sr-only'>Toggle Mute</span>",
"</button>",
"<span class='plyr__volume'>",
"<label for='volume{id}' class='plyr__sr-only'>Volume</label>",
"<input id='volume{id}' class='plyr__volume--input' type='range' min='0' max='10' value='5' data-plyr='volume'>",
"<progress class='plyr__volume--display' max='10' value='0' role='presentation'></progress>",
"</span>",
"<button type='button' data-plyr='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='plyr__sr-only'>Toggle Captions</span>",
"</button>",
"<button type='button' data-plyr='fullscreen'>",
"<svg class='icon--exit-fullscreen'><use xlink:href='#icon-exit-fullscreen'></use></svg>",
"<svg><use xlink:href='#icon-enter-fullscreen'></use></svg>",
"<span class='plyr__sr-only'>Toggle Fullscreen</span>",
"</button>",
"</div>"].join("");
// Setup the player
plyr.setup('.js-player', {
html: controls
});
```

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

3
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: 3.5 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

1
docs/dist/docs.svg vendored Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg"><symbol id="icon-github" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 .2c-4.4 0-8 3.6-8 8 0 3.5 2.3 6.5 5.5 7.6.4.1.5-.2.5-.4V14c-2.2.5-2.7-1-2.7-1-.4-.9-.9-1.2-.9-1.2-.7-.5.1-.5.1-.5.8.1 1.2.8 1.2.8.7 1.3 1.9.9 2.3.7.1-.5.3-.9.5-1.1-1.8-.2-3.6-.9-3.6-4 0-.9.3-1.6.8-2.1-.1-.2-.4-1 .1-2.1 0 0 .7-.2 2.2.8.6-.2 1.3-.3 2-.3s1.4.1 2 .3c1.5-1 2.2-.8 2.2-.8.4 1.1.2 1.9.1 2.1.5.6.8 1.3.8 2.1 0 3.1-1.9 3.7-3.7 3.9.3.4.6.9.6 1.6v2.2c0 .2.1.5.6.4 3.2-1.1 5.5-4.1 5.5-7.6-.1-4.4-3.7-8-8.1-8z"/></symbol><symbol id="icon-twitter" viewBox="0 0 16 16"><title>Twitter</title><path d="M16 3c-.6.3-1.2.4-1.9.5.7-.4 1.2-1 1.4-1.8-.6.4-1.3.6-2.1.8-.6-.6-1.5-1-2.4-1-1.7 0-3.2 1.5-3.2 3.3 0 .3 0 .5.1.7-2.7-.1-5.2-1.4-6.8-3.4-.3.5-.4 1-.4 1.7 0 1.1.6 2.1 1.5 2.7-.5 0-1-.2-1.5-.4C.7 7.7 1.8 9 3.3 9.3c-.3.1-.6.1-.9.1-.2 0-.4 0-.6-.1.4 1.3 1.6 2.3 3.1 2.3-1.1.9-2.5 1.4-4.1 1.4H0c1.5.9 3.2 1.5 5 1.5 6 0 9.3-5 9.3-9.3v-.4C15 4.3 15.6 3.7 16 3z"/></symbol><symbol id="icon-vimeo" viewBox="0 0 16 16"><path d="M16 4.3c-.1 1.6-1.2 3.7-3.3 6.4-2.2 2.8-4 4.2-5.5 4.2-.9 0-1.7-.9-2.4-2.6C4 9.9 3.4 5 2 5c-.1 0-.5.3-1.2.8l-.8-1c.8-.7 3.5-3.4 4.7-3.5 1.2-.1 2 .7 2.3 2.5.3 2 .8 6.1 1.8 6.1.9 0 2.5-3.4 2.6-4 .1-.9-.3-1.9-2.3-1.1.8-2.6 2.3-3.8 4.5-3.8 1.7.1 2.5 1.2 2.4 3.3z"/></symbol><symbol id="icon-youtube" viewBox="0 0 16 16"><path d="M15.8 4.8c-.2-1.3-.8-2.2-2.2-2.4C11.4 2 8 2 8 2s-3.4 0-5.6.4C1 2.6.3 3.5.2 4.8 0 6.1 0 8 0 8s0 1.9.2 3.2c.2 1.3.8 2.2 2.2 2.4C4.6 14 8 14 8 14s3.4 0 5.6-.4c1.4-.3 2-1.1 2.2-2.4C16 9.9 16 8 16 8s0-1.9-.2-3.2zM6 11V5l5 3-5 3z"/></symbol></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -1,2 +0,0 @@
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-playback\">");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} seconds</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\">Fast forward {seektime} seconds</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-sound\">");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: { }});

View File

@ -1,18 +1,18 @@
<!doctype html>
<html lang="en" class="error">
<head>
<meta charset="utf-8" />
<title>Doh. Looks like something went wrong.</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<head>
<meta charset="utf-8" />
<title>Doh. Looks like something went wrong.</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Docs styles -->
<link rel="stylesheet" href="//cdn.plyr.io/1.0.23/docs.css">
</head>
<body>
<main>
<h1>Doh.</h1>
<p>Looks like something went wrong.</p>
<a href="http://plyr.io" class="btn">Back to plyr.io</a>
</main>
</body>
</html>
<!-- Docs styles -->
<link rel="stylesheet" href="dist/docs.css">
</head>
<body>
<main>
<h1>Doh.</h1>
<p>Looks like something went wrong.</p>
<a href="http://plyr.io" class="btn btn--primary">Back to plyr.io</a>
</main>
</body>
</html>

View File

@ -1,79 +1,131 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Plyr - A simple HTML5 media player</title>
<meta name="description" content="A simple HTML5 media player with custom controls and WebVTT captions.">
<meta name="author" content="Sam Potts">
<meta name="viewport" content="width=device-width, initial-scale=1">
<head>
<meta charset="utf-8" />
<title>Plyr - A simple HTML5 media player</title>
<meta name="description" content="A simple HTML5 media player with custom controls and WebVTT captions.">
<meta name="author" content="Sam Potts">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Styles -->
<link rel="stylesheet" href="//cdn.plyr.io/1.0.23/plyr.css">
<!-- Styles -->
<link rel="stylesheet" href="../dist/plyr.css">
<!-- Docs styles -->
<link rel="stylesheet" href="//cdn.plyr.io/1.0.23/docs.css">
</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>
</header>
<!-- Docs styles -->
<link rel="stylesheet" href="dist/docs.css">
</head>
<body>
<header>
<h1>Plyr</h1>
<p>A simple, accessible HTML5 media player by <a href="https://twitter.com/sam_potts" target="_blank">@sam_potts</a> from <a href="https://twitter.com/selz" target="_blank">@selz</a></p>
<nav>
<ul>
<li>
<a href="https://github.com/selz/plyr" target="_blank" class="btn btn--large btn--primary" data-shr-network="github">
<svg class="icon"><use xlink:href="#icon-github"/></svg>Download on GitHub
</a>
</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 btn--large btn--twitter" data-shr-network="twitter">
<svg class="icon"><use xlink:href="#icon-twitter"/></svg>Tweet
</a>
</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>
<main role="main" id="main">
<nav class="btn__bar">
<ul>
<li class="active">
<button type="button" class="btn" data-source="video">Video</button>
</li>
<li>
<button type="button" class="btn" data-source="audio">Audio</button>
</li>
<li>
<button type="button" class="btn btn--youtube" data-source="youtube"><svg class="icon"><use xlink:href="#icon-youtube"/></svg>YouTube</button>
</li>
<li>
<button type="button" class="btn btn--vimeo" data-source="vimeo"><svg class="icon"><use xlink:href="#icon-vimeo"/></svg>Vimeo</button>
</li>
</ul>
</nav>
<section>
<div class="js-media-player">
<video poster="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg" controls crossorigin>
<!-- Video files -->
<source src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4" type="video/mp4">
<source src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.webm" type="video/webm">
<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>
<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>
</main>
<!-- Text track file -->
<track kind="captions" label="English" srclang="en" src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt" default>
<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>
<!-- 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>
<!-- Load SVG defs -->
<!-- You should bundle all SVG/Icons into one file using a build tool such as gulp and svg store -->
<script>
(function(d,p){var a=new XMLHttpRequest(),b=d.body;a.open("GET",p,!0);a.send();a.onload=function(){var c=d.createElement("div");c.style.display="none";c.innerHTML=a.responseText;b.insertBefore(c,b.childNodes[0])}})(document,"//cdn.plyr.io/1.0.23/sprite.svg");
</script>
<ul>
<li class="plyr__cite plyr__cite--video"><small><a href="http://viewfromabluemoon.com/" target="_blank">View From A Blue Moon</a> &copy; Brainfarm</small></li>
<li class="plyr__cite plyr__cite--audio"><small><a href="http://www.kishibashi.com/" target="_blank">Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;</a> &copy; Kishi Bashi</small></li>
<li class="plyr__cite plyr__cite--youtube"><small><a href="https://www.youtube.com/watch?v=bTqVqk7FSmY" target="_blank">View From A Blue Moon</a> on <span class="color--youtube"><svg class="icon"><use xlink:href="#icon-youtube"/></svg>YouTube</span></small>
<li class="plyr__cite plyr__cite--vimeo"><small><a href="https://vimeo.com/ondemand/viewfromabluemoon4k" target="_blank">View From A Blue Moon</a> on <span class="color--vimeo"><svg class="icon"><use xlink:href="#icon-vimeo"/></svg>Vimeo</span></small>
</ul>
</section>
</main>
<!-- Plyr core script -->
<script src="//cdn.plyr.io/1.0.23/plyr.js"></script>
<!-- Load SVG defs -->
<!-- You should bundle all SVG/Icons into one file using a build tool such as gulp and svg store -->
<script>
(function() {
[
'../dist/sprite.svg',
'dist/docs.svg'
]
.forEach(function(u) {
var x = new XMLHttpRequest(),
b = document.body;
<!-- Docs script -->
<script src="//cdn.plyr.io/1.0.23/docs.js"></script>
</body>
</html>
// Check for CORS support
// If you're loading from same domain, you can remove the whole if/else statement
// XHR for Chrome/Firefox/Opera/Safari/IE10+
if ('withCredentials' in x) {
x.open('GET', u, true);
}
// XDomainRequest for IE8 & IE9
else if (typeof XDomainRequest == 'function') {
x = new XDomainRequest();
x.open('GET', u);
}
else { return; }
// Inject hidden div with sprite on load
x.onload = function() {
var c = document.createElement('div');
c.setAttribute('hidden', '');
c.innerHTML = x.responseText;
b.insertBefore(c, b.childNodes[0]);
}
// Timeout for IE9
setTimeout(function () {
x.send();
}, 0);
});
})();
</script>
<!-- Plyr core script -->
<script src="../dist/plyr.js"></script>
<!-- Docs script -->
<script src="dist/docs.js"></script>
<!-- Rangetouch to fix <input type="range"> on touch devices (see https://rangetouch.com) -->
<script src="https://cdn.rangetouch.com/0.0.9/rangetouch.js"></script>
<!-- Sharing libary (https://shr.one) -->
<script src="https://cdn.shr.one/0.1.9/shr.js"></script>
<script>if(window.shr) { window.shr.setup({ count: { classname: 'btn__count' } }); }</script>
</body>
</html>

View File

@ -2,25 +2,177 @@
// Docs example
// ==========================================================================
/*global plyr, templates */
/*global plyr*/
// Setup the player
plyr.setup({
debug: true,
title: "Video demo",
html: templates.controls.render({}),
plyr.setup('.js-media-player', {
debug: true,
title: 'Video demo',
tooltips: {
controls: true
},
captions: {
defaultActive: true
defaultActive: true
}
});
// Google analytics
// General functions
(function() {
var buttons = document.querySelectorAll('[data-source]'),
types = {
video: 'video',
audio: 'audio',
youtube: 'youtube',
vimeo: 'vimeo'
},
currentType = window.location.hash.replace('#', ''),
historySupport = (window.history && window.history.pushState);
// Bind to each button
for (var i = buttons.length - 1; i >= 0; i--) {
buttons[i].addEventListener('click', function() {
var type = this.getAttribute('data-source');
newSource(type);
if (historySupport) {
history.pushState({ 'type': type }, '', '#' + type);
}
});
}
// List for backwards/forwards
window.addEventListener('popstate', function(event) {
if(event.state && 'type' in event.state) {
newSource(event.state.type);
}
});
// On load
if(historySupport) {
var video = !currentType.length;
// If there's no current type set, assume video
if(video) {
currentType = types.video;
}
// Replace current history state
if(currentType in types) {
history.replaceState({ 'type': currentType }, '', (video ? '' : '#' + currentType));
}
// If it's not video, load the source
if(currentType !== types.video) {
newSource(currentType, true);
}
}
// Toggle class on an element
function toggleClass(element, className, state) {
if (element) {
if (element.classList) {
element.classList[state ? 'add' : 'remove'](className);
}
else {
var name = (' ' + element.className + ' ').replace(/\s+/g, ' ').replace(' ' + className + ' ', '');
element.className = name + (state ? ' ' + className : '');
}
}
}
// Set a new source
function newSource(type, init) {
// Bail if new type isn't known, it's the current type, or current type is empty (video is default) and new type is video
if(!(type in types) || (!init && type == currentType) || (!currentType.length && type == types.video)) {
return;
}
// Get plyr instance
var player = document.querySelector('.js-media-player').plyr;
switch(type) {
case types.video:
player.source({
type: 'video',
title: 'View From A Blue Moon',
sources: [{
src: 'https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4',
type: 'video/mp4'
},
{
src: 'https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.webm',
type: 'video/webm'
}],
poster: 'https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg',
tracks: [{
kind: 'captions',
label: 'English',
srclang:'en',
src: 'https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt',
default: true
}]
});
break;
case types.audio:
player.source({
type: 'audio',
title: 'Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;',
sources: [{
src: 'https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3',
type: 'audio/mp3'
},
{
src: 'https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg',
type: 'audio/ogg'
}]
});
break;
case types.youtube:
player.source({
type: 'video',
title: 'View From A Blue Moon',
sources: [{
src: 'bTqVqk7FSmY',
type: 'youtube'
}]
});
break;
case types.vimeo:
player.source({
type: 'video',
title: 'View From A Blue Moon',
sources: [{
src: '143418951',
type: 'vimeo'
}]
});
break;
}
// Set the current type for next time
currentType = type;
// Remove active classes
for (var x = buttons.length - 1; x >= 0; x--) {
toggleClass(buttons[x].parentElement, 'active', false);
}
// Set active on parent
toggleClass(document.querySelector('[data-source="'+ type +'"]').parentElement, 'active', true);
}
})();
// Google analytics
// For demo site (http://[www.]plyr.io) only
if(document.domain.indexOf("plyr.io") > -1) {
if(document.domain.indexOf('plyr.io') > -1) {
(function(i,s,o,g,r,a,m){i.GoogleAnalyticsObject=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,"script","//www.google-analytics.com/analytics.js","ga");
ga("create", "UA-40881672-11", "auto");
ga("send", "pageview");
}
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-40881672-11', 'auto');
ga('send', 'pageview');
}

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

@ -1,802 +0,0 @@
/*!
* Copyright 2011 Twitter, Inc.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// A wrapper for compatibility with Mustache.js, quirks and all
var Hogan = {};
(function (Hogan) {
Hogan.Template = function (codeObj, text, compiler, options) {
codeObj = codeObj || {};
this.r = codeObj.code || this.r;
this.c = compiler;
this.options = options || {};
this.text = text || '';
this.partials = codeObj.partials || {};
this.subs = codeObj.subs || {};
this.buf = '';
}
Hogan.Template.prototype = {
// render: replaced by generated code.
r: function (context, partials, indent) { return ''; },
// variable escaping
v: hoganEscape,
// triple stache
t: coerceToString,
render: function render(context, partials, indent) {
return this.ri([context], partials || {}, indent);
},
// render internal -- a hook for overrides that catches partials too
ri: function (context, partials, indent) {
return this.r(context, partials, indent);
},
// ensurePartial
ep: function(symbol, partials) {
var partial = this.partials[symbol];
// check to see that if we've instantiated this partial before
var template = partials[partial.name];
if (partial.instance && partial.base == template) {
return partial.instance;
}
if (typeof template == 'string') {
if (!this.c) {
throw new Error("No compiler available.");
}
template = this.c.compile(template, this.options);
}
if (!template) {
return null;
}
// We use this to check whether the partials dictionary has changed
this.partials[symbol].base = template;
if (partial.subs) {
// Make sure we consider parent template now
if (!partials.stackText) partials.stackText = {};
for (key in partial.subs) {
if (!partials.stackText[key]) {
partials.stackText[key] = (this.activeSub !== undefined && partials.stackText[this.activeSub]) ? partials.stackText[this.activeSub] : this.text;
}
}
template = createSpecializedPartial(template, partial.subs, partial.partials,
this.stackSubs, this.stackPartials, partials.stackText);
}
this.partials[symbol].instance = template;
return template;
},
// tries to find a partial in the current scope and render it
rp: function(symbol, context, partials, indent) {
var partial = this.ep(symbol, partials);
if (!partial) {
return '';
}
return partial.ri(context, partials, indent);
},
// render a section
rs: function(context, partials, section) {
var tail = context[context.length - 1];
if (!isArray(tail)) {
section(context, partials, this);
return;
}
for (var i = 0; i < tail.length; i++) {
context.push(tail[i]);
section(context, partials, this);
context.pop();
}
},
// maybe start a section
s: function(val, ctx, partials, inverted, start, end, tags) {
var pass;
if (isArray(val) && val.length === 0) {
return false;
}
if (typeof val == 'function') {
val = this.ms(val, ctx, partials, inverted, start, end, tags);
}
pass = !!val;
if (!inverted && pass && ctx) {
ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]);
}
return pass;
},
// find values with dotted names
d: function(key, ctx, partials, returnFound) {
var found,
names = key.split('.'),
val = this.f(names[0], ctx, partials, returnFound),
doModelGet = this.options.modelGet,
cx = null;
if (key === '.' && isArray(ctx[ctx.length - 2])) {
val = ctx[ctx.length - 1];
} else {
for (var i = 1; i < names.length; i++) {
found = findInScope(names[i], val, doModelGet);
if (found !== undefined) {
cx = val;
val = found;
} else {
val = '';
}
}
}
if (returnFound && !val) {
return false;
}
if (!returnFound && typeof val == 'function') {
ctx.push(cx);
val = this.mv(val, ctx, partials);
ctx.pop();
}
return val;
},
// find values with normal names
f: function(key, ctx, partials, returnFound) {
var val = false,
v = null,
found = false,
doModelGet = this.options.modelGet;
for (var i = ctx.length - 1; i >= 0; i--) {
v = ctx[i];
val = findInScope(key, v, doModelGet);
if (val !== undefined) {
found = true;
break;
}
}
if (!found) {
return (returnFound) ? false : "";
}
if (!returnFound && typeof val == 'function') {
val = this.mv(val, ctx, partials);
}
return val;
},
// higher order templates
ls: function(func, cx, partials, text, tags) {
var oldTags = this.options.delimiters;
this.options.delimiters = tags;
this.b(this.ct(coerceToString(func.call(cx, text)), cx, partials));
this.options.delimiters = oldTags;
return false;
},
// compile text
ct: function(text, cx, partials) {
if (this.options.disableLambda) {
throw new Error('Lambda features disabled.');
}
return this.c.compile(text, this.options).render(cx, partials);
},
// template result buffering
b: function(s) { this.buf += s; },
fl: function() { var r = this.buf; this.buf = ''; return r; },
// method replace section
ms: function(func, ctx, partials, inverted, start, end, tags) {
var textSource,
cx = ctx[ctx.length - 1],
result = func.call(cx);
if (typeof result == 'function') {
if (inverted) {
return true;
} else {
textSource = (this.activeSub && this.subsText && this.subsText[this.activeSub]) ? this.subsText[this.activeSub] : this.text;
return this.ls(result, cx, partials, textSource.substring(start, end), tags);
}
}
return result;
},
// method replace variable
mv: function(func, ctx, partials) {
var cx = ctx[ctx.length - 1];
var result = func.call(cx);
if (typeof result == 'function') {
return this.ct(coerceToString(result.call(cx)), cx, partials);
}
return result;
},
sub: function(name, context, partials, indent) {
var f = this.subs[name];
if (f) {
this.activeSub = name;
f(context, partials, this, indent);
this.activeSub = false;
}
}
};
//Find a key in an object
function findInScope(key, scope, doModelGet) {
var val;
if (scope && typeof scope == 'object') {
if (scope[key] !== undefined) {
val = scope[key];
// try lookup with get for backbone or similar model data
} else if (doModelGet && scope.get && typeof scope.get == 'function') {
val = scope.get(key);
}
}
return val;
}
function createSpecializedPartial(instance, subs, partials, stackSubs, stackPartials, stackText) {
function PartialTemplate() {};
PartialTemplate.prototype = instance;
function Substitutions() {};
Substitutions.prototype = instance.subs;
var key;
var partial = new PartialTemplate();
partial.subs = new Substitutions();
partial.subsText = {}; //hehe. substext.
partial.buf = '';
stackSubs = stackSubs || {};
partial.stackSubs = stackSubs;
partial.subsText = stackText;
for (key in subs) {
if (!stackSubs[key]) stackSubs[key] = subs[key];
}
for (key in stackSubs) {
partial.subs[key] = stackSubs[key];
}
stackPartials = stackPartials || {};
partial.stackPartials = stackPartials;
for (key in partials) {
if (!stackPartials[key]) stackPartials[key] = partials[key];
}
for (key in stackPartials) {
partial.partials[key] = stackPartials[key];
}
return partial;
}
var rAmp = /&/g,
rLt = /</g,
rGt = />/g,
rApos = /\'/g,
rQuot = /\"/g,
hChars = /[&<>\"\']/;
function coerceToString(val) {
return String((val === null || val === undefined) ? '' : val);
}
function hoganEscape(str) {
str = coerceToString(str);
return hChars.test(str) ?
str
.replace(rAmp, '&amp;')
.replace(rLt, '&lt;')
.replace(rGt, '&gt;')
.replace(rApos, '&#39;')
.replace(rQuot, '&quot;') :
str;
}
var isArray = Array.isArray || function(a) {
return Object.prototype.toString.call(a) === '[object Array]';
};
})(typeof exports !== 'undefined' ? exports : Hogan);
(function (Hogan) {
// Setup regex assignments
// remove whitespace according to Mustache spec
var rIsWhitespace = /\S/,
rQuot = /\"/g,
rNewline = /\n/g,
rCr = /\r/g,
rSlash = /\\/g,
rLineSep = /\u2028/,
rParagraphSep = /\u2029/;
Hogan.tags = {
'#': 1, '^': 2, '<': 3, '$': 4,
'/': 5, '!': 6, '>': 7, '=': 8, '_v': 9,
'{': 10, '&': 11, '_t': 12
};
Hogan.scan = function scan(text, delimiters) {
var len = text.length,
IN_TEXT = 0,
IN_TAG_TYPE = 1,
IN_TAG = 2,
state = IN_TEXT,
tagType = null,
tag = null,
buf = '',
tokens = [],
seenTag = false,
i = 0,
lineStart = 0,
otag = '{{',
ctag = '}}';
function addBuf() {
if (buf.length > 0) {
tokens.push({tag: '_t', text: new String(buf)});
buf = '';
}
}
function lineIsWhitespace() {
var isAllWhitespace = true;
for (var j = lineStart; j < tokens.length; j++) {
isAllWhitespace =
(Hogan.tags[tokens[j].tag] < Hogan.tags['_v']) ||
(tokens[j].tag == '_t' && tokens[j].text.match(rIsWhitespace) === null);
if (!isAllWhitespace) {
return false;
}
}
return isAllWhitespace;
}
function filterLine(haveSeenTag, noNewLine) {
addBuf();
if (haveSeenTag && lineIsWhitespace()) {
for (var j = lineStart, next; j < tokens.length; j++) {
if (tokens[j].text) {
if ((next = tokens[j+1]) && next.tag == '>') {
// set indent to token value
next.indent = tokens[j].text.toString()
}
tokens.splice(j, 1);
}
}
} else if (!noNewLine) {
tokens.push({tag:'\n'});
}
seenTag = false;
lineStart = tokens.length;
}
function changeDelimiters(text, index) {
var close = '=' + ctag,
closeIndex = text.indexOf(close, index),
delimiters = trim(
text.substring(text.indexOf('=', index) + 1, closeIndex)
).split(' ');
otag = delimiters[0];
ctag = delimiters[delimiters.length - 1];
return closeIndex + close.length - 1;
}
if (delimiters) {
delimiters = delimiters.split(' ');
otag = delimiters[0];
ctag = delimiters[1];
}
for (i = 0; i < len; i++) {
if (state == IN_TEXT) {
if (tagChange(otag, text, i)) {
--i;
addBuf();
state = IN_TAG_TYPE;
} else {
if (text.charAt(i) == '\n') {
filterLine(seenTag);
} else {
buf += text.charAt(i);
}
}
} else if (state == IN_TAG_TYPE) {
i += otag.length - 1;
tag = Hogan.tags[text.charAt(i + 1)];
tagType = tag ? text.charAt(i + 1) : '_v';
if (tagType == '=') {
i = changeDelimiters(text, i);
state = IN_TEXT;
} else {
if (tag) {
i++;
}
state = IN_TAG;
}
seenTag = i;
} else {
if (tagChange(ctag, text, i)) {
tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag,
i: (tagType == '/') ? seenTag - otag.length : i + ctag.length});
buf = '';
i += ctag.length - 1;
state = IN_TEXT;
if (tagType == '{') {
if (ctag == '}}') {
i++;
} else {
cleanTripleStache(tokens[tokens.length - 1]);
}
}
} else {
buf += text.charAt(i);
}
}
}
filterLine(seenTag, true);
return tokens;
}
function cleanTripleStache(token) {
if (token.n.substr(token.n.length - 1) === '}') {
token.n = token.n.substring(0, token.n.length - 1);
}
}
function trim(s) {
if (s.trim) {
return s.trim();
}
return s.replace(/^\s*|\s*$/g, '');
}
function tagChange(tag, text, index) {
if (text.charAt(index) != tag.charAt(0)) {
return false;
}
for (var i = 1, l = tag.length; i < l; i++) {
if (text.charAt(index + i) != tag.charAt(i)) {
return false;
}
}
return true;
}
// the tags allowed inside super templates
var allowedInSuper = {'_t': true, '\n': true, '$': true, '/': true};
function buildTree(tokens, kind, stack, customTags) {
var instructions = [],
opener = null,
tail = null,
token = null;
tail = stack[stack.length - 1];
while (tokens.length > 0) {
token = tokens.shift();
if (tail && tail.tag == '<' && !(token.tag in allowedInSuper)) {
throw new Error('Illegal content in < super tag.');
}
if (Hogan.tags[token.tag] <= Hogan.tags['$'] || isOpener(token, customTags)) {
stack.push(token);
token.nodes = buildTree(tokens, token.tag, stack, customTags);
} else if (token.tag == '/') {
if (stack.length === 0) {
throw new Error('Closing tag without opener: /' + token.n);
}
opener = stack.pop();
if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) {
throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n);
}
opener.end = token.i;
return instructions;
} else if (token.tag == '\n') {
token.last = (tokens.length == 0) || (tokens[0].tag == '\n');
}
instructions.push(token);
}
if (stack.length > 0) {
throw new Error('missing closing tag: ' + stack.pop().n);
}
return instructions;
}
function isOpener(token, tags) {
for (var i = 0, l = tags.length; i < l; i++) {
if (tags[i].o == token.n) {
token.tag = '#';
return true;
}
}
}
function isCloser(close, open, tags) {
for (var i = 0, l = tags.length; i < l; i++) {
if (tags[i].c == close && tags[i].o == open) {
return true;
}
}
}
function stringifySubstitutions(obj) {
var items = [];
for (var key in obj) {
items.push('"' + esc(key) + '": function(c,p,t,i) {' + obj[key] + '}');
}
return "{ " + items.join(",") + " }";
}
function stringifyPartials(codeObj) {
var partials = [];
for (var key in codeObj.partials) {
partials.push('"' + esc(key) + '":{name:"' + esc(codeObj.partials[key].name) + '", ' + stringifyPartials(codeObj.partials[key]) + "}");
}
return "partials: {" + partials.join(",") + "}, subs: " + stringifySubstitutions(codeObj.subs);
}
Hogan.stringify = function(codeObj, text, options) {
return "{code: function (c,p,i) { " + Hogan.wrapMain(codeObj.code) + " }," + stringifyPartials(codeObj) + "}";
}
var serialNo = 0;
Hogan.generate = function(tree, text, options) {
serialNo = 0;
var context = { code: '', subs: {}, partials: {} };
Hogan.walk(tree, context);
if (options.asString) {
return this.stringify(context, text, options);
}
return this.makeTemplate(context, text, options);
}
Hogan.wrapMain = function(code) {
return 'var t=this;t.b(i=i||"");' + code + 'return t.fl();';
}
Hogan.template = Hogan.Template;
Hogan.makeTemplate = function(codeObj, text, options) {
var template = this.makePartials(codeObj);
template.code = new Function('c', 'p', 'i', this.wrapMain(codeObj.code));
return new this.template(template, text, this, options);
}
Hogan.makePartials = function(codeObj) {
var key, template = {subs: {}, partials: codeObj.partials, name: codeObj.name};
for (key in template.partials) {
template.partials[key] = this.makePartials(template.partials[key]);
}
for (key in codeObj.subs) {
template.subs[key] = new Function('c', 'p', 't', 'i', codeObj.subs[key]);
}
return template;
}
function esc(s) {
return s.replace(rSlash, '\\\\')
.replace(rQuot, '\\\"')
.replace(rNewline, '\\n')
.replace(rCr, '\\r')
.replace(rLineSep, '\\u2028')
.replace(rParagraphSep, '\\u2029');
}
function chooseMethod(s) {
return (~s.indexOf('.')) ? 'd' : 'f';
}
function createPartial(node, context) {
var prefix = "<" + (context.prefix || "");
var sym = prefix + node.n + serialNo++;
context.partials[sym] = {name: node.n, partials: {}};
context.code += 't.b(t.rp("' + esc(sym) + '",c,p,"' + (node.indent || '') + '"));';
return sym;
}
Hogan.codegen = {
'#': function(node, context) {
context.code += 'if(t.s(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,1),' +
'c,p,0,' + node.i + ',' + node.end + ',"' + node.otag + " " + node.ctag + '")){' +
't.rs(c,p,' + 'function(c,p,t){';
Hogan.walk(node.nodes, context);
context.code += '});c.pop();}';
},
'^': function(node, context) {
context.code += 'if(!t.s(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,1),c,p,1,0,0,"")){';
Hogan.walk(node.nodes, context);
context.code += '};';
},
'>': createPartial,
'<': function(node, context) {
var ctx = {partials: {}, code: '', subs: {}, inPartial: true};
Hogan.walk(node.nodes, ctx);
var template = context.partials[createPartial(node, context)];
template.subs = ctx.subs;
template.partials = ctx.partials;
},
'$': function(node, context) {
var ctx = {subs: {}, code: '', partials: context.partials, prefix: node.n};
Hogan.walk(node.nodes, ctx);
context.subs[node.n] = ctx.code;
if (!context.inPartial) {
context.code += 't.sub("' + esc(node.n) + '",c,p,i);';
}
},
'\n': function(node, context) {
context.code += write('"\\n"' + (node.last ? '' : ' + i'));
},
'_v': function(node, context) {
context.code += 't.b(t.v(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,0)));';
},
'_t': function(node, context) {
context.code += write('"' + esc(node.text) + '"');
},
'{': tripleStache,
'&': tripleStache
}
function tripleStache(node, context) {
context.code += 't.b(t.t(t.' + chooseMethod(node.n) + '("' + esc(node.n) + '",c,p,0)));';
}
function write(s) {
return 't.b(' + s + ');';
}
Hogan.walk = function(nodelist, context) {
var func;
for (var i = 0, l = nodelist.length; i < l; i++) {
func = Hogan.codegen[nodelist[i].tag];
func && func(nodelist[i], context);
}
return context;
}
Hogan.parse = function(tokens, text, options) {
options = options || {};
return buildTree(tokens, '', [], options.sectionTags || []);
}
Hogan.cache = {};
Hogan.cacheKey = function(text, options) {
return [text, !!options.asString, !!options.disableLambda, options.delimiters, !!options.modelGet].join('||');
}
Hogan.compile = function(text, options) {
options = options || {};
var key = Hogan.cacheKey(text, options);
var template = this.cache[key];
if (template) {
var partials = template.partials;
for (var name in partials) {
delete partials[name].instance;
}
return template;
}
template = this.generate(this.parse(this.scan(text, options.delimiters), text, options), text, options);
return this.cache[key] = template;
}
})(typeof exports !== 'undefined' ? exports : Hogan);
var Mustache = (function (Hogan) {
// Mustache.js has non-spec partial context behavior
function mustachePartial(name, context, partials, indent) {
var partialScope = this.f(name, context, partials, 0);
var cx = context;
if (partialScope) {
cx = cx.concat(partialScope);
}
return Hogan.Template.prototype.rp.call(this, name, cx, partials, indent);
}
var HoganTemplateWrapper = function(renderFunc, text, compiler){
this.rp = mustachePartial;
Hogan.Template.call(this, renderFunc, text, compiler);
};
HoganTemplateWrapper.prototype = Hogan.Template.prototype;
// Add a wrapper for Hogan's generate method. Mustache and Hogan keep
// separate caches, and Mustache returns wrapped templates.
var wrapper;
var HoganWrapper = function(){
this.cache = {};
this.generate = function(code, text, options) {
return new HoganTemplateWrapper(new Function('c', 'p', 'i', code), text, wrapper);
}
};
HoganWrapper.prototype = Hogan;
wrapper = new HoganWrapper();
return {
to_html: function(text, data, partials, sendFun) {
var template = wrapper.compile(text);
var result = template.render(data, partials);
if (!sendFun) {
return result;
}
sendFun(result);
}
}
})(Hogan);

View File

@ -0,0 +1,47 @@
// ==========================================================================
// 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%;
background: @body-background fixed;
}
body {
margin: 0;
padding: (@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,172 @@
// ==========================================================================
// 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;
}
&.active .btn {
&:extend(.btn--primary);
box-shadow: inset 0 1px 1px rgba(0,0,0, .2);
position: relative;
z-index: 1;
.icon {
color: inherit;
}
}
&.active + li .btn:hover {
z-index: 0;
}
}
.btn {
position: relative;
display: block;
border-radius: 0;
&:hover,
&:focus {
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;
user-select: none;
font-weight: @font-weight-bold;
}
// Buttons
.btn {
padding: (@padding-base / 2) ((@padding-base / 2) + 2);
background: linear-gradient(lighten(@off-white, 2%), darken(@off-white, 3%));
border: 1px solid @gray-light;
box-shadow: 0 1px 1px rgba(0,0,0, .05);
text-shadow: 0 1px 1px #fff;
color: @gray;
transition: background .1s ease, color .1s ease;
.font-size(@font-size-small);
&:hover,
&:focus {
border-color: darken(@gray-light, 8%);
color: @gray;
outline: 0;
}
}
// Sizes
.btn--large {
padding: (@padding-base / 2) @padding-base;
.font-size();
}
// Styles
.btn--primary {
background-image: linear-gradient(@link-color, darken(@link-color, 5%));
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--youtube .icon {
color: @color-youtube;
}
.btn--vimeo .icon {
color: @color-vimeo;
}
.btn--twitter .icon {
color: @color-twitter;
}
// Count bubble
.btn__count {
position: relative;
margin-left: (@padding-base / 2);
padding: (@padding-base / 2) (@padding-base * .75);
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,51 @@
// ==========================================================================
// Examples
// ==========================================================================
section {
margin: 0 auto @padding-base;
max-width: @example-width-video;
}
// For non supported browsers
video {
max-width: 100%;
vertical-align: middle;
}
// Example players
.plyr {
margin: 0 auto;
border-radius: @border-radius-large;
}
.plyr--audio {
max-width: @example-width-audio;
}
.plyr--video::after {
content: "";
pointer-events: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
border: 1px solid fade(#000, 15%);
border-radius: inherit;
}
// Style full supported player
.plyr__cite {
display: none;
margin-top: @padding-base;
.icon {
margin-right: (@padding-base / 4);
}
}
.plyr--video:not(.plyr--youtube):not(.plyr--vimeo) ~ ul .plyr__cite--video,
.plyr--audio ~ ul .plyr__cite--audio,
.plyr--youtube ~ ul .plyr__cite--youtube,
.plyr--vimeo ~ ul .plyr__cite--vimeo {
display: block;
}

View File

@ -0,0 +1,26 @@
// ==========================================================================
// Icons
// ==========================================================================
// Base size icon styles
.icon {
fill: currentColor;
width: @icon-size;
height: @icon-size;
vertical-align: -3px;
}
// Within elements
a svg,
button svg,
label svg {
pointer-events: none;
}
a .icon,
.btn .icon {
margin-right: (@padding-base / 2);
}
.btn:not(.btn-large) .icon {
width: (@icon-size - 2);
height: (@icon-size - 2);
}

View File

@ -0,0 +1,75 @@
// ==========================================================================
// Typography
// ==========================================================================
// Base
html {
font-size: 100%;
}
body {
font-family: "Avenir", "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.5;
text-align: center;
color: @gray;
font-weight: @font-weight-base;
.font-smoothing();
}
// Headings
h1,
h2 {
letter-spacing: -.025em;
color: @brand-primary;
margin: 0 0 (@padding-base / 2);
line-height: 1.2;
font-weight: @font-weight-bold;
}
h1 {
.font-size(@font-size-h1);
}
// Paragraph and small
p,
small {
margin: 0 0 @padding-base;
}
small {
display: block;
padding: 0 (@padding-base / 2);
.font-size(@font-size-small);
}
// Lists
ul,
li {
list-style: none;
margin: 0;
padding: 0;
}
// Links
a {
text-decoration: none;
color: @link-color;
border-bottom: 1px dotted currentColor;
transition: background .3s ease, color .3s ease, border .3s ease;
&:hover,
&:focus {
color: @gray-dark;
border-bottom-color: rgba(0,0,0,0);
}
&:focus {
.tab-focus();
}
&.logo {
border: 0;
}
}
.color--vimeo {
color: @color-vimeo;
}
.color--youtube {
color: @color-youtube;
}

View File

@ -2,163 +2,25 @@
// 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;
// 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;
}
// Animation
@import "lib/animation.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;
p {
.font-size(18);
}
@media (min-width: 560px) {
padding-top: (@padding-base * 3);
padding-bottom: (@padding-base * 3);
}
}
// Sections
section {
padding-bottom: @padding-base;
@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);
}
}
// Components
@import "components/base.less";
@import "components/icons.less";
@import "components/buttons.less";
@import "components/error.less";
@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");
font-style: normal;
font-weight: 400;
font-family: "Avenir";
src: url("//cdn.plyr.io/fonts/avenir-medium.woff2") format("woff2"),
url("//cdn.plyr.io/fonts/avenir-medium.woff") format("woff");
font-style: normal;
font-weight: @font-weight-base;
}
@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");
font-style: normal;
font-weight: 600;
font-family: "Avenir";
src: url("//cdn.plyr.io/fonts/avenir-bold.woff2") format("woff2"),
url("//cdn.plyr.io/fonts/avenir-bold.woff") format("woff");
font-style: normal;
font-weight: @font-weight-bold;
}

View File

@ -5,38 +5,37 @@
// Contain floats: nicolasgallagher.com/micro-clearfix-hack/
// ---------------------------------------
.clearfix() {
zoom: 1;
&:before,
&:after { content: ""; display: table; }
&:after { clear: both; }
zoom: 1;
&:before,
&:after { content: ""; display: table; }
&:after { clear: both; }
}
// Webkit-style focus
// ---------------------------------------
.tab-focus() {
// Default
outline: thin dotted @gray-dark;
// Webkit
//outline: 5px auto -webkit-focus-ring-color;
outline-offset: 1px;
// Default
outline: thin dotted @gray-dark;
// Webkit
outline-offset: 1px;
}
// Use rems for font sizing
// Leave <body> at 100%/16px
// ---------------------------------------
.font-size(@font-size: 16){
@rem: round((@font-size / 16), 1);
font-size: (@font-size * 1px);
font-size: ~"@{rem}rem";
@rem: round((@font-size / 16), 3);
font-size: (@font-size * 1px);
font-size: ~"@{rem}rem";
}
// Font smoothing
// ---------------------------------------
.font-smoothing(@mode: on) when (@mode = on) {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
-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;
-moz-osx-font-smoothing: auto;
-webkit-font-smoothing: subpixel-antialiased;
}

View File

@ -0,0 +1,48 @@
// ==========================================================================
// Variables
// ==========================================================================
// Colors
@gray-dark: #343f4a;
@gray: #55646b;
@gray-light: #cbd0d3;
@gray-lighter: #dbe3e8;
@off-white: #f2f5f7;
@brand-primary: #3498db;
@brand-secondary: #02BD9B;
// Brands
@color-twitter: #4BAAF4;
@color-youtube: #cc181e;
@color-vimeo: #19b7ed;
// Base
@body-background: @off-white; //linear-gradient(to left top, @brand-secondary, @brand-primary);
// Type
@font-size-base: 16;
@font-size-small: 14;
@font-size-h1: 64;
@font-weight-base: 500;
@font-weight-bold: 700;
// Elements
@link-color: @brand-primary;
@padding-base: 20px;
@arrow-size: 8px;
// Icons
@icon-size: 18px;
// Breakpoints
@screen-sm: 480px;
@screen-md: 768px;
// Radii
@border-radius-base: 4px;
@border-radius-large: 6px;
// Examples
@example-width-audio: 520px;
@example-width-video: 1200px;

12
docs/src/sprite/icon-github.svg Executable file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8,0.2c-4.4,0-8,3.6-8,8c0,3.5,2.3,6.5,5.5,7.6
C5.9,15.9,6,15.6,6,15.4c0-0.2,0-0.7,0-1.4C3.8,14.5,3.3,13,3.3,13c-0.4-0.9-0.9-1.2-0.9-1.2c-0.7-0.5,0.1-0.5,0.1-0.5
c0.8,0.1,1.2,0.8,1.2,0.8C4.4,13.4,5.6,13,6,12.8c0.1-0.5,0.3-0.9,0.5-1.1c-1.8-0.2-3.6-0.9-3.6-4c0-0.9,0.3-1.6,0.8-2.1
c-0.1-0.2-0.4-1,0.1-2.1c0,0,0.7-0.2,2.2,0.8c0.6-0.2,1.3-0.3,2-0.3c0.7,0,1.4,0.1,2,0.3c1.5-1,2.2-0.8,2.2-0.8
c0.4,1.1,0.2,1.9,0.1,2.1c0.5,0.6,0.8,1.3,0.8,2.1c0,3.1-1.9,3.7-3.7,3.9C9.7,12,10,12.5,10,13.2c0,1.1,0,1.9,0,2.2
c0,0.2,0.1,0.5,0.6,0.4c3.2-1.1,5.5-4.1,5.5-7.6C16,3.8,12.4,0.2,8,0.2z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<title>Twitter</title>
<path d="M16,3c-0.6,0.3-1.2,0.4-1.9,0.5c0.7-0.4,1.2-1,1.4-1.8c-0.6,0.4-1.3,0.6-2.1,0.8c-0.6-0.6-1.5-1-2.4-1
C9.3,1.5,7.8,3,7.8,4.8c0,0.3,0,0.5,0.1,0.7C5.2,5.4,2.7,4.1,1.1,2.1c-0.3,0.5-0.4,1-0.4,1.7c0,1.1,0.6,2.1,1.5,2.7
c-0.5,0-1-0.2-1.5-0.4c0,0,0,0,0,0c0,1.6,1.1,2.9,2.6,3.2C3,9.4,2.7,9.4,2.4,9.4c-0.2,0-0.4,0-0.6-0.1c0.4,1.3,1.6,2.3,3.1,2.3
c-1.1,0.9-2.5,1.4-4.1,1.4c-0.3,0-0.5,0-0.8,0c1.5,0.9,3.2,1.5,5,1.5c6,0,9.3-5,9.3-9.3c0-0.1,0-0.3,0-0.4C15,4.3,15.6,3.7,16,3z"/>
</svg>

After

Width:  |  Height:  |  Size: 981 B

9
docs/src/sprite/icon-vimeo.svg Executable file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<path d="M16,4.3c-0.1,1.6-1.2,3.7-3.3,6.4c-2.2,2.8-4,4.2-5.5,4.2c-0.9,0-1.7-0.9-2.4-2.6C4,9.9,3.4,5,2,5
C1.9,5,1.5,5.3,0.8,5.8L0,4.8c0.8-0.7,3.5-3.4,4.7-3.5C5.9,1.2,6.7,2,7,3.8c0.3,2,0.8,6.1,1.8,6.1c0.9,0,2.5-3.4,2.6-4
c0.1-0.9-0.3-1.9-2.3-1.1c0.8-2.6,2.3-3.8,4.5-3.8C15.3,1.1,16.1,2.2,16,4.3z"/>
</svg>

After

Width:  |  Height:  |  Size: 779 B

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<path d="M15.8,4.8c-0.2-1.3-0.8-2.2-2.2-2.4C11.4,2,8,2,8,2S4.6,2,2.4,2.4C1,2.6,0.3,3.5,0.2,4.8C0,6.1,0,8,0,8
s0,1.9,0.2,3.2c0.2,1.3,0.8,2.2,2.2,2.4C4.6,14,8,14,8,14s3.4,0,5.6-0.4c1.4-0.3,2-1.1,2.2-2.4C16,9.9,16,8,16,8S16,6.1,15.8,4.8z
M6,11V5l5,3L6,11z"/>
</svg>

After

Width:  |  Height:  |  Size: 739 B

View File

@ -1,62 +0,0 @@
<div class="player-controls">
<div class="player-progress">
<label for="seek{id}" class="sr-only">Seek</label>
<input id="seek{id}" class="player-progress-seek" type="range" min="0" max="100" step="0.5" value="0" data-player="seek">
<progress class="player-progress-played" max="100" value="0">
<span>0</span>% played
</progress>
<progress class="player-progress-buffer" max="100" value="0">
<span>0</span>% buffered
</progress>
</div>
<span class="player-controls-playback">
<button type="button" data-player="restart">
<svg><use xlink:href="#icon-restart"></use></svg>
<span class="sr-only">Restart</span>
</button>
<button type="button" data-player="rewind">
<svg><use xlink:href="#icon-rewind"></use></svg>
<span class="sr-only">Rewind {seektime} seconds</span>
</button>
<button type="button" data-player="play">
<svg><use xlink:href="#icon-play"></use></svg>
<span class="sr-only">Play</span>
</button>
<button type="button" data-player="pause">
<svg><use xlink:href="#icon-pause"></use></svg>
<span class="sr-only">Pause</span>
</button>
<button type="button" data-player="fast-forward">
<svg><use xlink:href="#icon-fast-forward"></use></svg>
<span class="sr-only">Fast forward {seektime} seconds</span>
</button>
<span class="player-time">
<span class="sr-only">Time</span>
<span class="player-duration">00:00</span>
</span>
</span>
<span class="player-controls-sound">
<input class="inverted sr-only" id="mute{id}" type="checkbox" data-player="mute">
<label id="mute{id}" for="mute{id}">
<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>
<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}">
<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 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>
<span class="sr-only">Toggle fullscreen</span>
</button>
</span>
</div>

View File

@ -4,59 +4,60 @@
/*global require, __dirname*/
/*jshint -W079 */
var fs = require("fs"),
path = require("path"),
gulp = require("gulp"),
gutil = require("gulp-util"),
concat = require("gulp-concat"),
uglify = require("gulp-uglify"),
less = require("gulp-less"),
sass = require("gulp-sass"),
minify = require("gulp-minify-css"),
run = require("run-sequence"),
prefix = require("gulp-autoprefixer"),
svgstore = require("gulp-svgstore"),
svgmin = require("gulp-svgmin"),
hogan = require("gulp-hogan-compile"),
rename = require("gulp-rename"),
s3 = require("gulp-s3"),
gzip = require("gulp-gzip"),
replace = require("gulp-replace"),
open = require("gulp-open");
var fs = require("fs"),
path = require("path"),
gulp = require("gulp"),
gutil = require("gulp-util"),
concat = require("gulp-concat"),
uglify = require("gulp-uglify"),
less = require("gulp-less"),
sass = require("gulp-sass"),
cleanCSS = require("gulp-clean-css"),
run = require("run-sequence"),
prefix = require("gulp-autoprefixer"),
svgstore = require("gulp-svgstore"),
svgmin = require("gulp-svgmin"),
rename = require("gulp-rename"),
s3 = require("gulp-s3"),
gzip = require("gulp-gzip"),
replace = require("gulp-replace"),
open = require("gulp-open"),
size = require("gulp-size");
var root = __dirname,
paths = {
plyr: {
// Source paths
src: {
less: path.join(root, "src/less/**/*"),
sass: path.join(root, "src/sass/**/*"),
js: path.join(root, "src/js/**/*"),
sprite: path.join(root, "src/sprite/*.svg")
},
// Output paths
output: path.join(root, "dist/")
},
docs: {
// Source paths
src: {
less: path.join(root, "docs/src/less/**/*"),
js: path.join(root, "docs/src/js/**/*"),
templates: path.join(root, "docs/src/templates/*.html")
},
// Output paths
output: path.join(root, "docs/dist/"),
// Docs
root: path.join(root, "docs/")
},
upload: [path.join(root, "dist/**"), path.join(root, "docs/dist/**")]
plyr: {
// Source paths
src: {
less: path.join(root, "src/less/**/*"),
scss: path.join(root, "src/scss/**/*"),
js: path.join(root, "src/js/**/*"),
sprite: path.join(root, "src/sprite/*.svg")
},
// Output paths
output: path.join(root, "dist/")
},
docs: {
// Source paths
src: {
less: path.join(root, "docs/src/less/**/*"),
js: path.join(root, "docs/src/js/**/*"),
sprite: path.join(root, "docs/src/sprite/**/*")
},
// Output paths
output: path.join(root, "docs/dist/"),
// Docs
root: path.join(root, "docs/")
},
upload: [path.join(root, "dist/**"), path.join(root, "docs/dist/**")]
},
// Task arrays
tasks = {
less: [],
sass: [],
js: []
tasks = {
less: [],
scss: [],
js: [],
sprite: []
},
// Fetch bundles from JSON
@ -65,131 +66,126 @@ package = loadJSON(path.join(root, "package.json"));
// Load json
function loadJSON(path) {
return JSON.parse(fs.readFileSync(path));
try {
return JSON.parse(fs.readFileSync(path));
}
catch(err) {
return {};
}
}
var build = {
js: function (files, bundle) {
for (var key in files) {
(function(key) {
var name = "js-" + key;
tasks.js.push(name);
js: function (files, bundle) {
for (var key in files) {
(function(key) {
var name = "js-" + key;
tasks.js.push(name);
gulp.task(name, function () {
return gulp
.src(bundles[bundle].js[key])
.pipe(concat(key))
.pipe(uglify())
.pipe(gulp.dest(paths[bundle].output));
});
})(key);
}
},
less: function(files, bundle) {
for (var key in files) {
(function (key) {
var name = "less-" + key;
tasks.less.push(name);
gulp.task(name, function () {
return gulp
.src(bundles[bundle].js[key])
.pipe(concat(key))
.pipe(uglify())
.pipe(gulp.dest(paths[bundle].output));
});
})(key);
}
},
less: function(files, bundle) {
for (var key in files) {
(function (key) {
var name = "less-" + key;
tasks.less.push(name);
gulp.task(name, function () {
return gulp
.src(bundles[bundle].less[key])
.pipe(less())
.on("error", gutil.log)
.pipe(concat(key))
.pipe(prefix(["last 2 versions"], { cascade: true }))
.pipe(minify())
.pipe(gulp.dest(paths[bundle].output));
});
})(key);
}
},
sass: function(files, bundle) {
for (var key in files) {
(function (key) {
var name = "sass-" + key;
tasks.sass.push(name);
gulp.task(name, function () {
return gulp
.src(bundles[bundle].less[key])
.pipe(less())
.on("error", gutil.log)
.pipe(concat(key))
.pipe(prefix(["last 2 versions"], { cascade: true }))
.pipe(cleanCSS())
.pipe(gulp.dest(paths[bundle].output));
});
})(key);
}
},
scss: function(files, bundle) {
for (var key in files) {
(function (key) {
var name = "scss-" + key;
tasks.scss.push(name);
gulp.task(name, function () {
return gulp
.src(bundles[bundle].sass[key])
.pipe(sass())
.on("error", gutil.log)
.pipe(concat(key))
.pipe(prefix(["last 2 versions"], { cascade: true }))
.pipe(minify())
.pipe(gulp.dest(paths[bundle].output));
});
})(key);
}
},
sprite: function() {
// Process Icons
gulp.task("sprite", function () {
return gulp
.src(paths.plyr.src.sprite)
.pipe(svgmin({
plugins: [{
removeDesc: true
}]
}))
.pipe(svgstore())
.pipe(gulp.dest(paths.plyr.output));
});
},
templates: function() {
// Build templates
gulp.task("templates", function () {
return gulp
.src(paths.docs.src.templates)
.pipe(hogan("templates.js", {
wrapper: false,
templateName: function (file) {
return path.basename(file.relative.replace(/\\/g, "-"), path.extname(file.relative));
}
}))
.pipe(gulp.dest(paths.docs.output));
});
}
gulp.task(name, function () {
return gulp
.src(bundles[bundle].scss[key])
.pipe(sass())
.on("error", gutil.log)
.pipe(concat(key))
.pipe(prefix(["last 2 versions"], { cascade: true }))
.pipe(cleanCSS())
.pipe(gulp.dest(paths[bundle].output));
});
})(key);
}
},
sprite: function(bundle) {
var name = "sprite-" + bundle;
tasks.sprite.push(name);
// Process Icons
gulp.task(name, function () {
return gulp
.src(paths[bundle].src.sprite)
.pipe(svgmin({
plugins: [{
removeDesc: true
}]
}))
.pipe(svgstore())
.pipe(rename({ basename: (bundle == "plyr" ? "sprite" : bundle) }))
.pipe(gulp.dest(paths[bundle].output));
});
}
};
// Plyr core files
build.js(bundles.plyr.js, "plyr");
build.less(bundles.plyr.less, "plyr");
build.sass(bundles.plyr.sass, "plyr");
build.sprite();
build.scss(bundles.plyr.scss, "plyr");
build.sprite("plyr");
// Docs files
build.templates();
build.less(bundles.docs.less, "docs");
build.js(bundles.docs.js, "docs");
build.sprite("docs");
// Default gulp task
gulp.task("default", function(){
run("templates", tasks.js, tasks.less, "sprite");
});
// Build all JS (inc. templates)
// Build all JS
gulp.task("js", function(){
run("templates", tasks.js);
run(tasks.js);
});
// Build SASS (for testing, default is LESS)
gulp.task("sass", function(){
run(tasks.sass);
// Build SCSS (for testing, default is LESS)
gulp.task("scss", function(){
run(tasks.scss);
});
// Watch for file changes
gulp.task("watch", function () {
// Plyr core
// 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, tasks.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.sprite, tasks.sprite);
});
// Default gulp task
gulp.task("default", function(){
run(tasks.js, tasks.less, tasks.sprite, "watch");
});
// Publish a version to CDN and docs
@ -198,69 +194,91 @@ gulp.task("watch", function () {
// Some options
var aws = loadJSON(path.join(root, "aws.json")),
version = package.version,
maxAge = 31536000, // seconds 1 year
maxAge = 31536000, // seconds 1 year
options = {
cdn: {
headers: {
"Cache-Control": "max-age=" + maxAge + ", no-transform, public",
"Vary": "Accept-Encoding"
},
gzippedOnly: true
},
docs: {
headers: {
"Cache-Control": "public, must-revalidate, proxy-revalidate, max-age=0",
"Vary": "Accept-Encoding"
},
gzippedOnly: true
}
},
cdnpath = new RegExp(aws.cdn.bucket + "\/(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)","gi");
cdn: {
headers: {
"Cache-Control": "max-age=" + maxAge,
"Vary": "Accept-Encoding"
},
gzippedOnly: true
},
docs: {
headers: {
"Cache-Control": "public, must-revalidate, proxy-revalidate, max-age=0",
"Vary": "Accept-Encoding"
},
gzippedOnly: true
}
};
// If aws is setup
if("cdn" in aws) {
var regex = "(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:-[\\da-z\\-]+(?:\.[\\da-z\\-]+)*)?(?:\\+[\\da-z\\-]+(?:\.[\\da-z\\-]+)*)?",
cdnpath = new RegExp(aws.cdn.bucket + "\/" + regex, "gi"),
semver = new RegExp("v" + regex, "gi"),
localpath = new RegExp("(\.\.\/)?dist", "gi");
}
// Publish version to CDN bucket
gulp.task("cdn", function () {
console.log("Uploading " + version + " to " + aws.cdn.bucket);
console.log("Uploading " + version + " to " + aws.cdn.bucket);
// Upload to CDN
gulp.src(paths.upload)
.pipe(rename(function (path) {
path.dirname = path.dirname.replace(".", version);
}))
.pipe(gzip())
.pipe(s3(aws.cdn, options.cdn));
// Upload to CDN
gulp.src(paths.upload)
.pipe(size({
showFiles: true,
gzip: true
}))
.pipe(rename(function (path) {
path.dirname = path.dirname.replace(".", version);
}))
.pipe(gzip())
.pipe(s3(aws.cdn, options.cdn));
});
// Publish to Docs bucket
gulp.task("docs", function () {
console.log("Uploading " + version + " docs to " + aws.docs.bucket);
console.log("Uploading " + version + " docs to " + aws.docs.bucket);
// Replace versioned files in *.html
gulp.src([paths.docs.root + "*.html"])
.pipe(replace(cdnpath, aws.cdn.bucket + "/" + version))
.pipe(gulp.dest(paths.docs.root))
.pipe(gzip())
.pipe(s3(aws.docs, options.docs));
// Replace versioned files in readme.md
gulp.src([root + "/readme.md"])
.pipe(replace(cdnpath, aws.cdn.bucket + "/" + version))
.pipe(gulp.dest(root));
// Upload error.html to cdn using docs options
gulp.src([paths.docs.root + "error.html"])
.pipe(gzip())
.pipe(s3(aws.cdn, options.docs));
// Replace versioned files in plyr.js
gulp.src(path.join(root, "src/js/plyr.js"))
.pipe(replace(semver, "v" + version))
.pipe(gulp.dest(path.join(root, "src/js/")));
// Replace local file paths with remote paths in docs
// e.g. "../dist/plyr.js" to "https://cdn.plyr.io/x.x.x/plyr.js"
gulp.src([paths.docs.root + "*.html"])
.pipe(replace(localpath, "https://" + aws.cdn.bucket + "/" + version))
.pipe(gzip())
.pipe(s3(aws.docs, options.docs));
// Upload error.html to cdn (as well as docs site)
gulp.src([paths.docs.root + "error.html"])
.pipe(replace(localpath, "https://" + aws.cdn.bucket + "/" + version))
.pipe(gzip())
.pipe(s3(aws.cdn, options.docs));
});
// Open the docs site to check it's sweet
gulp.task("open", function () {
console.log("Opening " + aws.docs.bucket + "...");
console.log("Opening " + aws.docs.bucket + "...");
// A file must be specified or gulp will skip the task
// Doesn't matter which file since we set the URL above
// Weird, I know...
gulp.src([paths.docs.root + "index.html"])
.pipe(open("", {
url: "http://" + aws.docs.bucket
}));
// A file must be specified or gulp will skip the task
// Doesn't matter which file since we set the URL above
// Weird, I know...
gulp.src([paths.docs.root + "index.html"])
.pipe(open("", {
url: "http://" + aws.docs.bucket
}));
});
// Do everything
// Do everything
gulp.task("publish", function () {
run("templates", tasks.js, tasks.less, "sprite", "cdn", "docs", "open");
});
run(tasks.js, tasks.less, tasks.sprite, "cdn", "docs");
});

View File

@ -1,31 +1,28 @@
{
"name": "plyr",
"version": "1.0.23",
"description": "A simple HTML5 media player using custom controls",
"version": "1.6.4",
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
"homepage": "http://plyr.io",
"main": "gulpfile.js",
"main": "src/js/plyr.js",
"dependencies": {},
"devDependencies": {
"gulp": "~3.8.6",
"gulp-autoprefixer": "^0.0.8",
"gulp-concat": "~2.3.3",
"gulp": "^3.9.1",
"gulp-autoprefixer": "^3.1.0",
"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-open": "^0.3.2",
"gulp-less": "^3.0.5",
"gulp-clean-css": "^2.0.6",
"gulp-open": "^2.0.0",
"gulp-rename": "^1.2.0",
"gulp-replace": "^0.5.3",
"gulp-s3": "^0.3.0",
"gulp-sass": "^1.3.3",
"gulp-svgmin": "^1.0.0",
"gulp-svgstore": "^5.0.0",
"gulp-uglify": "~0.3.1",
"gulp-util": "~2.2.20",
"run-sequence": "^0.3.6"
},
"scripts": {
"preinstall": "npm install -g gulp"
"gulp-sass": "^2.3.1",
"gulp-size": "^2.1.0",
"gulp-svgmin": "^1.2.2",
"gulp-svgstore": "^5.0.5",
"gulp-uglify": "^1.5.3",
"gulp-util": "^3.0.7",
"run-sequence": "^1.1.5"
},
"keywords": [
"HTML5 Video",
@ -36,8 +33,15 @@
"type": "git",
"url": "git://github.com/selz/plyr.git"
},
"authors": [
"Sam Potts <me@sampotts.me>"
],
"license": "MIT"
"license": "MIT",
"bugs": {
"url": "https://github.com/selz/plyr/issues"
},
"directories": {
"doc": "docs"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Sam Potts <sam@selz.com>"
}

719
readme.md
View File

@ -1,150 +1,227 @@
# Plyr
A simple, accessible HTML5 media player.
A simple, accessible and customizable HTML5, YouTube and Vimeo media player.
[Checkout the demo](http://plyr.io)
[Checkout the demo](https://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_v1.6.0.png)](https://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 customizable media player that supports [*modern*](#browser-support) browsers. Sure, there are many other players out there but we wanted to keep things simple, using the right elements for the job.
## Features
- **Accessible** - full support for captions and screen readers.
- **Lightweight** - just 5.7KB minified and gzipped.
- **Customisable** - 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.
- **No dependencies** - written in vanilla JavaScript, no jQuery required.
- **Accessible** - full support for VTT captions and screen readers
- **Lightweight** - under 10KB minified and gzipped
- **[Customisable](#html)** - make the player look how you want with the markup you want
- **Semantic** - uses the *right* elements. `<input type="range">` for volume and `<progress>` for progress and well, `<button>`s for buttons. There's no `<span>` or `<a href="#">` button hacks
- **Responsive** - as you'd expect these days
- **HTML Video & Audio** - support for both formats
- **[Embedded Video](#embeds)** - support for YouTube and Vimeo video playback
- **[API](#api)** - toggle playback, volume, seeking, and more
- **[Universal events](#events)** - no messing around with Vimeo and YouTube APIs, all events are universal across formats
- **[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.
Oh and yes, it works with Bootstrap.
## Changelog
Check out [the changelog](changelog.md)
Check out the [changelog](changelog.md) to see what's new with Plyr.
## Planned development
- Accept a string selector, a node, or a nodelist for the `container` property of `selectors`.
## Planned Development
- Streaming
- Playback speed
- Playlists
- 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.
If you have any cool ideas or features, please let me know by [creating an issue](https://github.com/Selz/plyr/issues/new) or, of course, forking and sending a pull request.
## Implementation
Check `docs/index.html` and `docs/dist/docs.js` for an example setup.
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.6.4/plyr.js` to `https://cdn.plyr.io/1.6.4/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.0.23/plyr.js` to `https://cdn.plyr.io/1.0.23/plyr.js`
### Node Package Manager (NPM)
Using NPM, you can grab Plyr:
```
npm install plyr
```
[https://www.npmjs.com/package/plyr](https://www.npmjs.com/package/plyr)
### Bower
If bower is your thang, you can grab Plyr using:
```
bower install plyr
```
[http://bower.io/search/?q=plyr](http://bower.io/search/?q=plyr)
More info on setting up dependencies can be found in the [Bower Docs](http://bower.io/docs/creating-packages/#maintaining-dependencies)
### CDN
If you want to use our CDN, you can use the following. HTTPS (SSL) is supported.
### 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:
```html
<link rel="stylesheet" href="//cdn.plyr.io/1.0.23/plyr.css">
<script src="//cdn.plyr.io/1.0.23/plyr.js"></script>
<link rel="stylesheet" href="https://cdn.plyr.io/1.6.4/plyr.css">
<script src="https://cdn.plyr.io/1.6.4/plyr.js"></script>
```
You can also access the `sprite.svg` file at `//cdn.plyr.io/1.0.23/sprite.svg`.
You can also access the `sprite.svg` file at `https://cdn.plyr.io/1.6.4/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.
### CSS & Styling
If you want to use the default css, add the `plyr.css` file from `/dist` into your head, or even better use `plyr.less` or `plyr.scss` file included in `/src` in your build to save a request.
```html
<link rel="stylesheet" href="dist/plyr.css">
```
The default setup uses the BEM methodology with `plyr` as the block, e.g. `.plyr__controls`. You can change the class hooks in the options. Check out the source for more on this.
### SVG
The SVG sprite for the controls icons is loaded in by AJAX to help with performance. This is best added before the closing `</body>`, before any other scripts.
The SVG sprite for the controls icons can be loaded two ways:
- By passing the *relative* path to the sprite as the `iconUrl` option; or
- Using AJAX, injecting the sprite into a hidden div.
#### Using the `iconUrl` option
This method requires the SVG sprite to be hosted on the *same domain* as your page hosting the player. Currently no browser supports cross origin SVG sprites due to XSS issues. Fingers crossed this will come soon though. An example value for this option would be:
```
/path/to/sprite.svg
```
#### Using AJAX
Using AJAX means you can load the sprite from a different origin. Avoiding the issues above. This is an example script to load an SVG sprite best added before the closing `</body>`, before any other scripts.
```html
<script>
(function(d,p){
var a=new XMLHttpRequest(),
b=d.body;
a.open("GET",p,!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])
}
})(document,"dist/sprite.svg");
a.onload = function() {
var c = d.createElement('div');
c.setAttribute('hidden', '');
c.innerHTML = a.responseText;
b.insertBefore(c, b.childNodes[0]);
};
})(document, 'https://cdn.plyr.io/1.6.4/sprite.svg');
</script>
```
If you're using the `<base>` tag on your site, you may need to use something like this:
[svgfixer.js](https://gist.github.com/leonderijke/c5cf7c5b2e424c0061d2)
More info on SVG sprites here:
[http://css-tricks.com/svg-sprites-use-better-icon-fonts/](http://css-tricks.com/svg-sprites-use-better-icon-fonts/)
and the AJAX technique here:
[http://css-tricks.com/svg-sprites-use-better-icon-fonts/](http://css-tricks.com/svg-sprites-use-better-icon-fonts/)
and the AJAX technique here:
[http://css-tricks.com/ajaxing-svg-sprite/](http://css-tricks.com/ajaxing-svg-sprite/)
### HTML
The only extra markup that's needed to use plyr is a `<div>` wrapper. Replace the source, poster and captions with urls for your media.
```html
<div class="player">
<video poster="//cdn.selz.com/plyr/1.0/poster.jpg" controls crossorigin>
<div class="plyr">
<video poster="/path/to/poster.jpg" controls>
<!-- 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="/path/to/video.mp4" type="video/mp4">
<source src="/path/to/video.webm" type="video/webm">
<!-- Text track file -->
<track kind="captions" label="English captions" src="//cdn.selz.com/plyr/1.0/movie_captions_en.vtt" srclang="en" default>
<track kind="captions" label="English captions" src="/path/to/captions.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="/path/to/movie.mp4">Download</a>
</video>
</div>
```
And the same for `<audio>`
```html
<div class="player">
<div class="plyr">
<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="/path/to/audio.mp3" type="audio/mp3">
<source src="/path/to/audio.ogg" type="audio/ogg">
<!-- Fallback for browsers that don't support the <audio> element -->
<div>
<a href="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3">Download</a>
</div>
<a href="/path/to/audio.mp3">Download</a>
</audio>
</div>
```
```
For YouTube and Vimeo, Plyr uses the standard YouTube API markup (an empty `<div>`):
```html
<div class="plyr">
<div data-video-id="bTqVqk7FSmY" data-type="youtube"></div>
</div>
```
```html
<div class="plyr">
<div data-video-id="143418951" data-type="vimeo"></div>
</div>
```
#### Cross Origin (CORS)
You'll notice the `crossorigin` attribute on the example `<video>` and `<audio>` elements. This is because the media is loaded from another domain. If your media is hosted on another domain, you may need to add this attribute.
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.
### Captions
WebVTT captions are supported. To add a caption track, check the HTML example above and look for the `<track>` element.
Be sure to [validate your caption files](https://quuz.org/webvtt/)
### JavaScript
#### Quick setup
Here's an example of a default setup:
```html
<script src="dist/plyr.js"></script>
<script>
plyr.setup({
*options*
});
</script>
<script src="https://cdn.plyr.io/1.6.4/plyr.js"></script>
<script>plyr.setup();</script>
```
This will look for all elements with the specified container classname (default is `plyr`) and setup plyr on each element found. You can specify other options, including a different selector hook below. The container classname will be added to the specified element(s) if it is not already present (for the CSS).
You can initialize the player a few other ways:
Passing a [NodeList](https://developer.mozilla.org/en-US/docs/Web/API/NodeList):
```javascript
plyr.setup(document.querySelectorAll('.js-plyr'), options);
```
Passing a [HTMLElement](https://developer.mozilla.org/en/docs/Web/API/HTMLElement):
```javascript
plyr.setup(document.querySelector('.js-plyr'), options);
```
Passing a [string selector](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll):
```javascript
plyr.setup('.js-plyr', options);
```
Passing just the options object:
```javascript
plyr.setup(options);
```
#### RangeTouch
Some touch browsers (particularly Mobile Safari on iOS) seem to have issues with `<input type="range">` elements whereby touching the track to set the value doesn't work and sliding the thumb can be tricky. To combat this, I've created [RangeTouch](https://rangetouch.com) which I'd recommend including in your solution. It's a tiny script with a nice benefit for users on touch devices.
#### Options
You can pass the following options to the setup method.
Options must be passed as an object to the `setup()` method as above or as JSON in `data-plyr` attribute on each of your target elements (e.g. data-plyr='{ title: "testing" }') - note the single quotes encapsulating the JSON.
<table class="table" width="100%">
<thead>
@ -160,7 +237,7 @@ You can pass the following options to the setup method.
<td><code>enabled</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Completely disable Plyr. This would allow you to do a User Agent check or similar to programatically enable or disable Plyr for a certain UA. Example below.</td>
<td>Completely disable Plyr. This would allow you to do a User Agent check or similar to programmatically enable or disable Plyr for a certain UA. Example below.</td>
</tr>
<tr>
<td><code>html</code></td>
@ -168,12 +245,42 @@ 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 internationalization (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>iconUrl</code></td>
<td>String</td>
<td><code>null</code></td>
<td>Specify a relative path to the SVG sprite, hosted on the *same domain* as the page the player is hosted on. Using this menthod means no requirement for the AJAX sprite loading script. See the <a href="#svg">SVG section</a> for more info.</td>
</tr>
<tr>
<td><code>debug</code></td>
<td>Boolean</td>
<td><code>false</code></td>
<td>Display debugging information on what Plyr is doing.</td>
</tr>
<tr>
<td><code>autoplay</code></td>
<td>Boolean</td>
<td><code>false</code></td>
<td>Autoplay the media on load. This is generally advised against on UX grounds. It is also disabled on iOS (an Apple limitation).</td>
</tr>
<tr>
<td><code>seekTime</code></td>
<td>Number</td>
@ -187,16 +294,56 @@ You can pass the following options to the setup method.
<td>A number, between 1 and 10, representing the initial volume of the player.</td>
</tr>
<tr>
<td><code>click</code></td>
<td><code>clickToPlay</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Click (or tap) will toggle pause/play of a <code>&lt;video&gt;</code>.</td>
<td>Click (or tap) of the video container will toggle pause/play.</td>
</tr>
<tr>
<td><code>hideControls</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Hide video controls automatically after 2s of no mouse or focus movement, on control element blur (tab out), on playback start or entering fullscreen. As soon as the mouse is moved, a control element is focused or playback is paused, the controls reappear instantly.</td>
</tr>
<tr>
<td><code>showPosterOnEnd</code></td>
<td>Boolean</td>
<td><code>false</code></td>
<td>This will restore and *reload* HTML5 video once playback is complete. Note: depending on the browser caching, this may result in the video downloading again (or parts of it). Use with caution.</td>
</tr>
<tr>
<td><code>tooltips</code></td>
<td>Object</td>
<td><code>{ controls: false, seek: true }</code></td>
<td>
<strong>controls</strong>: Display control labels as tooltips on :hover &amp; :focus (by default, the labels are screen reader only).
<br><br>
<strong>seek</strong>: Display a seek tooltip to indicate on click where the media would seek to.
</td>
</tr>
<tr>
<td><code>duration</code></td>
<td>Number</td>
<td><code>null</code></td>
<td>Specify a custom duration.</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>
<td>Object</td>
<td>&mdash;</td>
<td>See <code>plyr.js</code> in <code>/src</code> for more info. The only option you might want to change is <code>player</code> which is the hook used for Plyr, the default is <code>.player</code>.</td>
<td>See <code>plyr.js</code> in <code>/src</code> for more info. You probably don't need to change any of these.</td>
</tr>
<tr>
<td><code>listeners</code></td>
<td>Object</td>
<td>&mdash;</td>
<td>Allows early binding of event listeners to the controls. See <code>controls</code> above for list of controls and see <code>plyr.js</code> in <code>/src</code> for more info.</td>
</tr>
<tr>
<td><code>classes</code></td>
@ -208,29 +355,79 @@ You can pass the following options to the setup method.
<td><code>captions</code></td>
<td>Object</td>
<td>&mdash;</td>
<td>This currently contains one property `defaultActive` which toggles if captions should be on by default. The default value is <code>false</code>.</td>
<td>One property <code>defaultActive</code> which toggles if captions should be on by default. The default value is <code>false</code>.</td>
</tr>
<tr>
<td><code>fullscreen</code></td>
<td>Object</td>
<td>&mdash;</td>
<td>This currently contains two properties;<code>enabled</code> which toggles if fullscreen should be enabled (if the browser supports it). The default value is <code>true</code>. Also an extra property called <code>fallback</code> which will enable a full window view for older browsers. The default value is <code>true</code>.</td>
<td>See <a href="#fullscreen-options">below</a></td>
</tr>
<tr>
<td><code>storage</code></td>
<td>Object</td>
<td>&mdash;</td>
<td>This currently contains one property `enabled` 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.</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>
</tbody>
</table>
#### Fullscreen options
<table class="table" width="100%" id="fullscreen-options">
<thead>
<tr>
<th width="20%">Option</th>
<th width="15%">Type</th>
<th width="15%">Default</th>
<th width="50%">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>enabled</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Toggles if fullscreen should be enabled (if the browser supports it).</td>
</tr>
<tr>
<td><code>fallback</code></td>
<td>Boolean</td>
<td><code>true</code></td>
<td>Enable a full viewport view for older browsers.</td>
</tr>
<tr>
<td><code>allowAudio</code></td>
<td>Boolean</td>
<td><code>false</code></td>
<td>Allow audio play to toggle fullscreen. This will be more useful later when posters are supported.</td>
</tr>
</tbody>
</table>
## API
A `plyr` object is added to any element that Plyr is initialised on. You can then control the player by accessing methods in the `plyr` object. For example if you wanted to pause Plyr:
#### Fetching the plyr instance
A `plyr` object is added to any element that Plyr is initialized on. You can then control the player by accessing methods in the `plyr` object.
There are two ways to access the instance, firstly you re-query the element container you used for setup (e.g. `.js-plyr`) like so:
```javascript
document.querySelectorAll(".player")[0].plyr.pause();
var player = document.querySelector('.js-plyr').plyr;
```
Or you can use the returned object from your call to the setup method:
```javascript
var player = plyr.setup('.js-plyr')[0];
```
This will return an array of plyr instances setup, so you need to specify the index of the instance you want. This is less useful if you are setting up mutliple instances. You can listen for the `setup` [event](#events) documented below which will return each instance one by one, as they are setup (in the `plyr` key of the event object).
Once you have your instance, you can use the API methods below on it. For example to pause it:
```javascript
player.pause();
```
Here's a list of the methods supported:
@ -242,8 +439,8 @@ Here's a list of the methods supported:
<th width="15%">Parameters</th>
<th width="65%">Description</th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
<tr>
<td><code>play()</code></td>
<td>&mdash;</td>
@ -279,6 +476,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>
@ -289,54 +491,341 @@ 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>
<td>String or Array</td>
<td>Object or undefined</td>
<td>
Set the media source.
<br><br>
<strong>string</strong><br>
<code>.source("/path/to/video.mp4")</code><br>
This will set the <code>src</code> attribute on the <code>video</code> or <code>audio</code> element.
Get/Set the media source.
<br><br>
<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.
<strong>Object</strong><br>
See <a href="#source-method">below</a>
<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.)
<br><br>
<strong>undefined</strong><br>
Returns the current media source url. Works for both native videos and embeds.
</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>
## Events/Callbacks
#### .source() method
The `plyr` object on the player element also contains a `media` property which is a reference to the `<audio>` or `<video>` element within the player which you can use to listen for events. Here's an example:
This allows changing the plyr source and type on the fly.
Video example:
```javascript
var media = document.querySelectorAll(".player")[0].plyr.media;
media.addEventListener("playing", function() {
console.log("playing");
player.source({
type: 'video',
title: 'Example title',
sources: [{
src: '/path/to/movie.mp4',
type: 'video/mp4'
},
{
src: '/path/to/movie.webm',
type: 'video/webm'
}],
poster: '/path/to/poster.jpg',
tracks: [{
kind: 'captions',
label: 'English',
srclang:'en',
src: '/path/to/captions.vtt',
default: true
}]
});
```
A complete list of events can be found here:
[Media Events - W3.org](http://www.w3.org/2010/05/video/mediaevents.html)
Audio example:
```javascript
player.source({
type: 'audio',
title: 'Example title',
sources: [{
src: '/path/to/audio.mp3',
type: 'audio/mp3'
},
{
src: '/path/to/audio.ogg',
type: 'audio/ogg'
}]
});
```
YouTube example:
```javascript
player.source({
type: 'video',
title: 'Example title',
sources: [{
src: 'bTqVqk7FSmY',
type: 'youtube'
}]
});
```
Vimeo example
```javascript
player.source({
type: 'video',
title: 'Example title',
sources: [{
src: '143418951',
type: 'vimeo'
}]
});
```
Some more details on the object parameters
<table class="table" width="100%">
<thead>
<tr>
<th width="20%">Key</th>
<th width="15%">Type</th>
<th width="65%">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>type</code></td>
<td>String</td>
<td>Options are <code>video</code>, <code>audio</code>, <code>youtube</code> and <code>vimeo</code></td>
</tr>
<tr>
<td><code>title</code></td>
<td>String</td>
<td>Title of the new media. Used for the aria labelling.</td>
</tr>
<tr>
<td><code>sources</code></td>
<td>Array</td>
<td>This is an array of sources. <code>type</code> is optional for YouTube and Vimeo when specifying an array. For YouTube and Vimeo media, only the video ID must be passed as the source as shown above. The keys of this object are mapped directly to HTML attributes so more can be added to the object if required.</td>
</tr>
<tr>
<td><code>poster</code></td>
<td>String</td>
<td>URL for the poster image (video only).</td>
</tr>
<tr>
<td><code>tracks</code></td>
<td>Array</td>
<td>An array of track objects. Each element in the array is mapped directly to a track element and any keys mapped directly to HTML attributes so as in the example above, it will render as `<track kind="captions" label="English" srclang="en" src="https://cdn.selz.com/plyr/1.0/example_captions_en.vtt" default>`. Booleans are converted to HTML5 value-less attributes.</td>
</tr>
</tbody>
</table>
## Events
You can listen for events on the element you setup Plyr on. Some events only apply to HTML5 audio and video.
<table class="table" width="100%">
<thead>
<tr>
<th width="20%">Event name</th>
<th width="20%">HTML5 only</th>
<th width="60%">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>canplay</code></td>
<td></td>
<td>Sent when enough data is available that the media can be played, at least for a couple of frames. This corresponds to the <code>HAVE_ENOUGH_DATA</code> <code>readyState</code>.</td>
</tr>
<tr>
<td><code>canplaythrough</code></td>
<td></td>
<td>Sent when the ready state changes to <code>CAN_PLAY_THROUGH</code>, indicating that the entire media can be played without interruption, assuming the download rate remains at least at the current level. <strong>Note</strong>: Manually setting the <code>currentTime</code> will eventually fire a <code>canplaythrough</code> event in firefox. Other browsers might not fire this event.</td>
</tr>
<tr>
<td><code>emptied</code></td>
<td></td>
<td>The media has become empty; for example, this event is sent if the media has already been loaded (or partially loaded), and the <code>load()</code> method is called to reload it.</td>
</tr>
<tr>
<td><code>ended</code></td>
<td></td>
<td>Sent when playback completes.</td>
</tr>
<tr>
<td><code>error</code></td>
<td></td>
<td>Sent when an error occurs.&nbsp; The element's <code>error</code> attribute contains more information.</td>
</tr>
<tr>
<td><code>loadeddata</code></td>
<td></td>
<td>The first frame of the media has finished loading.</td>
</tr>
<tr>
<td><code>loadedmetadata</code></td>
<td></td>
<td>The media's metadata has finished loading; all attributes now contain as much useful information as they're going to.</td>
</tr>
<tr>
<td><code>loadstart</code></td>
<td></td>
<td>Sent when loading of the media begins.</td>
</tr>
<tr>
<td><code>pause</code></td>
<td></td>
<td>Sent when playback is paused.</td>
</tr>
<tr>
<td><code>play</code></td>
<td></td>
<td>Sent when playback of the media starts after having been paused; that is, when playback is resumed after a prior <code>pause</code> event.</td>
</tr>
<tr>
<td><code>playing</code></td>
<td></td>
<td>Sent when the media begins to play (either for the first time, after having been paused, or after ending and then restarting).</td>
</tr>
<tr>
<td><code>progress</code></td>
<td></td>
<td>Sent periodically to inform interested parties of progress downloading the media. Information about the current amount of the media that has been downloaded is available in the media element's <code>buffered</code> attribute.</td>
</tr>
<tr>
<td><code>seeked</code></td>
<td></td>
<td>Sent when a seek operation completes.</td>
</tr>
<tr>
<td><code>seeking</code></td>
<td></td>
<td>Sent when a seek operation begins.</td>
</tr>
<tr>
<td><code>stalled</code></td>
<td></td>
<td>Sent when the user agent is trying to fetch media data, but data is unexpectedly not forthcoming.</td>
</tr>
<tr>
<td><code>timeupdate</code></td>
<td></td>
<td>The time indicated by the element's <code>currentTime</code> attribute has changed.</td>
</tr>
<tr>
<td><code>volumechange</code></td>
<td></td>
<td>Sent when the audio volume changes (both when the volume is set and when the <code>muted</code> attribute is changed).</td>
</tr>
<tr>
<td><code>waiting</code></td>
<td></td>
<td>Sent when the requested operation (such as playback) is delayed pending the completion of another operation (such as a seek).</td>
</tr>
<tr>
<td><code>enterfullscreen</code></td>
<td></td>
<td>User enters fullscreen (either the proper fullscreen or full-window fallback for older browsers)</td>
</tr>
<tr>
<td><code>exitfullscreen</code></td>
<td></td>
<td>User exits fullscreen</td>
</tr>
<tr>
<td><code>captionsenabled</code></td>
<td></td>
<td>Captions toggled on</td>
</tr>
<tr>
<td><code>captionsdisabled</code></td>
<td></td>
<td>Captions toggled off</td>
</tr>
<tr>
<td><code>ready</code></td>
<td></td>
<td>Triggered when initial setup is done or a source change has occurred.</td>
</tr>
</tbody>
</table>
Details borrowed from: [https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events)
Here's an example of binding an event listener:
```javascript
document.querySelector('.js-plyr').addEventListener('ready', function() {
var player = event.target.plyr;
});
```
## Embeds
YouTube and Vimeo are currently supported and function much like a HTML5 video. Check the relevant documentation sections for any differences.
Plyr references a custom version of the Vimeo Froogaloop API as Vimeo have neglected to maintain the library and there were bugs with their version. You don't need to worry about including your own versions of the Vimeo or YouTube JavaScript APIs.
The native API's can be accessed through the `embed` property of the plyr object. For example:
```javascript
document.querySelector('.js-plyr').addEventListener('ready', function() {
var player = event.target.plyr;
// YouTube
console.log(player.embed.getVideoData());
// Vimeo
console.log(player.embed.api('getColor'));
});
```
More info on the respective API's here:
[YouTube API Reference](https://developers.google.com/youtube/js_api_reference)
[Vimeo API Reference](https://developer.vimeo.com/player/js-api#reference)
*Please note*: not all API methods may work 100%. Your mileage may vary. It's better to use the universal plyr API where possible.
## 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.
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 `plyr-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>
@ -353,19 +842,19 @@ Fullscreen in Plyr is supported for all browsers that [currently support it](htt
<td></td>
<td></td>
<td></td>
<td>✖&sup2;</td>
<td>API&sup2;</td>
<td>&sup3;</td>
</tr>
</tbody>
</table>
&sup1; iPhone forces the native player for `<video>` so no customisation possible
&sup1; Mobile Safari on the iPhone forces the native player for `<video>` so no useful customisation is possible. `<audio>` elements have volume controls disabled.
&sup2; Native player used (no support for `<progress>` or `<input type="range">`)
&sup2; Native player used (no support for `<progress>` or `<input type="range">`) but the API is supported (v1.0.28+)
&sup3; IE10 has no native fullscreen support, fallback can be used (see options)
The `enabled` option can be used to disable certain User Agents. For example, if you don't want to use Plyr for smartphones, you could use:
The `enabled` option can be used to disable certain User Agents. For example, if you don't want to use Plyr for smartphones, you could use:
```javascript
enabled: /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)
@ -374,24 +863,32 @@ 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/)
- [HTML5 Weekly #177](http://html5weekly.com/issues/177)
- [Responsive Design #149](http://us4.campaign-archive2.com/?u=559bc631fe5294fc66f5f7f89&id=451a61490f)
- [Web Design Weekly #174](https://web-design-weekly.com/2015/02/24/web-design-weekly-174/)
- [Hacker News](https://news.ycombinator.com/item?id=9136774)
- [Web Platform Daily](http://webplatformdaily.org/releases/2015-03-04)
- [LayerVault Designer News](https://news.layervault.com/stories/45394-plyr--a-simple-html5-media-player)
- [The Treehouse Show #131](https://teamtreehouse.com/library/episode-131-origami-react-responsive-hero-images)
- [noupe.com](http://www.noupe.com/design/html5-plyr-is-a-responsive-and-accessible-video-player-94389.html)
## Used by
- [Selz.com](https://selz.com)
- [koel - A personal music streaming server that works.](http://koel.phanan.net/)
- [Oscar Radio](http://oscar-radio.xyz/)
Let me know on [Twitter](https://twitter.com/sam_potts) I can add you to the above list. It'd be awesome to see how you're using Plyr :-)
Let me know on [Twitter](https://twitter.com/sam_potts) I can add you to the above list. It'd be awesome to see how you're using Plyr :-)
## Useful links and credits
Credit to the PayPal HTML5 Video player from which Plyr's caption functionality is ported from:
@ -404,4 +901,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

29
src/less/mixins.less Normal file
View File

@ -0,0 +1,29 @@
// ==========================================================================
// Plyr mixins
// https://github.com/selz/plyr
// ==========================================================================
// <input type="range"> styling
.plyr-range-track() {
height: @plyr-range-track-height;
background: transparent;
border: 0;
border-radius: (@plyr-range-track-height / 2);
user-select: none;
}
.plyr-range-thumb() {
position: relative;
height: @plyr-range-thumb-height;
width: @plyr-range-thumb-width;
background: @plyr-range-thumb-bg;
border: @plyr-range-thumb-border;
border-radius: 100%;
transition: background .2s ease, border .2s ease, transform .2s ease;
box-shadow: @plyr-range-thumb-shadow;
box-sizing: border-box;
}
.plyr-range-thumb-active() {
background: @plyr-range-thumb-active-bg;
border-color: @plyr-range-thumb-active-border-color;
transform: scale(@plyr-range-thumb-active-scale);
}

File diff suppressed because it is too large Load Diff

66
src/less/variables.less Normal file
View File

@ -0,0 +1,66 @@
// ==========================================================================
// Plyr variables
// https://github.com/selz/plyr
// ==========================================================================
// Colors
@plyr-color-main: #3498db;
// Font sizes
@plyr-font-size-small: 14px;
@plyr-font-size-base: 16px;
// Captions
@plyr-font-size-captions-base: ceil(@plyr-font-size-base * 1.25);
@plyr-font-size-captions-medium: ceil(@plyr-font-size-base * 1.5);
@plyr-font-size-captions-large: (@plyr-font-size-base * 2);
// Controls
@plyr-control-spacing: 10px;
@plyr-video-controls-bg: #000;
@plyr-video-control-color: #fff;
@plyr-video-control-color-hover: #fff;
@plyr-video-control-bg-hover: @plyr-color-main;
@plyr-audio-controls-bg: #fff;
@plyr-audio-controls-border: 1px solid #dbe3e8;
@plyr-audio-controls-box-shadow: 0 1px 1px fade(#000, 5%);
@plyr-audio-control-color: #565D64;
@plyr-audio-control-color-hover: #fff;
@plyr-audio-control-bg-hover: @plyr-color-main;
// Tooltips
@plyr-tooltip-bg: @plyr-video-controls-bg;
@plyr-tooltip-border-color: fade(darken(@plyr-video-controls-bg, 75%), 10%);
@plyr-tooltip-arrow-border-color: fade(darken(@plyr-video-controls-bg, 75%), 20%);
@plyr-tooltip-border-width: 1px;
@plyr-tooltip-shadow: 0 0 5px @plyr-tooltip-border-color, 0 0 0 @plyr-tooltip-border-width @plyr-tooltip-border-color;
@plyr-tooltip-color: @plyr-video-control-color;
@plyr-tooltip-padding: (@plyr-control-spacing / 2);
@plyr-tooltip-arrow-size: 4px;
@plyr-tooltip-radius: 3px;
// Progress
@plyr-progress-loading-size: 25px;
@plyr-progress-loading-bg: fade(#000, 15%);
@plyr-video-progress-bg: fade(#fff, 25%);
@plyr-video-progress-buffered-bg: @plyr-video-progress-bg;
@plyr-audio-progress-bg: fade(#C6D6DB, 66%);
@plyr-audio-progress-buffered-bg: @plyr-audio-progress-bg;
// Range sliders
@plyr-range-track-height: 8px;
@plyr-range-thumb-height: floor(@plyr-range-track-height * 2);
@plyr-range-thumb-width: floor(@plyr-range-track-height * 2);
@plyr-range-thumb-bg: #fff;
@plyr-range-thumb-border: 2px solid transparent;
@plyr-range-thumb-shadow: 0 1px 1px fade(@plyr-video-controls-bg, 15%), 0 0 0 1px fade(#000, 15%);
@plyr-range-thumb-active-border-color: #fff;
@plyr-range-thumb-active-bg: @plyr-video-control-bg-hover;
@plyr-range-thumb-active-scale: 1.25;
@plyr-video-range-track-bg: @plyr-video-progress-buffered-bg;
@plyr-audio-range-track-bg: @plyr-audio-progress-buffered-bg;
@plyr-range-selected-bg: @plyr-color-main;
// Breakpoints
@plyr-bp-screen-sm: 480px;
@plyr-bp-screen-md: 768px;

View File

@ -1,518 +0,0 @@
// ==========================================================================
// HTML5 Media Player
// ==========================================================================
// Variables
// -------------------------------
// Colors
$blue: #3498DB;
$gray-dark: #343f4a;
$gray: #565d64;
$gray-light: #cbd0d3;
// Font sizes
$font-size-small: 14px;
$font-size-base: 16px;
$font-size-large: ceil(($font-size-base * 1.5));
// Controls
$control-spacing: 10px;
$controls-bg: $gray-dark;
$control-bg-hover: $blue;
$control-color: $gray-light;
$control-color-inactive: $gray;
$control-color-hover: #fff;
// Progress
$progress-bg: lighten($gray, 10%);
$progress-playing-bg: $blue;
$progress-buffered-bg: $gray;
$progress-loading-size: 40px;
$progress-loading-bg: rgba(0,0,0, .15);
// Range
$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;
// Breakpoints
$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;
}
// Contain floats: nicolasgallagher.com/micro-clearfix-hack/
@mixin clearfix()
{
zoom: 1;
&:before,
&:after { content: ""; display: table; }
&:after { clear: both; }
}
// Tab focus styles
@mixin tab-focus()
{
outline: thin dotted #000;
outline-offset: 0;
}
// Animation
// ---------------------------------------
@keyframes progress {
to { background-position: @progress-loading-size 0; }
}
// <input type="range"> styling
// ---------------------------------------
@mixin volume-thumb()
{
height: $volume-thumb-height;
width: $volume-thumb-width;
background: $volume-thumb-bg;
border: 0;
border-radius: ($volume-thumb-height / 2);
transition: background .3s ease;
cursor: ew-resize;
}
@mixin volume-track()
{
height: $volume-track-height;
background: $volume-track-bg;
border: 0;
border-radius: ($volume-track-height / 2);
}
@mixin seek-thumb() {
background: transparent;
border: 0;
width: ($control-spacing * 2);
height: $control-spacing;
}
@mixin seek-track() {
background: none;
border: 0;
}
// Font smoothing
// ---------------------------------------
@mixin font-smoothing($mode: on) when ($mode = on)
{
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
@mixin font-smoothing($mode: on) when ($mode = off)
{
-moz-osx-font-smoothing: auto;
-webkit-font-smoothing: subpixel-antialiased;
}
// Styles
// -------------------------------
// Base
.player {
position: relative;
max-width: 100%;
min-width: 290px;
overflow: hidden; // For the controls
// border-box everything
// http://paulirish.com/2012/box-sizing-border-box-ftw/
&,
*,
*::after,
*::before {
box-sizing: border-box;
}
// For video
&-video-wrapper {
position: relative;
}
video {
width: 100%;
height: auto;
vertical-align: middle;
}
// Captions
&-captions {
display: none;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 20px;
min-height: 2.5em;
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;
text-align: center;
@include font-smoothing();
@media (min-width: $bp-captions-large) {
font-size: $font-size-large;
}
}
&.captions-active &-captions {
display: block;
}
// Player controls
&-controls {
@include clearfix();
@include font-smoothing();
position: relative;
padding: ($control-spacing * 2) $control-spacing $control-spacing;
background: $controls-bg;
line-height: 1;
text-align: center;
// Layout
&-sound {
display: block;
margin: $control-spacing auto 0;
}
@media (min-width: $bp-control-split) {
&-playback {
float: left;
}
&-sound {
float: right;
margin-top: 0;
}
}
input + label,
button {
display: inline-block;
vertical-align: middle;
margin: 0 2px;
padding: ($control-spacing / 2) $control-spacing;
transition: background .3s ease;
border-radius: 3px;
cursor: pointer;
svg {
width: 18px;
height: 18px;
display: block;
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;
}
input:focus + label,
button:focus {
@include tab-focus();
color: $control-color-focus;
}
button:hover,
input + label:hover {
background: $control-bg-hover;
color: $control-color-hover;
}
.icon-exit-fullscreen,
.icon-muted,
.icon-captions-on {
display: none;
}
.player-time {
display: inline-block;
vertical-align: middle;
margin-left: $control-spacing;
color: $control-color;
font-weight: 600;
font-size: $font-size-small;
@include font-smoothing();
}
}
// Player progress
// <progress> element
&-progress {
position: absolute;
top: 0;
left: 0;
right: 0;
width: 100%;
height: $control-spacing;
background: $progress-bg;
&-buffer[value],
&-played[value],
&-seek[type=range] {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
margin: 0;
vertical-align: top;
-webkit-appearance: none;
-moz-appearance: none;
border: none;
background: transparent;
}
&-buffer[value],
&-played[value] {
&::-webkit-progress-bar {
background: transparent;
}
// Inherit from currentColor;
&::-webkit-progress-value {
background: currentColor;
}
&::-moz-progress-bar {
background: currentColor;
}
}
&-played[value] {
z-index: 2;
color: $progress-playing-bg;
}
&-buffer[value] {
color: $progress-buffered-bg;
}
// Seek control
// <input[type='range']> element
// Specificity is for bootstrap compatibility
&-seek[type=range] {
z-index: 3;
cursor: pointer;
outline: 0;
// Webkit
&::-webkit-slider-runnable-track {
@include seek-track();
}
&::-webkit-slider-thumb {
-webkit-appearance: none;
@include seek-thumb();
}
// Mozilla
&::-moz-range-track {
@include seek-track();
}
&::-moz-range-thumb {
-moz-appearance: none;
@include seek-thumb();
}
// Microsoft
&::-ms-track {
color: transparent;
@include seek-track();
}
&::-ms-fill-lower,
&::-ms-fill-upper {
@include seek-track();
}
&::-ms-thumb {
@include seek-thumb();
}
&:focus {
outline: 0;
}
&::-moz-focus-outer {
border: 0;
}
}
}
// Loading state
&.loading .player-progress-buffer {
animation: progress 1s linear infinite;
background-size: $progress-loading-size $progress-loading-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%,
$progress-loading-bg 75%,
transparent 75%,
transparent);
color: transparent;
}
// States
&-controls [data-player='pause'],
&.playing .player-controls [data-player='play'] {
display: none;
}
&.playing .player-controls [data-player='pause'] {
display: inline-block;
}
// Volume control
// <input[type='range']> element
// Specificity is for bootstrap compatibility
&-volume[type=range] {
vertical-align: middle;
-webkit-appearance: none;
-moz-appearance: none;
width: 100px;
margin: 0 $control-spacing 0 0;
padding: 0;
cursor: pointer;
background: none;
// Webkit
&::-webkit-slider-runnable-track {
@include range-track();
}
&::-webkit-slider-thumb {
-webkit-appearance: none;
margin-top: -(($volume-thumb-height - $volume-track-height) / 2);
@include range-thumb();
}
// Mozilla
&::-moz-range-track {
@include range-track();
}
&::-moz-range-thumb {
@include range-thumb();
}
// Microsoft
&::-ms-track {
height: $volume-track-height;
background: transparent;
border-color: transparent;
border-width: (($volume-thumb-height - $volume-track-height) / 2) 0;
color: transparent;
}
&::-ms-fill-lower,
&::-ms-fill-upper {
@include range-track();
}
&::-ms-thumb {
@include range-thumb();
}
&:focus {
outline: 0;
&::-webkit-slider-thumb {
background: $volume-thumb-bg-focus;
}
&::-moz-range-thumb {
background: $volume-thumb-bg-focus;
}
&::-ms-thumb {
background: $volume-thumb-bg-focus;
}
}
}
// Full screen mode
&-fullscreen,
&.fullscreen-active {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100%;
width: 100%;
z-index: 10000000;
background: #000;
.player-video-wrapper {
height: 100%;
width: 100%;
video {
height: 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;
left: 0;
right: 0;
}
}
// Change icons on state change
&.fullscreen-active .icon-exit-fullscreen,
&.muted .player-controls .icon-muted,
&.captions-active .player-controls .icon-captions-on {
display: block;
& + svg {
display: none;
}
}
// Some options are hidden by default
[data-player='captions'],
[data-player='captions'] + label,
[data-player='fullscreen'],
[data-player='fullscreen'] + label {
display: none;
}
&.captions-enabled [data-player='captions'],
&.captions-enabled [data-player='captions'] + label,
&.fullscreen-enabled [data-player='fullscreen'],
&.fullscreen-enabled [data-player='fullscreen'] + label {
display: inline-block;
}
// Full browser view hides toggle
&-fullscreen [data-player='fullscreen'],
&-fullscreen [data-player='fullscreen'] + label {
display: none !important;
}
}

29
src/scss/mixins.scss Normal file
View File

@ -0,0 +1,29 @@
// ==========================================================================
// Plyr mixins
// https://github.com/selz/plyr
// ==========================================================================
// <input type="range"> styling
@mixin plyr-range-track() {
height: $plyr-range-track-height;
background: transparent;
border: 0;
border-radius: ($plyr-range-track-height / 2);
user-select: none;
}
@mixin plyr-range-thumb() {
position: relative;
height: $plyr-range-thumb-height;
width: $plyr-range-thumb-width;
background: $plyr-range-thumb-bg;
border: $plyr-range-thumb-border;
border-radius: 100%;
transition: background .2s ease, border .2s ease, transform .2s ease;
box-shadow: $plyr-range-thumb-shadow;
box-sizing: border-box;
}
@mixin plyr-range-thumb-active() {
background: $plyr-range-thumb-active-bg;
border-color: $plyr-range-thumb-active-border-color;
transform: scale($plyr-range-thumb-active-scale);
}

686
src/scss/plyr.scss Normal file
View File

@ -0,0 +1,686 @@
// ==========================================================================
// Plyr styles
// https://github.com/selz/plyr
// ==========================================================================
@import "variables";
@import "mixins";
// Animation
// ---------------------------------------
@keyframes plyr-progress {
to { background-position: $plyr-progress-loading-size 0; }
}
// Styles
// -------------------------------
// Base
.plyr {
position: relative;
max-width: 100%;
min-width: 200px;
font-family: Avenir, "Avenir Next", "Helvetica Neue", "Segoe UI", Helvetica, Arial, sans-serif;
// border-box everything
// http://paulirish.com/2012/box-sizing-border-box-ftw/
&,
*,
*::after,
*::before {
box-sizing: border-box;
}
// Fix 300ms delay
a, button, input, label {
touch-action: manipulation;
}
// Media elements
video,
audio {
width: 100%;
height: auto;
vertical-align: middle;
border-radius: inherit;
}
// Range inputs
// Specificity is for bootstrap compatibility
input[type='range'] {
display: block;
height: ($plyr-range-thumb-height * $plyr-range-thumb-active-scale);
width: 100%;
margin: 0;
padding: 0;
vertical-align: middle;
appearance: none;
cursor: pointer;
border: none;
background: transparent;
// WebKit
&::-webkit-slider-runnable-track {
@include plyr-range-track();
}
&::-webkit-slider-thumb {
-webkit-appearance: none;
margin-top: -(($plyr-range-thumb-height - $plyr-range-track-height) / 2);
@include plyr-range-thumb();
}
// Mozilla
&::-moz-range-track {
@include plyr-range-track();
}
&::-moz-range-thumb {
@include plyr-range-thumb();
}
&::-moz-focus-outer {
border: 0;
}
// Microsoft
&::-ms-track {
height: $plyr-range-track-height;
background: transparent;
border: 0;
color: transparent;
}
&::-ms-fill-upper {
@include plyr-range-track();
}
&::-ms-fill-lower {
@include plyr-range-track();
background: $plyr-range-selected-bg;
}
&::-ms-thumb {
@include plyr-range-thumb();
// For some reason, Edge uses the -webkit margin above
margin-top: 0;
}
&::-ms-tooltip {
display: none;
}
// Focus styles
&:focus {
outline: 0;
}
&::-moz-focus-outer {
border: 0;
}
&.tab-focus:focus {
outline-offset: 3px;
}
// Pressed styles
&:active {
&::-webkit-slider-thumb {
@include plyr-range-thumb-active();
}
&::-moz-range-thumb {
@include plyr-range-thumb-active();
}
&::-ms-thumb {
@include plyr-range-thumb-active();
}
}
}
}
// Video range inputs
.plyr--video input[type='range'].tab-focus:focus {
outline: 1px dotted transparentize($plyr-video-control-color, .5);
}
// Audio range inputs
.plyr--audio input[type='range'].tab-focus:focus {
outline: 1px dotted transparentize($plyr-audio-control-color, .5);
}
// Screen reader only elements
.plyr__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;
}
// Video
.plyr__video-wrapper {
position: relative;
background: #000;
border-radius: inherit;
// Cleaner radius, also forces iframe radius
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
}
// Container for embeds
.plyr__video-embed {
padding-bottom: 56.25%; /* 16:9 */
height: 0;
overflow: hidden;
border-radius: inherit;
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
user-select: none;
}
// Vimeo hack
> div {
position: relative;
padding-bottom: 200%;
transform: translateY(-35.95%);
}
}
// To allow mouse events to be captured if full support
.plyr .plyr__video-embed iframe {
pointer-events: none;
}
// Captions
// --------------------------------------------------------------
// Hide default captions
.plyr video::-webkit-media-text-track-container {
display: none;
}
.plyr__captions {
display: none;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: ($plyr-control-spacing * 2);
transform: translateY(-($plyr-control-spacing * 6));
transition: transform .3s ease;
color: #fff;
font-size: $plyr-font-size-captions-base;
text-align: center;
font-weight: 400;
span {
border-radius: 2px;
padding: floor($plyr-control-spacing / 3) $plyr-control-spacing;
background: transparentize(#000, .15);
}
span:empty {
display: none;
}
@media (min-width: $plyr-bp-screen-md) {
font-size: $plyr-font-size-captions-medium;
}
}
.plyr--captions-active .plyr__captions {
display: block;
}
.plyr--fullscreen-active .plyr__captions {
font-size: $plyr-font-size-captions-large;
}
.plyr--hide-controls .plyr__captions {
transform: translateY(-($plyr-control-spacing * 2));
}
// Controls
// --------------------------------------------------------------
// Playback controls
.plyr__controls {
display: flex;
align-items: center;
line-height: 1;
text-align: center;
transition: opacity .3s ease;
// Spacing
> button,
.plyr__progress,
.plyr__time {
margin-left: ($plyr-control-spacing / 2);
&:first-child {
margin-left: 0;
}
}
.plyr__volume {
margin-left: ($plyr-control-spacing / 2);
}
[data-plyr="pause"] {
margin-left: 0;
}
// Buttons
button {
position: relative;
display: inline-block;
flex-shrink: 0;
vertical-align: middle;
padding: ($plyr-control-spacing / 2);
border: 0;
background: transparent;
border-radius: 3px;
cursor: pointer;
transition: background .3s ease, color .3s ease, opacity .3s ease;
color: inherit;
svg {
width: 18px;
height: 18px;
display: block;
fill: currentColor;
}
// Default focus
&:focus {
outline: 0;
}
}
// Hide toggle icons by default
.icon--exit-fullscreen,
.icon--muted,
.icon--captions-on {
display: none;
}
@media (min-width: $plyr-bp-screen-sm) {
> button,
.plyr__progress,
.plyr__time {
margin-left: $plyr-control-spacing;
}
button {
padding: ($plyr-control-spacing / 2) $plyr-control-spacing;
}
}
}
// Hide controls
.plyr--hide-controls .plyr__controls {
opacity: 0;
}
// Video controls
.plyr--video .plyr__controls {
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: ($plyr-control-spacing * 5) $plyr-control-spacing $plyr-control-spacing;
background: linear-gradient(transparentize($plyr-video-controls-bg, 1), transparentize($plyr-video-controls-bg, .5));
border-bottom-left-radius: inherit;
border-bottom-right-radius: inherit;
color: $plyr-video-control-color;
button {
// Hover and tab focus
&.tab-focus:focus,
&:hover {
background: $plyr-video-control-bg-hover;
color: $plyr-video-control-color-hover;
}
}
@media (min-width: $plyr-bp-screen-sm) {
padding-left: ($plyr-control-spacing * 1.5);
padding-right: ($plyr-control-spacing * 1.5);
}
}
// Audio controls
.plyr--audio .plyr__controls {
padding: $plyr-control-spacing;
border-radius: inherit;
background: $plyr-audio-controls-bg;
border: $plyr-audio-controls-border;
box-shadow: $plyr-audio-controls-box-shadow;
color: $plyr-audio-control-color;
button {
// Hover and tab focus
&.tab-focus:focus,
&:hover {
background: $plyr-audio-control-bg-hover;
color: $plyr-audio-control-color-hover;
}
}
}
// Large play button (video only)
.plyr__play-large {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: $plyr-control-spacing;
background: $plyr-video-control-bg-hover;
border: 4px solid currentColor;
border-radius: 100%;
box-shadow: 0 1px 1px transparentize($plyr-video-controls-bg, .85);
color: $plyr-video-control-color;
transition: opacity .3s ease, visibility .3s ease;
svg {
position: relative;
left: 2px;
width: 20px;
height: 20px;
display: block;
fill: currentColor;
}
&:focus {
outline: 1px dotted transparentize($plyr-video-control-color, .5);
}
}
.plyr--audio .plyr__play-large {
display: none;
}
.plyr--playing .plyr__play-large {
opacity: 0;
visibility: hidden;
}
// States
.plyr__controls [data-plyr='pause'],
.plyr--playing .plyr__controls [data-plyr='play'] {
display: none;
}
.plyr--playing .plyr__controls [data-plyr='pause'] {
display: inline-block;
}
// Change icons on state change
.plyr--fullscreen-active .icon--exit-fullscreen,
.plyr--muted .plyr__controls .icon--muted,
.plyr--captions-active .plyr__controls .icon--captions-on {
display: block;
& + svg {
display: none;
}
}
// Some options are hidden by default
.plyr [data-plyr='captions'],
.plyr [data-plyr='fullscreen'] {
display: none;
}
.plyr--captions-enabled [data-plyr='captions'],
.plyr--fullscreen-enabled [data-plyr='fullscreen'] {
display: inline-block;
}
// Tooltips
// --------------------------------------------------------------
.plyr__tooltip {
position: absolute;
z-index: 2;
bottom: 100%;
margin-bottom: ($plyr-tooltip-padding * 2);
padding: $plyr-tooltip-padding ($plyr-tooltip-padding * 1.5);
pointer-events: none;
opacity: 0;
background: $plyr-tooltip-bg;
box-shadow: $plyr-tooltip-shadow;
border-radius: $plyr-tooltip-radius;
color: $plyr-tooltip-color;
font-size: $plyr-font-size-small;
line-height: 1.3;
transform: translate(-50%, 10px) scale(.8);
transform-origin: 50% 100%;
transition: transform .2s .1s ease, opacity .2s .1s ease;
// Arrows
&::before {
content: '';
position: absolute;
width: 0;
height: 0;
left: 50%;
transform: translateX(-50%);
}
// The background triangle
&::before {
bottom: -$plyr-tooltip-arrow-size;
border-right: $plyr-tooltip-arrow-size solid transparent;
border-top: $plyr-tooltip-arrow-size solid $plyr-tooltip-bg;
border-left: $plyr-tooltip-arrow-size solid transparent;
z-index: 2;
}
}
.plyr button:hover .plyr__tooltip,
.plyr button.tab-focus:focus .plyr__tooltip,
.plyr__tooltip--visible {
opacity: 1;
transform: translate(-50%, 0) scale(1);
}
.plyr button:hover .plyr__tooltip {
z-index: 3;
}
// Playback progress
// --------------------------------------------------------------
// <progress> element
.plyr__progress {
position: relative;
flex: 1;
input[type="range"] {
position: relative;
z-index: 2;
&::-webkit-slider-runnable-track {
background: transparent;
}
&::-moz-range-track {
background: transparent;
}
&::-ms-fill-upper {
background: transparent;
}
}
// Seek tooltip to show time
.plyr__tooltip {
left: 0;
}
}
.plyr__progress--buffer,
.plyr__progress--played,
.plyr__volume--display {
position: absolute;
left: 0;
top: 50%;
width: 100%;
height: $plyr-range-track-height;
margin: -($plyr-range-track-height / 2) 0 0;
padding: 0;
vertical-align: top;
appearance: none;
border: none;
border-radius: 100px;
&::-webkit-progress-bar {
background: transparent;
}
&::-webkit-progress-value {
background: currentColor;
border-radius: 100px;
min-width: $plyr-range-track-height;
}
&::-moz-progress-bar {
background: currentColor;
border-radius: 100px;
min-width: $plyr-range-track-height;
}
&::-ms-fill {
border-radius: 100px;
}
}
.plyr__progress--played,
.plyr__volume--display {
z-index: 1;
color: $plyr-range-selected-bg;
background: transparent;
transition: none;
&::-webkit-progress-value {
min-width: $plyr-range-track-height;
max-width: 99%;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&::-moz-progress-bar {
min-width: $plyr-range-track-height;
max-width: 99%;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&::-ms-fill {
display: none;
}
}
.plyr__progress--buffer {
&::-webkit-progress-value {
transition: width .2s ease;
}
&::-moz-progress-bar {
transition: width .2s ease;
}
&::-ms-fill {
transition: width .2s ease;
}
}
.plyr--video .plyr__progress--buffer,
.plyr--video .plyr__volume--display {
background: $plyr-video-range-track-bg;
}
.plyr--video .plyr__progress--buffer {
color: $plyr-video-progress-buffered-bg;
}
.plyr--audio .plyr__progress--buffer,
.plyr--audio .plyr__volume--display {
background: $plyr-audio-range-track-bg;
}
.plyr--audio .plyr__progress--buffer {
color: $plyr-audio-progress-buffered-bg;
}
// Loading state
.plyr--loading .plyr__progress--buffer {
animation: plyr-progress 1s linear infinite;
background-size: $plyr-progress-loading-size $plyr-progress-loading-size;
background-repeat: repeat-x;
background-image: linear-gradient(
-45deg,
$plyr-progress-loading-bg 25%,
transparent 25%,
transparent 50%,
$plyr-progress-loading-bg 50%,
$plyr-progress-loading-bg 75%,
transparent 75%,
transparent);
color: transparent;
}
.plyr--video.plyr--loading .plyr__progress--buffer {
background-color: $plyr-video-progress-buffered-bg;
}
.plyr--audio.plyr--loading .plyr__progress--buffer {
background-color: $plyr-audio-progress-buffered-bg;
}
// Time
// --------------------------------------------------------------
.plyr__time {
display: inline-block;
vertical-align: middle;
font-size: $plyr-font-size-small;
line-height: .95;
}
// Media duration hidden on small screens
.plyr__time + .plyr__time {
display: none;
@media (min-width: $plyr-bp-screen-md) {
display: inline-block;
}
// Add a slash in before
&::before {
content: '\2044';
margin-right: $plyr-control-spacing;
}
}
// Volume
// --------------------------------------------------------------
.plyr .plyr__volume {
display: none;
position: relative;
input[type="range"] {
position: relative;
z-index: 2;
}
@media (min-width: $plyr-bp-screen-sm) {
display: block;
max-width: 60px;
}
@media (min-width: $plyr-bp-screen-md) {
max-width: 100px;
}
}
// Hide sound controls on iOS
// It's not supported to change volume using JavaScript:
// https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html
.plyr--is-ios .plyr__volume,
.plyr--is-ios [data-plyr='mute'] {
display: none !important;
}
// Fullscreen
// --------------------------------------------------------------
.plyr--fullscreen,
.plyr--fullscreen-active {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100%;
width: 100%;
z-index: 10000000;
background: #000;
border-radius: 0;
video {
height: 100%;
}
.plyr__video-wrapper {
height: 100%;
width: 100%;
}
.plyr__controls {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
}

67
src/scss/variables.scss Normal file
View File

@ -0,0 +1,67 @@
// ==========================================================================
// Plyr variables
// https://github.com/selz/plyr
// https://robots.thoughtbot.com/sass-default
// ==========================================================================
// Colors
$plyr-color-main: #3498db !default;
// Font sizes
$plyr-font-size-small: 14px !default;
$plyr-font-size-base: 16px !default;
// Captions
$plyr-font-size-captions-base: ceil($plyr-font-size-base * 1.25) !default;
$plyr-font-size-captions-medium: ceil($plyr-font-size-base * 1.5) !default;
$plyr-font-size-captions-large: ($plyr-font-size-base * 2) !default;
// Controls
$plyr-control-spacing: 10px !default;
$plyr-video-controls-bg: #000 !default;
$plyr-video-control-color: #fff !default;
$plyr-video-control-color-hover: #fff !default;
$plyr-video-control-bg-hover: $plyr-color-main !default;
$plyr-audio-controls-bg: #fff !default;
$plyr-audio-controls-border: 1px solid #dbe3e8 !default;
$plyr-audio-controls-box-shadow: 0 1px 1px transparentize(#000, .95) !default;
$plyr-audio-control-color: #565D64 !default;
$plyr-audio-control-color-hover: #fff !default;
$plyr-audio-control-bg-hover: $plyr-color-main;
// Tooltips
$plyr-tooltip-bg: $plyr-video-controls-bg !default;
$plyr-tooltip-border-color: transparentize(darken($plyr-video-controls-bg, 75%), .9) !default;
$plyr-tooltip-arrow-border-color: transparentize(darken($plyr-video-controls-bg, 75%), .8) !default;
$plyr-tooltip-border-width: 1px !default;
$plyr-tooltip-shadow: 0 0 5px $plyr-tooltip-border-color, 0 0 0 $plyr-tooltip-border-width $plyr-tooltip-border-color !default;
$plyr-tooltip-color: $plyr-video-control-color !default;
$plyr-tooltip-padding: ($plyr-control-spacing / 2) !default;
$plyr-tooltip-arrow-size: 4px !default;
$plyr-tooltip-radius: 3px !default;
// Progress
$plyr-progress-loading-size: 25px !default;
$plyr-progress-loading-bg: transparentize(#000, .85) !default;
$plyr-video-progress-bg: transparentize(#fff, .75) !default;
$plyr-video-progress-buffered-bg: $plyr-video-progress-bg !default;
$plyr-audio-progress-bg: transparentize(#C6D6DB, .33) !default;
$plyr-audio-progress-buffered-bg: $plyr-audio-progress-bg !default;
// Range sliders
$plyr-range-track-height: 8px !default;
$plyr-range-thumb-height: floor($plyr-range-track-height * 2) !default;
$plyr-range-thumb-width: floor($plyr-range-track-height * 2) !default;
$plyr-range-thumb-bg: #fff !default;
$plyr-range-thumb-border: 2px solid transparent !default;
$plyr-range-thumb-shadow: 0 1px 1px transparentize($plyr-video-controls-bg, .85), 0 0 0 1px transparentize(#000, .85) !default;
$plyr-range-thumb-active-border-color: #fff !default;
$plyr-range-thumb-active-bg: $plyr-video-control-bg-hover !default;
$plyr-range-thumb-active-scale: 1.25 !default;
$plyr-video-range-track-bg: $plyr-video-progress-buffered-bg !default;
$plyr-audio-range-track-bg: $plyr-audio-progress-buffered-bg !default;
$plyr-range-selected-bg: $plyr-color-main !default;
// Breakpoints
$plyr-bp-screen-sm: 480px !default;
$plyr-bp-screen-md: 768px !default;

View File

@ -1,10 +1,6 @@
<?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>
<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>
<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>
<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"></path>
</g>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 747 B

After

Width:  |  Height:  |  Size: 443 B

View File

@ -1,13 +1,9 @@
<?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>
<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>
<rect id="Rectangle-1" sketch:type="MSShapeGroup" x="3" y="11" width="3" height="2"></rect>
<rect id="Rectangle-3" sketch:type="MSShapeGroup" x="12" y="11" width="3" height="2"></rect>
<rect id="Rectangle-2" sketch:type="MSShapeGroup" x="7" y="11" width="4" height="2"></rect>
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g>
<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"></path>
<rect x="3" y="11" width="3" height="2"></rect>
<rect x="12" y="11" width="3" height="2"></rect>
<rect x="7" y="11" width="4" height="2"></rect>
</g>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 557 B

View File

@ -1,13 +1,7 @@
<?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>
<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)">
<path d="M7.00325,17.01 L7.00325,13.377 L8.29625,14.694 C8.68825,15.082 9.32125,15.082 9.71325,14.694 C10.10525,14.306 10.10425,13.678 9.71325,13.291 L6.74625,10.291 C6.55825,10.105 6.30425,10 6.03725,10 C6.02625,10 6.01425,10 6.00325,10.001 C5.99225,10.002 5.98025,10 5.96925,10 C5.70325,10 5.44825,10.105 5.26025,10.291 L2.29325,13.291 C1.90225,13.679 1.90225,14.307 2.29325,14.694 C2.68425,15.081 3.31825,15.082 3.71025,14.694 L5.00425,13.377 L5.00425,17.01 C5.00425,17.557 5.44725,18 5.99425,18 L6.01225,18 C6.55925,18 7.00225,17.557 7.00225,17.01 L7.00325,17.01 Z" id="Shape" sketch:type="MSShapeGroup" transform="translate(6.003438, 14.000000) rotate(-135.000000) translate(-6.003438, -14.000000) "></path>
<path d="M15.0066876,5.377 L16.2996876,6.694 C16.6916876,7.082 17.3246876,7.082 17.7166876,6.694 C18.1086876,6.306 18.1076876,5.678 17.7166876,5.291 L14.7496876,2.291 C14.5616876,2.105 14.3076876,2 14.0406876,2 C14.0296876,2 14.0176876,2 14.0066876,2.001 C13.9956876,2.002 13.9836876,2 13.9726876,2 C13.7066876,2 13.4516876,2.105 13.2636876,2.291 L10.2966876,5.291 C9.90568756,5.679 9.90568756,6.307 10.2966876,6.694 C10.6876876,7.081 11.3216876,7.082 11.7136876,6.694 L13.0076876,5.377 L13.0076876,9.01 C13.0076876,9.557 13.4506876,10 13.9976876,10 C14.5626876,10 15.0056876,9.557 15.0056876,9.01 L15.0066876,5.377 Z" id="Shape-2" sketch:type="MSShapeGroup" transform="translate(14.006875, 6.000000) rotate(45.000000) translate(-14.006875, -6.000000) "></path>
</g>
<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">
<g transform="translate(9.000000, 9.000000) rotate(-180.000000) translate(-9.000000, -9.000000) translate(0.000000, 2.000000)">
<path d="M7.69999981,6.30000001 C7.00064659,5.62264405 6.3,6.3 6.3,6.3 L2,10.6 L2,6 L0,6 L0,13 C0,13.6 0.4,14 1,14 L8,14 L8,12 L3.4,12 L7.7,7.7 C7.7,7.7 8.39935303,6.97735597 7.69999981,6.30000001 Z"></path>
<path d="M11,14 L11,12 L16,12 L16,2 L2,2 L2,3 L0,3 L0,1 C0,0.4 0.4,0 1,0 L17,0 C17.6,0 18,0.4 18,1 L18,13 C18,13.6 17.6,14 17,14 L11,14 Z"></path>
</g>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 719 B

View File

@ -1,13 +1,7 @@
<?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>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1">
<g id="collapse" sketch:type="MSLayerGroup" transform="translate(-1.000000, -1.000000)">
<path d="M15.00325,9.01 L15.00325,5.377 L16.29625,6.694 C16.68825,7.082 17.32125,7.082 17.71325,6.694 C18.10525,6.306 18.10425,5.678 17.71325,5.291 L14.74625,2.291 C14.55825,2.105 14.30425,2 14.03725,2 C14.02625,2 14.01425,2 14.00325,2.001 C13.99225,2.002 13.98025,2 13.96925,2 C13.70325,2 13.44825,2.105 13.26025,2.291 L10.29325,5.291 C9.90225,5.679 9.90225,6.307 10.29325,6.694 C10.68425,7.081 11.31825,7.082 11.71025,6.694 L13.00425,5.377 L13.00425,9.01 C13.00425,9.557 13.44725,10 13.99425,10 L14.01225,10 C14.55925,10 15.00225,9.557 15.00225,9.01 L15.00325,9.01 Z" id="Shape" sketch:type="MSShapeGroup" transform="translate(14.003438, 6.000000) rotate(-135.000000) translate(-14.003438, -6.000000) "></path>
<path d="M7.00668756,13.377 L8.29968756,14.694 C8.69168756,15.082 9.32468756,15.082 9.71668756,14.694 C10.1086876,14.306 10.1076876,13.678 9.71668756,13.291 L6.74968756,10.291 C6.56168756,10.105 6.30768756,10 6.04068756,10 C6.02968756,10 6.01768756,10 6.00668756,10.001 C5.99568756,10.002 5.98368756,10 5.97268756,10 C5.70668756,10 5.45168756,10.105 5.26368756,10.291 L2.29668756,13.291 C1.90568756,13.679 1.90568756,14.307 2.29668756,14.694 C2.68768756,15.081 3.32168756,15.082 3.71368756,14.694 L5.00768756,13.377 L5.00768756,17.01 C5.00768756,17.557 5.45068756,18 5.99768756,18 C6.56268756,18 7.00568756,17.557 7.00568756,17.01 L7.00668756,13.377 Z" id="Shape-2" sketch:type="MSShapeGroup" transform="translate(6.006875, 14.000000) rotate(45.000000) translate(-6.006875, -14.000000) "></path>
</g>
<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">
<g transform="translate(0.000000, 2.000000)">
<path d="M7.69999981,6.30000001 C7.00064659,5.62264405 6.3,6.3 6.3,6.3 L2,10.6 L2,6 L0,6 L0,13 C0,13.6 0.4,14 1,14 L8,14 L8,12 L3.4,12 L7.7,7.7 C7.7,7.7 8.39935303,6.97735597 7.69999981,6.30000001 Z"></path>
<path d="M11,14 L11,12 L16,12 L16,2 L2,2 L2,3 L0,3 L0,1 C0,0.4 0.4,0 1,0 L17,0 C17.6,0 18,0.4 18,1 L18,13 C18,13.6 17.6,14 17,14 L11,14 Z"></path>
</g>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 637 B

13
src/sprite/icon-fast-forward.svg Executable file → Normal file
View File

@ -1,6 +1,7 @@
<?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">
<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>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<polygon points="7,6.4 0,1 0,15 7,9.6 7,15 16,8 7,1 "/>
</svg>

Before

Width:  |  Height:  |  Size: 635 B

After

Width:  |  Height:  |  Size: 534 B

View File

@ -1,14 +1,8 @@
<?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>
<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>
<path d="M14.934,6.799 C14.848,5.051 13.42,3.808 12.427,3.15 C11.957,2.838 11.333,3.028 11.102,3.558 L11.064,3.644 C10.876,4.075 11.019,4.583 11.4,4.838 C12.106,5.311 12.986,6.085 13.024,6.903 C13.056,7.579 12.471,8.371 11.361,9.173 C10.963,9.461 10.832,10.012 11.076,10.448 L11.118,10.523 C11.384,10.998 11.984,11.147 12.418,10.835 C14.158,9.584 15.004,8.229 14.934,6.798 L14.934,6.799 Z" id="Shape" sketch:type="MSShapeGroup"></path>
<path d="M17.934,6.799 C17.848,5.051 16.42,3.808 15.427,3.15 C14.957,2.838 14.333,3.028 14.102,3.558 L14.064,3.644 C13.876,4.075 14.019,4.583 14.4,4.838 C15.106,5.311 15.986,6.085 16.024,6.903 C16.056,7.579 15.471,8.371 14.361,9.173 C13.963,9.461 13.832,10.012 14.076,10.448 L14.118,10.523 C14.384,10.998 14.984,11.147 15.418,10.835 C17.158,9.584 18.004,8.229 17.934,6.798 L17.934,6.799 Z" id="Shape-2" sketch:type="MSShapeGroup" transform="translate(15.945467, 6.999165) rotate(-180.000000) translate(-15.945467, -6.999165) "></path>
</g>
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g 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"></path>
<path d="M14.934,6.799 C14.848,5.051 13.42,3.808 12.427,3.15 C11.957,2.838 11.333,3.028 11.102,3.558 L11.064,3.644 C10.876,4.075 11.019,4.583 11.4,4.838 C12.106,5.311 12.986,6.085 13.024,6.903 C13.056,7.579 12.471,8.371 11.361,9.173 C10.963,9.461 10.832,10.012 11.076,10.448 L11.118,10.523 C11.384,10.998 11.984,11.147 12.418,10.835 C14.158,9.584 15.004,8.229 14.934,6.798 L14.934,6.799 Z"></path>
<path d="M17.934,6.799 C17.848,5.051 16.42,3.808 15.427,3.15 C14.957,2.838 14.333,3.028 14.102,3.558 L14.064,3.644 C13.876,4.075 14.019,4.583 14.4,4.838 C15.106,5.311 15.986,6.085 16.024,6.903 C16.056,7.579 15.471,8.371 14.361,9.173 C13.963,9.461 13.832,10.012 14.076,10.448 L14.118,10.523 C14.384,10.998 14.984,11.147 15.418,10.835 C17.158,9.584 18.004,8.229 17.934,6.798 L17.934,6.799 Z" transform="translate(15.945467, 6.999165) rotate(-180.000000) translate(-15.945467, -6.999165) "></path>
</g>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,13 +1,8 @@
<?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>
<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)">
<path d="M0,2 L0,12 C5.24848613e-17,14 2,14 2,14 L4,14 C4,14 6,14 6,12 C6,11.786438 6,11.572876 6,11 L6,2 C6,3.17446247e-09 4,0 4,0 L2,0 C2,0 0,0 0,2 Z M2,2 L4,2 L4,12 L2,12 L2,2 Z" id="Path-1" sketch:type="MSShapeGroup"></path>
<path d="M8,2 L8,12 C8,14 10,14 10,14 L12,14 C12,14 14,14 14,12 C14,11.786438 14,11.572876 14,11 L14,2 C14,3.17446247e-09 12,0 12,0 L10,0 C10,0 8,0 8,2 Z M10,2 L12,2 L12,12 L10,12 L10,2 Z" id="Path-2" sketch:type="MSShapeGroup"></path>
</g>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<path d="M5,1H2C1.4,1,1,1.4,1,2v12c0,0.6,0.4,1,1,1h3c0.6,0,1-0.4,1-1V2C6,1.4,5.6,1,5,1z"/>
<path d="M14,1h-3c-0.6,0-1,0.4-1,1v12c0,0.6,0.4,1,1,1h3c0.6,0,1-0.4,1-1V2C15,1.4,14.6,1,14,1z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 667 B

13
src/sprite/icon-play.svg Executable file → Normal file
View File

@ -1,6 +1,7 @@
<?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">
<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>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<path d="M13.6,7.2l-10-7C2.9-0.3,2,0.2,2,1v14c0,0.8,0.9,1.3,1.6,0.8l10-7C14.1,8.4,14.1,7.6,13.6,7.2z"/>
</svg>

Before

Width:  |  Height:  |  Size: 515 B

After

Width:  |  Height:  |  Size: 582 B

16
src/sprite/icon-restart.svg Normal file → Executable file
View File

@ -1,10 +1,6 @@
<?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>
<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>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 16 16" 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">
<path d="M7.7,1.2l0.7,6.4l2.1-2.1c1.9,1.9,1.9,5.1,0,7C9.6,13.5,8.3,14,7,14c-1.3,0-2.6-0.5-3.5-1.5
c-1.9-1.9-1.9-5.1,0-7c0.6-0.6,1.4-1.1,2.3-1.3L5.2,2.3C4,2.6,2.9,3.2,2,4.1c-2.7,2.7-2.7,7.1,0,9.9c1.3,1.3,3.1,2,4.9,2
c1.9,0,3.6-0.7,4.9-2c2.7-2.7,2.7-7.1,0-9.9l2.2-2.2L7.7,1.2z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 505 B

View File

@ -1,10 +1,7 @@
<?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>
<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>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<polygon points="9,1 0,8 9,15 9,9.6 16,15 16,1 9,6.4 "/>
</svg>

Before

Width:  |  Height:  |  Size: 1021 B

After

Width:  |  Height:  |  Size: 535 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">
<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 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: 1020 B