Compare commits
204 Commits
Author | SHA1 | Date | |
---|---|---|---|
1ddb4eb60c | |||
891abd1d4a | |||
aed7db34ea | |||
90608e9e1a | |||
70b4b14984 | |||
9fbbb474db | |||
bc7a6ebdde | |||
353d920e25 | |||
6110098e97 | |||
b5092c338c | |||
cce7e9932e | |||
e6c30ec137 | |||
9bcd0434db | |||
debdf112cc | |||
533bd173b2 | |||
e05538e480 | |||
38f554b480 | |||
7d487553b2 | |||
ca8fd08e81 | |||
bc67d969cb | |||
c449fc0867 | |||
18b2d81985 | |||
533af96c4f | |||
be8b4d2735 | |||
7d077d543b | |||
9b09c9c7a0 | |||
592bcc8d7e | |||
30529ee4e4 | |||
ee2cdb2c9b | |||
1371c1341f | |||
05bf08a438 | |||
1e03aa1360 | |||
7463e31f95 | |||
83caa3f55a | |||
787465d626 | |||
33357a5992 | |||
cd2532867c | |||
8f80e4fa65 | |||
125a95e9e1 | |||
58f8cdd8c8 | |||
b164a2f3fb | |||
262c9f9e13 | |||
2c4c8c58d5 | |||
daec1baebc | |||
0674e13bab | |||
aee076dc3b | |||
66969f1a65 | |||
e964c1a298 | |||
941b4c1c20 | |||
95e39e7bd7 | |||
0785ca6024 | |||
6543fc1e5b | |||
9133247cdf | |||
bf7f6f40bd | |||
43a904917f | |||
9fe6e5ffcb | |||
a46e421bf6 | |||
20090aee03 | |||
c4ca7fe0d2 | |||
6b41752415 | |||
2bc53d12ea | |||
2f6dc5279b | |||
c8b2867b1f | |||
e56132ae3b | |||
45d4091c20 | |||
60c53a5894 | |||
032c823d3a | |||
66f724a3be | |||
bf0c81b484 | |||
aa72a17f44 | |||
8825e82634 | |||
f700d50dc8 | |||
a585270d21 | |||
7a23dda294 | |||
f3c324038f | |||
34c9bdc84c | |||
38a206892b | |||
12a737a49e | |||
e7946189c6 | |||
850720d8f2 | |||
b130a13c8a | |||
75c090e8b9 | |||
f983f0771b | |||
9f1e5a55f4 | |||
5fcfd5fa4f | |||
e135309670 | |||
e97b616811 | |||
c504ecffe6 | |||
9534db823d | |||
1ba1bec066 | |||
aad4a720dc | |||
a978348123 | |||
00cf797c20 | |||
6b0f58dab2 | |||
04cf5dfda1 | |||
fe1989dea1 | |||
5d19b43888 | |||
06ed345f29 | |||
e0cd34c996 | |||
06641d5709 | |||
a0d2d5cd24 | |||
e9cdbfb8da | |||
df64fdac9e | |||
4dbbbd04cc | |||
c9c3ee9014 | |||
67191c2a75 | |||
8ba4522b3e | |||
52eaf62b58 | |||
8d43f412ac | |||
e9ea90f527 | |||
5dc0d84300 | |||
ec8923ef08 | |||
5a414572f9 | |||
7f40307b0a | |||
a12485d10f | |||
4695bbf483 | |||
20ee77a55e | |||
78a0ac8674 | |||
e49c417e54 | |||
b39961ec49 | |||
8894b4c7b9 | |||
cdf3deb458 | |||
b5fc21239b | |||
93cc9edd9a | |||
dcd9ca3a93 | |||
c202cc1ffb | |||
093af22942 | |||
9d966e41b1 | |||
240aa7aa5f | |||
654e9cd623 | |||
73c3888309 | |||
4f0633fdc1 | |||
f41854ebe7 | |||
f398266206 | |||
4c17f98520 | |||
398815857f | |||
4c5020a396 | |||
df84ce6e90 | |||
7161378da1 | |||
224b612ae7 | |||
19d7522722 | |||
ceace2a678 | |||
d627454b2a | |||
7ccbfad6ad | |||
91f8a158d2 | |||
8925dcde01 | |||
3d1a586314 | |||
d04b278802 | |||
7345f656c1 | |||
530abac3a7 | |||
e702d9a881 | |||
b0aeccb793 | |||
43d8d748ce | |||
b43ea5c7d3 | |||
f56759222d | |||
c8b7bb570c | |||
d536b29550 | |||
ecbda018c5 | |||
5187311ff0 | |||
d9a94ac7b0 | |||
3526e322ef | |||
99cabd545d | |||
1f7f7b10de | |||
b2421b592a | |||
5322f4c62f | |||
7ab8647fc8 | |||
50c76f3d7e | |||
2f4c56176d | |||
7c5f38311b | |||
e568bc9c8d | |||
c2c4172634 | |||
73de5b5773 | |||
aa1fed0b16 | |||
22331ae9f1 | |||
8b436276bf | |||
c61db87fd6 | |||
388cb4df39 | |||
9feffb2972 | |||
acea5cdb24 | |||
55ed577b6a | |||
20b206a161 | |||
9c028a0ecc | |||
b677c3d7ad | |||
aa6bc2df2f | |||
a16579fd21 | |||
ae5a816df1 | |||
1532f2ab23 | |||
5370fc5c83 | |||
8482a1a320 | |||
f3603ac3fa | |||
44fe647a49 | |||
928a89e599 | |||
80d6d806c4 | |||
aeecf40191 | |||
f368ed572d | |||
5291bf616e | |||
a00407a475 | |||
4f47ec49b1 | |||
c48afb7880 | |||
5d3fb359b8 | |||
0227dfa7d8 | |||
b9915b4b94 | |||
f4c1313c19 | |||
7681d63876 |
1
.gitignore
vendored
@ -4,3 +4,4 @@ node_modules
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
aws.json
|
aws.json
|
||||||
docs/index.dev.html
|
docs/index.dev.html
|
||||||
|
*.mp4
|
@ -9,8 +9,7 @@
|
|||||||
"rhino" : false,
|
"rhino" : false,
|
||||||
"couch" : false,
|
"couch" : false,
|
||||||
"wsh" : true, // Windows Scripting Host.
|
"wsh" : true, // Windows Scripting Host.
|
||||||
"jquery" : true,
|
"jquery" : false,
|
||||||
"predef" : [ "jQuery", "$" ],
|
|
||||||
|
|
||||||
// Development.
|
// Development.
|
||||||
"debug" : false, // Allow debugger statements e.g. browser breakpoints.
|
"debug" : false, // Allow debugger statements e.g. browser breakpoints.
|
||||||
@ -51,6 +50,6 @@
|
|||||||
"plusplus" : false, // Prohibit use of `++` & `--`.
|
"plusplus" : false, // Prohibit use of `++` & `--`.
|
||||||
"sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`.
|
"sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`.
|
||||||
"trailing" : true, // Prohibit trailing whitespaces.
|
"trailing" : true, // Prohibit trailing whitespaces.
|
||||||
"white" : false, // Check against strict whitespace and indentation rules.
|
"white" : true, // Check against strict whitespace and indentation rules.
|
||||||
"indent" : 2 // Specify indentation spacing
|
"indent" : 4 // Specify indentation spacing
|
||||||
}
|
}
|
62
bower.json
@ -1,33 +1,33 @@
|
|||||||
{
|
{
|
||||||
"name": "plyr",
|
"name": "plyr",
|
||||||
"description": "A simple HTML5 media player using custom controls",
|
"description": "A simple HTML5 media player using custom controls",
|
||||||
"homepage": "http://plyr.io",
|
"homepage": "http://plyr.io",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Audio",
|
"Audio",
|
||||||
"Video",
|
"Video",
|
||||||
"HTML5 Audio",
|
"HTML5 Audio",
|
||||||
"HTml5 Video"
|
"HTml5 Video"
|
||||||
],
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
"Sam Potts <me@sampotts.me>"
|
"Sam Potts <me@sampotts.me>"
|
||||||
],
|
],
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"main": [
|
"main": [
|
||||||
"dist/plyr.css",
|
"dist/plyr.css",
|
||||||
"dist/plyr.js",
|
"dist/plyr.js",
|
||||||
"dist/sprite.svg",
|
"dist/sprite.svg",
|
||||||
"src/less/plyr.less",
|
"src/less/plyr.less",
|
||||||
"src/sass/plyr.sass",
|
"src/sass/plyr.scss",
|
||||||
"src/js/plyr.js"
|
"src/js/plyr.js"
|
||||||
],
|
],
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"bower_components",
|
"bower_components",
|
||||||
".gitignore"
|
".gitignore"
|
||||||
],
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/selz/plyr.git"
|
"url": "git://github.com/selz/plyr.git"
|
||||||
},
|
},
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
}
|
}
|
45
bundles.json
@ -1,25 +1,24 @@
|
|||||||
{
|
{
|
||||||
"plyr": {
|
"plyr": {
|
||||||
"less": {
|
"less": {
|
||||||
"plyr.css": ["src/less/plyr.less"]
|
"plyr.css": ["src/less/plyr.less"]
|
||||||
},
|
},
|
||||||
"sass": {
|
"sass": {
|
||||||
"plyr.css": ["src/less/plyr.sass"]
|
"plyr.css": ["src/less/plyr.sass"]
|
||||||
},
|
},
|
||||||
"js": {
|
"js": {
|
||||||
"plyr.js": ["src/js/plyr.js"]
|
"plyr.js": ["src/js/plyr.js"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"docs": {
|
"docs": {
|
||||||
"less": {
|
"less": {
|
||||||
"docs.css": ["docs/src/less/docs.less"]
|
"docs.css": ["docs/src/less/docs.less"]
|
||||||
},
|
},
|
||||||
"js": {
|
"js": {
|
||||||
"docs.js": [
|
"docs.js": [
|
||||||
"docs/src/js/lib/hogan-3.0.2.mustache.js",
|
"docs/src/js/lib/classlist.js",
|
||||||
"docs/dist/templates.js",
|
"docs/src/js/docs.js"
|
||||||
"docs/src/js/docs.js"
|
]
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
151
changelog.md
@ -1,8 +1,153 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
# 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 (Fixes #36)
|
||||||
|
|
||||||
|
## v1.0.22
|
||||||
|
- Added support() API method for checking mimetype support
|
||||||
|
- Added source() API method for setting media source(s) (Fixes #44)
|
||||||
|
- Added poster() API method for setting poster source
|
||||||
|
- Refactored captions logic for manual captions
|
||||||
|
|
||||||
## v1.0.21
|
## v1.0.21
|
||||||
- Added an <input type="range"> for seeking to improve experience (and support dragging)
|
- 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)
|
- Icons for restart and captions improved (and some IDs changed) (Fixes #49)
|
||||||
|
|
||||||
## v1.0.20
|
## v1.0.20
|
||||||
- Default controls included (Fixes #45)
|
- Default controls included (Fixes #45)
|
||||||
@ -11,7 +156,7 @@
|
|||||||
- License changed to MIT
|
- License changed to MIT
|
||||||
|
|
||||||
## v1.0.19
|
## v1.0.19
|
||||||
- Fixed firefox fullscreen issue (#38)
|
- Fixed firefox fullscreen issue (Fixes #38)
|
||||||
|
|
||||||
## v1.0.18
|
## v1.0.18
|
||||||
- Added CDN references
|
- Added CDN references
|
||||||
|
64
controls.md
@ -1,10 +1,36 @@
|
|||||||
# Controls HTML
|
# Controls
|
||||||
|
|
||||||
This is the markup that is rendered for the Plyr controls. You can use the default controls or provide a customized version of markup based on your needs.
|
This is the markup that is rendered for the Plyr controls. You can use the default controls or provide a customized version of markup based on your needs.
|
||||||
|
|
||||||
The demo Plyr setup uses a Hogan template. This purely to allow for localization at a later date. Check out `controls.html` in `/src/templates` to get an idea of how the default html is structured. Alternatively check out the `plyr.js` source.
|
## Internationalization using default controls
|
||||||
|
|
||||||
## Requirements
|
You can provide an `i18n` object as one of your options when initialising the plugin which we be used when rendering the controls.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
i18n: {
|
||||||
|
restart: "Restart",
|
||||||
|
rewind: "Rewind {seektime} secs",
|
||||||
|
play: "Play",
|
||||||
|
pause: "Pause",
|
||||||
|
forward: "Forward {seektime} secs",
|
||||||
|
played: "played",
|
||||||
|
buffered: "buffered",
|
||||||
|
currentTime: "Current time",
|
||||||
|
duration: "Duration",
|
||||||
|
volume: "Volume",
|
||||||
|
toggleMute: "Toggle Mute",
|
||||||
|
toggleCaptions: "Toggle Captions",
|
||||||
|
toggleFullscreen: "Toggle Fullscreen"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: `{seektime}` will be replaced with your configured seek time or the default. For example "Forward {seektime} secs" would render as "Forward 10 secs".
|
||||||
|
|
||||||
|
## Using custom HTML
|
||||||
|
|
||||||
|
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.
|
The classes and data attributes used in your template should match the `selectors` option.
|
||||||
|
|
||||||
@ -13,11 +39,11 @@ You need to add several placeholders to your html template that are replaced whe
|
|||||||
- `{id}` - the dynamically generated ID for the player (for form controls)
|
- `{id}` - the dynamically generated ID for the player (for form controls)
|
||||||
- `{seektime}` - the seek time specified in options for fast forward and rewind
|
- `{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
|
```javascript
|
||||||
["<div class='player-controls'>",
|
["<div class='player-controls'>",
|
||||||
@ -31,14 +57,14 @@ This is the default `html` option from `plyr.js`.
|
|||||||
"<span>0</span>% buffered",
|
"<span>0</span>% buffered",
|
||||||
"</progress>",
|
"</progress>",
|
||||||
"</div>",
|
"</div>",
|
||||||
"<span class='player-controls-playback'>",
|
"<span class='player-controls-left'>",
|
||||||
"<button type='button' data-player='restart'>",
|
"<button type='button' data-player='restart'>",
|
||||||
"<svg><use xlink:href='#icon-restart'></use></svg>",
|
"<svg><use xlink:href='#icon-restart'></use></svg>",
|
||||||
"<span class='sr-only'>Restart</span>",
|
"<span class='sr-only'>Restart</span>",
|
||||||
"</button>",
|
"</button>",
|
||||||
"<button type='button' data-player='rewind'>",
|
"<button type='button' data-player='rewind'>",
|
||||||
"<svg><use xlink:href='#icon-rewind'></use></svg>",
|
"<svg><use xlink:href='#icon-rewind'></use></svg>",
|
||||||
"<span class='sr-only'>Rewind {seektime} seconds</span>",
|
"<span class='sr-only'>Rewind {seektime} secs</span>",
|
||||||
"</button>",
|
"</button>",
|
||||||
"<button type='button' data-player='play'>",
|
"<button type='button' data-player='play'>",
|
||||||
"<svg><use xlink:href='#icon-play'></use></svg>",
|
"<svg><use xlink:href='#icon-play'></use></svg>",
|
||||||
@ -50,32 +76,34 @@ This is the default `html` option from `plyr.js`.
|
|||||||
"</button>",
|
"</button>",
|
||||||
"<button type='button' data-player='fast-forward'>",
|
"<button type='button' data-player='fast-forward'>",
|
||||||
"<svg><use xlink:href='#icon-fast-forward'></use></svg>",
|
"<svg><use xlink:href='#icon-fast-forward'></use></svg>",
|
||||||
"<span class='sr-only'>Fast forward {seektime} seconds</span>",
|
"<span class='sr-only'>Forward {seektime} secs</span>",
|
||||||
"</button>",
|
"</button>",
|
||||||
"<span class='player-time'>",
|
"<span class='player-time'>",
|
||||||
"<span class='sr-only'>Time</span>",
|
"<span class='sr-only'>Current time</span>",
|
||||||
|
"<span class='player-current-time'>00:00</span>",
|
||||||
|
"</span>",
|
||||||
|
"<span class='player-time'>",
|
||||||
|
"<span class='sr-only'>Duration</span>",
|
||||||
"<span class='player-duration'>00:00</span>",
|
"<span class='player-duration'>00:00</span>",
|
||||||
"</span>",
|
"</span>",
|
||||||
"</span>",
|
"</span>",
|
||||||
"<span class='player-controls-sound'>",
|
"<span class='player-controls-right'>",
|
||||||
"<input class='inverted sr-only' id='mute{id}' type='checkbox' data-player='mute'>",
|
"<button type='button' data-player='mute'>",
|
||||||
"<label id='mute{id}' for='mute{id}'>",
|
|
||||||
"<svg class='icon-muted'><use xlink:href='#icon-muted'></use></svg>",
|
"<svg class='icon-muted'><use xlink:href='#icon-muted'></use></svg>",
|
||||||
"<svg><use xlink:href='#icon-volume'></use></svg>",
|
"<svg><use xlink:href='#icon-volume'></use></svg>",
|
||||||
"<span class='sr-only'>Toggle Mute</span>",
|
"<span class='sr-only'>Toggle Mute</span>",
|
||||||
"</label>",
|
"</button>",
|
||||||
"<label for='volume{id}' class='sr-only'>Volume</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 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'>",
|
"<button type='button' data-player='captions'>",
|
||||||
"<label for='captions{id}'>",
|
|
||||||
"<svg class='icon-captions-on'><use xlink:href='#icon-captions-on'></use></svg>",
|
"<svg class='icon-captions-on'><use xlink:href='#icon-captions-on'></use></svg>",
|
||||||
"<svg><use xlink:href='#icon-captions-off'></use></svg>",
|
"<svg><use xlink:href='#icon-captions-off'></use></svg>",
|
||||||
"<span class='sr-only'>Toggle Captions</span>",
|
"<span class='sr-only'>Toggle Captions</span>",
|
||||||
"</label>",
|
"</button>",
|
||||||
"<button type='button' data-player='fullscreen'>",
|
"<button type='button' data-player='fullscreen'>",
|
||||||
"<svg class='icon-exit-fullscreen'><use xlink:href='#icon-exit-fullscreen'></use></svg>",
|
"<svg class='icon-exit-fullscreen'><use xlink:href='#icon-exit-fullscreen'></use></svg>",
|
||||||
"<svg><use xlink:href='#icon-enter-fullscreen'></use></svg>",
|
"<svg><use xlink:href='#icon-enter-fullscreen'></use></svg>",
|
||||||
"<span class='sr-only'>Toggle fullscreen</span>",
|
"<span class='sr-only'>Toggle Fullscreen</span>",
|
||||||
"</button>",
|
"</button>",
|
||||||
"</span>",
|
"</span>",
|
||||||
"</div>"].join("\n");
|
"</div>"].join("\n");
|
||||||
|
2
dist/plyr.css
vendored
2
dist/plyr.js
vendored
2
dist/sprite.svg
vendored
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 4.3 KiB |
2
docs/dist/docs.css
vendored
2
docs/dist/docs.js
vendored
1
docs/dist/docs.svg
vendored
Normal 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 |
2
docs/dist/templates.js
vendored
@ -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: { }});
|
|
@ -1,18 +1,18 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en" class="error">
|
<html lang="en" class="error">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Doh. Looks like something went wrong.</title>
|
<title>Doh. Looks like something went wrong.</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<!-- Docs styles -->
|
<!-- Docs styles -->
|
||||||
<link rel="stylesheet" href="//cdn.plyr.io/1.0.21/docs.css">
|
<link rel="stylesheet" href="dist/docs.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main>
|
<main>
|
||||||
<h1>Doh.</h1>
|
<h1>Doh.</h1>
|
||||||
<p>Looks like something went wrong.</p>
|
<p>Looks like something went wrong.</p>
|
||||||
<a href="http://plyr.io" class="btn">Back to plyr.io</a>
|
<a href="http://plyr.io" class="btn">Back to plyr.io</a>
|
||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
178
docs/index.html
@ -1,79 +1,127 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Plyr - A simple HTML5 media player</title>
|
<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="description" content="A simple HTML5 media player with custom controls and WebVTT captions.">
|
||||||
<meta name="author" content="Sam Potts">
|
<meta name="author" content="Sam Potts">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<!-- Styles -->
|
<!-- Styles -->
|
||||||
<link rel="stylesheet" href="//cdn.plyr.io/1.0.21/plyr.css">
|
<link rel="stylesheet" href="../dist/plyr.css">
|
||||||
|
|
||||||
<!-- Docs styles -->
|
<!-- Docs styles -->
|
||||||
<link rel="stylesheet" href="//cdn.plyr.io/1.0.21/docs.css">
|
<link rel="stylesheet" href="dist/docs.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<h1>Plyr</h1>
|
<h1>Plyr</h1>
|
||||||
<p>A simple HTML5 media player with custom controls and WebVTT captions.</p>
|
<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>
|
||||||
<a href="https://github.com/selz/plyr" target="_blank" class="btn">Download on GitHub</a>
|
<nav>
|
||||||
</header>
|
<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>
|
<main role="main" id="main">
|
||||||
<section class="example-video">
|
<nav class="btn__bar">
|
||||||
<div class="player">
|
<ul>
|
||||||
<video poster="//cdn.selz.com/plyr/1.0/poster.jpg" controls crossorigin>
|
<li class="active">
|
||||||
<!-- Video files -->
|
<button type="button" class="btn" data-source="video">Video</button>
|
||||||
<source src="//cdn.selz.com/plyr/1.0/movie.mp4" type="video/mp4">
|
</li>
|
||||||
<source src="//cdn.selz.com/plyr/1.0/movie.webm" type="video/webm">
|
<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">
|
||||||
|
|
||||||
<!-- Text track file -->
|
<!-- Text track file -->
|
||||||
<track kind="captions" label="English" srclang="en" src="//cdn.selz.com/plyr/1.0/movie_en_captions.vtt" default>
|
<track kind="captions" label="English" srclang="en" src="https://cdn.selz.com/plyr/1.0/example_captions_en.vtt" default>
|
||||||
|
|
||||||
<!-- Fallback for browsers that don't support the <video> element -->
|
<!-- Fallback for browsers that don't support the <video> element -->
|
||||||
<div>
|
<a href="https://cdn.selz.com/plyr/1.0/movie.mp4">Download</a>
|
||||||
<a href="//cdn.selz.com/plyr/1.0/movie.mp4">Download</a>
|
</video>
|
||||||
</div>
|
</div>
|
||||||
</video>
|
|
||||||
</div>
|
|
||||||
<small>Big Buck Bunny. More info can be found at <a href="https://peach.blender.org" target="_blank">peach.blender.org</a>.</small>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="example-audio">
|
<ul>
|
||||||
<div class="player">
|
<li class="plyr__cite plyr__cite--video"><small><a href="http://viewfromabluemoon.com/" target="_blank">View From A Blue Moon</a> © Brainfarm</small></li>
|
||||||
<audio controls>
|
<li class="plyr__cite plyr__cite--audio"><small><a href="http://www.kishibashi.com/" target="_blank">Kishi Bashi – “It All Began With A Burst”</a> © Kishi Bashi</small></li>
|
||||||
<!-- Audio files -->
|
<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>
|
||||||
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3" type="audio/mp3">
|
<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>
|
||||||
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.ogg" type="audio/ogg">
|
</ul>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
<!-- Fallback for browsers that don't support the <audio> element -->
|
<!-- Load SVG defs -->
|
||||||
<div>
|
<!-- You should bundle all SVG/Icons into one file using a build tool such as gulp and svg store -->
|
||||||
<a href="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3">Download</a>
|
<script>
|
||||||
</div>
|
(function() {
|
||||||
</audio>
|
[
|
||||||
</div>
|
'../dist/sprite.svg',
|
||||||
<small>"96" by Logistics, which can be purchased from <a href="https://www.hospitalrecords.com/shop/artist/logistics" target="_blank">Hospital Records</a>.</small>
|
'dist/docs.svg'
|
||||||
</section>
|
]
|
||||||
</main>
|
.forEach(function(u) {
|
||||||
|
var x = new XMLHttpRequest(),
|
||||||
|
b = document.body;
|
||||||
|
|
||||||
<footer>
|
// Check for CORS support
|
||||||
<p>Used by …</p>
|
// If you're loading from same domain, you can remove the whole if/else statement
|
||||||
<a href="https://selz.com" target="_blank" class="logo">
|
// XHR for Chrome/Firefox/Opera/Safari/IE10+
|
||||||
<img src="https://d33i624pw6jj68.cloudfront.net/static/img/logos/selz.svg" alt="Selz">
|
if ('withCredentials' in x) {
|
||||||
</a>
|
x.open('GET', u, true);
|
||||||
</footer>
|
}
|
||||||
|
// XDomainRequest for IE8 & IE9
|
||||||
|
else if (typeof XDomainRequest == 'function') {
|
||||||
|
x = new XDomainRequest();
|
||||||
|
x.open('GET', u);
|
||||||
|
}
|
||||||
|
else { return; }
|
||||||
|
|
||||||
<!-- Load SVG defs -->
|
// Inject hidden div with sprite on load
|
||||||
<!-- You should bundle all SVG/Icons into one file using a build tool such as gulp and svg store -->
|
x.onload = function() {
|
||||||
<script>
|
var c = document.createElement('div');
|
||||||
(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.21/sprite.svg");
|
c.setAttribute('hidden', '');
|
||||||
</script>
|
c.innerHTML = x.responseText;
|
||||||
|
b.insertBefore(c, b.childNodes[0]);
|
||||||
|
}
|
||||||
|
|
||||||
<!-- Plyr core script -->
|
// Timeout for IE9
|
||||||
<script src="//cdn.plyr.io/1.0.21/plyr.js"></script>
|
setTimeout(function () {
|
||||||
|
x.send();
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
<!-- Docs script -->
|
<!-- Plyr core script -->
|
||||||
<script src="//cdn.plyr.io/1.0.21/docs.js"></script>
|
<script src="../dist/plyr.js"></script>
|
||||||
</body>
|
|
||||||
|
<!-- Shr core script -->
|
||||||
|
<script src="https://cdn.shr.one/0.1.9/shr.js"></script>
|
||||||
|
|
||||||
|
<!-- Docs script -->
|
||||||
|
<script src="dist/docs.js"></script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
BIN
docs/poster.jpg
Normal file
After Width: | Height: | Size: 171 KiB |
@ -2,25 +2,132 @@
|
|||||||
// Docs example
|
// Docs example
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
/*global plyr, templates */
|
/*global plyr, shr*/
|
||||||
|
|
||||||
// Setup the player
|
// Setup the player
|
||||||
plyr.setup({
|
plyr.setup('.js-media-player', {
|
||||||
debug: true,
|
debug: true,
|
||||||
title: "Video demo",
|
title: 'Video demo',
|
||||||
html: templates.controls.render({}),
|
tooltips: true,
|
||||||
captions: {
|
captions: {
|
||||||
defaultActive: true
|
defaultActive: true
|
||||||
|
},
|
||||||
|
onSetup: function() {
|
||||||
|
console.log('✓ Setup done');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Setup shr
|
||||||
|
shr.setup({
|
||||||
|
count: {
|
||||||
|
classname: 'btn__count'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// General functions
|
||||||
|
(function() {
|
||||||
|
var buttons = document.querySelectorAll('[data-source]');
|
||||||
|
|
||||||
|
// Bind to each button
|
||||||
|
for (var i = buttons.length - 1; i >= 0; i--) {
|
||||||
|
buttons[i].addEventListener('click', newSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
var trigger = this,
|
||||||
|
type = trigger.getAttribute('data-source'),
|
||||||
|
player = document.querySelector('.js-media-player').plyr;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case '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.0/example_captions_en.vtt',
|
||||||
|
default: true
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'audio':
|
||||||
|
player.source({
|
||||||
|
type: 'audio',
|
||||||
|
title: 'Kishi Bashi – “It All Began With A Burst”',
|
||||||
|
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 'youtube':
|
||||||
|
player.source({
|
||||||
|
type: 'video',
|
||||||
|
title: 'View From A Blue Moon',
|
||||||
|
sources: [{
|
||||||
|
src: 'bTqVqk7FSmY',
|
||||||
|
type: 'youtube'
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'vimeo':
|
||||||
|
player.source({
|
||||||
|
type: 'video',
|
||||||
|
title: 'View From A Blue Moon',
|
||||||
|
sources: [{
|
||||||
|
src: '143418951',
|
||||||
|
type: 'vimeo'
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var x = buttons.length - 1; x >= 0; x--) {
|
||||||
|
toggleClass(buttons[x].parentElement, 'active', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleClass((event.target || event.srcElement).parentElement, 'active', true);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
// Google analytics
|
// Google analytics
|
||||||
// For demo site (http://[www.]plyr.io) only
|
// 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(){
|
(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),
|
(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)
|
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");
|
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||||
ga("create", "UA-40881672-11", "auto");
|
ga('create', 'UA-40881672-11', 'auto');
|
||||||
ga("send", "pageview");
|
ga('send', 'pageview');
|
||||||
}
|
}
|
237
docs/src/js/lib/classlist.js
Normal 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;
|
||||||
|
}());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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, '&')
|
|
||||||
.replace(rLt, '<')
|
|
||||||
.replace(rGt, '>')
|
|
||||||
.replace(rApos, ''')
|
|
||||||
.replace(rQuot, '"') :
|
|
||||||
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);
|
|
52
docs/src/less/components/base.less
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// ==========================================================================
|
||||||
|
// Base layout
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
// BORDER-BOX ALL THE THINGS!
|
||||||
|
// http://paulirish.com/2012/box-sizing-border-box-ftw/
|
||||||
|
*, *::after, *::before {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hidden
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
font-size: 100%;
|
||||||
|
background: linear-gradient(#fff, @body-background) fixed;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: "Avenir", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
text-align: center;
|
||||||
|
color: @gray;
|
||||||
|
.font-smoothing(on);
|
||||||
|
padding: 0 (@padding-base / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Header
|
||||||
|
header {
|
||||||
|
padding: @padding-base;
|
||||||
|
margin-bottom: @padding-base;
|
||||||
|
|
||||||
|
p {
|
||||||
|
.font-size(18);
|
||||||
|
}
|
||||||
|
@media (min-width: @screen-sm) {
|
||||||
|
padding-top: (@padding-base * 3);
|
||||||
|
padding-bottom: (@padding-base * 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sections
|
||||||
|
section {
|
||||||
|
padding-bottom: @padding-base;
|
||||||
|
|
||||||
|
@media (min-width: @screen-sm) {
|
||||||
|
padding-bottom: (@padding-base * 2);
|
||||||
|
}
|
||||||
|
}
|
172
docs/src/less/components/buttons.less
Normal 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;
|
||||||
|
font-weight: 600;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
.btn {
|
||||||
|
padding: (@padding-base / 2) ((@padding-base / 2) + 2);
|
||||||
|
background: linear-gradient(lighten(@body-background, 2%), darken(@body-background, 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%);
|
||||||
|
}
|
||||||
|
}
|
19
docs/src/less/components/error.less
Normal 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;
|
||||||
|
}
|
72
docs/src/less/components/examples.less
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// ==========================================================================
|
||||||
|
// Examples
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
section {
|
||||||
|
margin: 0 auto @padding-base;
|
||||||
|
max-width: @example-width-video;
|
||||||
|
}
|
||||||
|
|
||||||
|
video,
|
||||||
|
.plyr__video-embed {
|
||||||
|
border-radius: @border-radius-base;
|
||||||
|
max-width: 100%;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.plyr__video-embed {
|
||||||
|
-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example players
|
||||||
|
.plyr {
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
&__controls {
|
||||||
|
border-radius: 0 0 @border-radius-base @border-radius-base;
|
||||||
|
}
|
||||||
|
video,
|
||||||
|
.plyr__video-embed {
|
||||||
|
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||||
|
}
|
||||||
|
&--fullscreen,
|
||||||
|
&--fullscreen-active {
|
||||||
|
max-width: none;
|
||||||
|
|
||||||
|
.plyr-controls,
|
||||||
|
video,
|
||||||
|
iframe {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
iframe {
|
||||||
|
-webkit-mask-image: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.plyr--audio {
|
||||||
|
max-width: @example-width-audio;
|
||||||
|
|
||||||
|
.plyr__controls {
|
||||||
|
border-radius: @border-radius-base;
|
||||||
|
}
|
||||||
|
.plyr__progress {
|
||||||
|
border-radius: @border-radius-base @border-radius-base 0 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style full supported player
|
||||||
|
.plyr__cite {
|
||||||
|
display: none;
|
||||||
|
margin-top: @padding-base;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-right: (@padding-base / 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.plyr--video ~ ul .plyr__cite--video,
|
||||||
|
.plyr--audio ~ ul .plyr__cite--audio,
|
||||||
|
.plyr--youtube ~ ul .plyr__cite--youtube,
|
||||||
|
.plyr--vimeo ~ ul .plyr__cite--vimeo {
|
||||||
|
display: block;
|
||||||
|
}
|
26
docs/src/less/components/icons.less
Normal 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);
|
||||||
|
}
|
63
docs/src/less/components/type.less
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// ==========================================================================
|
||||||
|
// Typography
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
// Headings
|
||||||
|
h1,
|
||||||
|
h2 {
|
||||||
|
letter-spacing: -.025em;
|
||||||
|
color: #2E3C44;
|
||||||
|
margin: 0 0 (@padding-base / 2);
|
||||||
|
line-height: 1.2;
|
||||||
|
.font-smoothing();
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
.font-size(@font-size-h1);
|
||||||
|
color: #3498DB;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
@ -2,163 +2,25 @@
|
|||||||
// HTML5 Video Player Demo Page
|
// HTML5 Video Player Demo Page
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
// Reset
|
// CSS Reset
|
||||||
@import "lib/normalize.less";
|
@import "lib/normalize.less";
|
||||||
|
|
||||||
// Mixins
|
// Mixins
|
||||||
@import "lib/mixins.less";
|
@import "lib/mixins.less";
|
||||||
// Fonts - docs only!
|
|
||||||
@import "lib/fontface.less";
|
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
// ---------------------------------------
|
@import "variables.less";
|
||||||
// Colors
|
|
||||||
@blue: #3498DB;
|
|
||||||
@gray-dark: #343f4a;
|
|
||||||
@gray: #565d64;
|
|
||||||
@gray-light: #cbd0d3;
|
|
||||||
|
|
||||||
// Elements
|
// Animation
|
||||||
@link-color: @blue;
|
@import "lib/animation.less";
|
||||||
@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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type
|
// Type
|
||||||
h1,
|
@import "lib/fontface.less";
|
||||||
h2 {
|
@import "components/type.less";
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Header
|
// Components
|
||||||
header {
|
@import "components/base.less";
|
||||||
padding: @padding-base;
|
@import "components/icons.less";
|
||||||
margin-bottom: @padding-base;
|
@import "components/buttons.less";
|
||||||
|
@import "components/error.less";
|
||||||
p {
|
@import "components/examples.less";
|
||||||
.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
9
docs/src/less/lib/animation.less
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// ==========================================================================
|
||||||
|
// Animations
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
// Fade
|
||||||
|
@keyframes fade-in {
|
||||||
|
0% { opacity: 0 }
|
||||||
|
100% { opacity: 1 }
|
||||||
|
}
|
@ -1,16 +1,18 @@
|
|||||||
|
// ==========================================================================
|
||||||
|
// Fonts
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Avenir";
|
font-family: "Avenir";
|
||||||
src: url("//cdn.plyr.io/fonts/avenir-medium.woff2") format("woff2"),
|
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.woff") format("woff");
|
||||||
url("//cdn.plyr.io/fonts/avenir-medium.ttf") format("truetype");
|
font-style: normal;
|
||||||
font-style: normal;
|
font-weight: 400;
|
||||||
font-weight: 400;
|
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Avenir";
|
font-family: "Avenir";
|
||||||
src: url("//cdn.plyr.io/fonts/avenir-bold.woff2") format("woff2"),
|
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.woff") format("woff");
|
||||||
url("//cdn.plyr.io/fonts/avenir-bold.ttf") format("truetype");
|
font-style: normal;
|
||||||
font-style: normal;
|
font-weight: 600;
|
||||||
font-weight: 600;
|
|
||||||
}
|
}
|
@ -5,38 +5,37 @@
|
|||||||
// Contain floats: nicolasgallagher.com/micro-clearfix-hack/
|
// Contain floats: nicolasgallagher.com/micro-clearfix-hack/
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
.clearfix() {
|
.clearfix() {
|
||||||
zoom: 1;
|
zoom: 1;
|
||||||
&:before,
|
&:before,
|
||||||
&:after { content: ""; display: table; }
|
&:after { content: ""; display: table; }
|
||||||
&:after { clear: both; }
|
&:after { clear: both; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Webkit-style focus
|
// Webkit-style focus
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
.tab-focus() {
|
.tab-focus() {
|
||||||
// Default
|
// Default
|
||||||
outline: thin dotted @gray-dark;
|
outline: thin dotted @gray-dark;
|
||||||
// Webkit
|
// Webkit
|
||||||
//outline: 5px auto -webkit-focus-ring-color;
|
outline-offset: 1px;
|
||||||
outline-offset: 1px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use rems for font sizing
|
// Use rems for font sizing
|
||||||
// Leave <body> at 100%/16px
|
// Leave <body> at 100%/16px
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
.font-size(@font-size: 16){
|
.font-size(@font-size: 16){
|
||||||
@rem: round((@font-size / 16), 1);
|
@rem: round((@font-size / 16), 3);
|
||||||
font-size: (@font-size * 1px);
|
font-size: (@font-size * 1px);
|
||||||
font-size: ~"@{rem}rem";
|
font-size: ~"@{rem}rem";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Font smoothing
|
// Font smoothing
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
.font-smoothing(@mode: on) when (@mode = on) {
|
.font-smoothing(@mode: on) when (@mode = on) {
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
.font-smoothing(@mode: on) when (@mode = off) {
|
.font-smoothing(@mode: on) when (@mode = off) {
|
||||||
-moz-osx-font-smoothing: auto;
|
-moz-osx-font-smoothing: auto;
|
||||||
-webkit-font-smoothing: subpixel-antialiased;
|
-webkit-font-smoothing: subpixel-antialiased;
|
||||||
}
|
}
|
43
docs/src/less/variables.less
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// ==========================================================================
|
||||||
|
// Variables
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
// Colors
|
||||||
|
@blue: #3498db;
|
||||||
|
@gray-dark: #343f4a;
|
||||||
|
@gray: #55646b;
|
||||||
|
@gray-light: #cbd0d3;
|
||||||
|
@gray-lighter: #dbe3e8;
|
||||||
|
@off-white: #f2f5f7;
|
||||||
|
|
||||||
|
// Brands
|
||||||
|
@color-twitter: #4BAAF4;
|
||||||
|
@color-youtube: #cc181e;
|
||||||
|
@color-vimeo: #19b7ed;
|
||||||
|
|
||||||
|
// Base
|
||||||
|
@body-background: @off-white;
|
||||||
|
|
||||||
|
// Type
|
||||||
|
@font-size-base: 16;
|
||||||
|
@font-size-small: 14;
|
||||||
|
@font-size-h1: 64;
|
||||||
|
|
||||||
|
// Elements
|
||||||
|
@link-color: @blue;
|
||||||
|
@padding-base: 20px;
|
||||||
|
@arrow-size: 8px;
|
||||||
|
|
||||||
|
// Icons
|
||||||
|
@icon-size: 18px;
|
||||||
|
|
||||||
|
// Breakpoints
|
||||||
|
@screen-sm: 480px;
|
||||||
|
@screen-md: 768px;
|
||||||
|
|
||||||
|
// Radii
|
||||||
|
@border-radius-base: 4px;
|
||||||
|
|
||||||
|
// Examples
|
||||||
|
@example-width-audio: 520px;
|
||||||
|
@example-width-video: 1200px;
|
12
docs/src/sprite/icon-github.svg
Executable 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 |
11
docs/src/sprite/icon-twitter.svg
Executable 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
@ -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 |
9
docs/src/sprite/icon-youtube.svg
Executable 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 |
@ -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>
|
|
378
gulpfile.js
@ -4,59 +4,60 @@
|
|||||||
/*global require, __dirname*/
|
/*global require, __dirname*/
|
||||||
/*jshint -W079 */
|
/*jshint -W079 */
|
||||||
|
|
||||||
var fs = require("fs"),
|
var fs = require("fs"),
|
||||||
path = require("path"),
|
path = require("path"),
|
||||||
gulp = require("gulp"),
|
gulp = require("gulp"),
|
||||||
gutil = require("gulp-util"),
|
gutil = require("gulp-util"),
|
||||||
concat = require("gulp-concat"),
|
concat = require("gulp-concat"),
|
||||||
uglify = require("gulp-uglify"),
|
uglify = require("gulp-uglify"),
|
||||||
less = require("gulp-less"),
|
less = require("gulp-less"),
|
||||||
sass = require("gulp-sass"),
|
sass = require("gulp-sass"),
|
||||||
minify = require("gulp-minify-css"),
|
minify = require("gulp-minify-css"),
|
||||||
run = require("run-sequence"),
|
run = require("run-sequence"),
|
||||||
prefix = require("gulp-autoprefixer"),
|
prefix = require("gulp-autoprefixer"),
|
||||||
svgstore = require("gulp-svgstore"),
|
svgstore = require("gulp-svgstore"),
|
||||||
svgmin = require("gulp-svgmin"),
|
svgmin = require("gulp-svgmin"),
|
||||||
hogan = require("gulp-hogan-compile"),
|
rename = require("gulp-rename"),
|
||||||
rename = require("gulp-rename"),
|
s3 = require("gulp-s3"),
|
||||||
s3 = require("gulp-s3"),
|
gzip = require("gulp-gzip"),
|
||||||
gzip = require("gulp-gzip"),
|
replace = require("gulp-replace"),
|
||||||
replace = require("gulp-replace"),
|
open = require("gulp-open"),
|
||||||
open = require("gulp-open");
|
size = require("gulp-size");
|
||||||
|
|
||||||
var root = __dirname,
|
var root = __dirname,
|
||||||
paths = {
|
paths = {
|
||||||
plyr: {
|
plyr: {
|
||||||
// Source paths
|
// Source paths
|
||||||
src: {
|
src: {
|
||||||
less: path.join(root, "src/less/**/*"),
|
less: path.join(root, "src/less/**/*"),
|
||||||
sass: path.join(root, "src/sass/**/*"),
|
sass: path.join(root, "src/sass/**/*"),
|
||||||
js: path.join(root, "src/js/**/*"),
|
js: path.join(root, "src/js/**/*"),
|
||||||
sprite: path.join(root, "src/sprite/*.svg")
|
sprite: path.join(root, "src/sprite/*.svg")
|
||||||
},
|
},
|
||||||
// Output paths
|
// Output paths
|
||||||
output: path.join(root, "dist/")
|
output: path.join(root, "dist/")
|
||||||
},
|
},
|
||||||
docs: {
|
docs: {
|
||||||
// Source paths
|
// Source paths
|
||||||
src: {
|
src: {
|
||||||
less: path.join(root, "docs/src/less/**/*"),
|
less: path.join(root, "docs/src/less/**/*"),
|
||||||
js: path.join(root, "docs/src/js/**/*"),
|
js: path.join(root, "docs/src/js/**/*"),
|
||||||
templates: path.join(root, "docs/src/templates/*.html")
|
sprite: path.join(root, "docs/src/sprite/**/*")
|
||||||
},
|
},
|
||||||
// Output paths
|
// Output paths
|
||||||
output: path.join(root, "docs/dist/"),
|
output: path.join(root, "docs/dist/"),
|
||||||
// Docs
|
// Docs
|
||||||
root: path.join(root, "docs/")
|
root: path.join(root, "docs/")
|
||||||
},
|
},
|
||||||
upload: [path.join(root, "dist/**"), path.join(root, "docs/dist/**")]
|
upload: [path.join(root, "dist/**"), path.join(root, "docs/dist/**")]
|
||||||
},
|
},
|
||||||
|
|
||||||
// Task arrays
|
// Task arrays
|
||||||
tasks = {
|
tasks = {
|
||||||
less: [],
|
less: [],
|
||||||
sass: [],
|
sass: [],
|
||||||
js: []
|
js: [],
|
||||||
|
sprite: []
|
||||||
},
|
},
|
||||||
|
|
||||||
// Fetch bundles from JSON
|
// Fetch bundles from JSON
|
||||||
@ -65,131 +66,126 @@ package = loadJSON(path.join(root, "package.json"));
|
|||||||
|
|
||||||
// Load json
|
// Load json
|
||||||
function loadJSON(path) {
|
function loadJSON(path) {
|
||||||
return JSON.parse(fs.readFileSync(path));
|
try {
|
||||||
|
return JSON.parse(fs.readFileSync(path));
|
||||||
|
}
|
||||||
|
catch(err) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var build = {
|
var build = {
|
||||||
js: function (files, bundle) {
|
js: function (files, bundle) {
|
||||||
for (var key in files) {
|
for (var key in files) {
|
||||||
(function(key) {
|
(function(key) {
|
||||||
var name = "js-" + key;
|
var name = "js-" + key;
|
||||||
tasks.js.push(name);
|
tasks.js.push(name);
|
||||||
|
|
||||||
gulp.task(name, function () {
|
gulp.task(name, function () {
|
||||||
return gulp
|
return gulp
|
||||||
.src(bundles[bundle].js[key])
|
.src(bundles[bundle].js[key])
|
||||||
.pipe(concat(key))
|
.pipe(concat(key))
|
||||||
.pipe(uglify())
|
.pipe(uglify())
|
||||||
.pipe(gulp.dest(paths[bundle].output));
|
.pipe(gulp.dest(paths[bundle].output));
|
||||||
});
|
});
|
||||||
})(key);
|
})(key);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
less: function(files, bundle) {
|
less: function(files, bundle) {
|
||||||
for (var key in files) {
|
for (var key in files) {
|
||||||
(function (key) {
|
(function (key) {
|
||||||
var name = "less-" + key;
|
var name = "less-" + key;
|
||||||
tasks.less.push(name);
|
tasks.less.push(name);
|
||||||
|
|
||||||
gulp.task(name, function () {
|
gulp.task(name, function () {
|
||||||
return gulp
|
return gulp
|
||||||
.src(bundles[bundle].less[key])
|
.src(bundles[bundle].less[key])
|
||||||
.pipe(less())
|
.pipe(less())
|
||||||
.on("error", gutil.log)
|
.on("error", gutil.log)
|
||||||
.pipe(concat(key))
|
.pipe(concat(key))
|
||||||
.pipe(prefix(["last 2 versions"], { cascade: true }))
|
.pipe(prefix(["last 2 versions"], { cascade: true }))
|
||||||
.pipe(minify())
|
.pipe(minify())
|
||||||
.pipe(gulp.dest(paths[bundle].output));
|
.pipe(gulp.dest(paths[bundle].output));
|
||||||
});
|
});
|
||||||
})(key);
|
})(key);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sass: function(files, bundle) {
|
sass: function(files, bundle) {
|
||||||
for (var key in files) {
|
for (var key in files) {
|
||||||
(function (key) {
|
(function (key) {
|
||||||
var name = "sass-" + key;
|
var name = "sass-" + key;
|
||||||
tasks.sass.push(name);
|
tasks.sass.push(name);
|
||||||
|
|
||||||
gulp.task(name, function () {
|
gulp.task(name, function () {
|
||||||
return gulp
|
return gulp
|
||||||
.src(bundles[bundle].sass[key])
|
.src(bundles[bundle].sass[key])
|
||||||
.pipe(sass())
|
.pipe(sass())
|
||||||
.on("error", gutil.log)
|
.on("error", gutil.log)
|
||||||
.pipe(concat(key))
|
.pipe(concat(key))
|
||||||
.pipe(prefix(["last 2 versions"], { cascade: true }))
|
.pipe(prefix(["last 2 versions"], { cascade: true }))
|
||||||
.pipe(minify())
|
.pipe(minify())
|
||||||
.pipe(gulp.dest(paths[bundle].output));
|
.pipe(gulp.dest(paths[bundle].output));
|
||||||
});
|
});
|
||||||
})(key);
|
})(key);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sprite: function() {
|
sprite: function(bundle) {
|
||||||
// Process Icons
|
var name = "sprite-" + bundle;
|
||||||
gulp.task("sprite", function () {
|
tasks.sprite.push(name);
|
||||||
return gulp
|
|
||||||
.src(paths.plyr.src.sprite)
|
// Process Icons
|
||||||
.pipe(svgmin({
|
gulp.task(name, function () {
|
||||||
plugins: [{
|
return gulp
|
||||||
removeDesc: true
|
.src(paths[bundle].src.sprite)
|
||||||
}]
|
.pipe(svgmin({
|
||||||
}))
|
plugins: [{
|
||||||
.pipe(svgstore())
|
removeDesc: true
|
||||||
.pipe(gulp.dest(paths.plyr.output));
|
}]
|
||||||
});
|
}))
|
||||||
},
|
.pipe(svgstore())
|
||||||
templates: function() {
|
.pipe(rename({ basename: (bundle == "plyr" ? "sprite" : bundle) }))
|
||||||
// Build templates
|
.pipe(gulp.dest(paths[bundle].output));
|
||||||
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));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Plyr core files
|
// Plyr core files
|
||||||
build.js(bundles.plyr.js, "plyr");
|
build.js(bundles.plyr.js, "plyr");
|
||||||
build.less(bundles.plyr.less, "plyr");
|
build.less(bundles.plyr.less, "plyr");
|
||||||
build.sass(bundles.plyr.sass, "plyr");
|
build.sass(bundles.plyr.sass, "plyr");
|
||||||
build.sprite();
|
build.sprite("plyr");
|
||||||
|
|
||||||
// Docs files
|
// Docs files
|
||||||
build.templates();
|
|
||||||
build.less(bundles.docs.less, "docs");
|
build.less(bundles.docs.less, "docs");
|
||||||
build.js(bundles.docs.js, "docs");
|
build.js(bundles.docs.js, "docs");
|
||||||
|
build.sprite("docs");
|
||||||
|
|
||||||
// Default gulp task
|
// Build all JS
|
||||||
gulp.task("default", function(){
|
|
||||||
run("templates", tasks.js, tasks.less, "sprite");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Build all JS (inc. templates)
|
|
||||||
gulp.task("js", function(){
|
gulp.task("js", function(){
|
||||||
run("templates", tasks.js);
|
run(tasks.js);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Build SASS (for testing, default is LESS)
|
// Build SASS (for testing, default is LESS)
|
||||||
gulp.task("sass", function(){
|
gulp.task("sass", function(){
|
||||||
run(tasks.sass);
|
run(tasks.sass);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Watch for file changes
|
// Watch for file changes
|
||||||
gulp.task("watch", function () {
|
gulp.task("watch", function () {
|
||||||
// Plyr core
|
// Plyr core
|
||||||
gulp.watch(paths.plyr.src.js, tasks.js);
|
gulp.watch(paths.plyr.src.js, tasks.js);
|
||||||
gulp.watch(paths.plyr.src.less, tasks.less);
|
gulp.watch(paths.plyr.src.less, tasks.less);
|
||||||
gulp.watch(paths.plyr.src.sprite, "sprite");
|
gulp.watch(paths.plyr.src.sprite, tasks.sprite);
|
||||||
|
|
||||||
// Docs
|
// Docs
|
||||||
gulp.watch(paths.docs.src.js, tasks.js);
|
gulp.watch(paths.docs.src.js, tasks.js);
|
||||||
gulp.watch(paths.docs.src.less, tasks.less);
|
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
|
// Publish a version to CDN and docs
|
||||||
@ -198,69 +194,83 @@ gulp.task("watch", function () {
|
|||||||
// Some options
|
// Some options
|
||||||
var aws = loadJSON(path.join(root, "aws.json")),
|
var aws = loadJSON(path.join(root, "aws.json")),
|
||||||
version = package.version,
|
version = package.version,
|
||||||
maxAge = 31536000, // seconds 1 year
|
maxAge = 31536000, // seconds 1 year
|
||||||
options = {
|
options = {
|
||||||
cdn: {
|
cdn: {
|
||||||
headers: {
|
headers: {
|
||||||
"Cache-Control": "max-age=" + maxAge + ", no-transform, public",
|
"Cache-Control": "max-age=" + maxAge,
|
||||||
"Vary": "Accept-Encoding"
|
"Vary": "Accept-Encoding"
|
||||||
},
|
},
|
||||||
gzippedOnly: true
|
gzippedOnly: true
|
||||||
},
|
},
|
||||||
docs: {
|
docs: {
|
||||||
headers: {
|
headers: {
|
||||||
"Cache-Control": "public, must-revalidate, proxy-revalidate, max-age=0",
|
"Cache-Control": "public, must-revalidate, proxy-revalidate, max-age=0",
|
||||||
"Vary": "Accept-Encoding"
|
"Vary": "Accept-Encoding"
|
||||||
},
|
},
|
||||||
gzippedOnly: true
|
gzippedOnly: true
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
cdnpath = new RegExp(aws.cdn.bucket + "\/(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)","gi");
|
|
||||||
|
// If aws is setup
|
||||||
|
if("cdn" in aws) {
|
||||||
|
var cdnpath = new RegExp(aws.cdn.bucket + "\/(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)","gi"),
|
||||||
|
localpath = new RegExp("(\.\.\/)?dist", "gi");
|
||||||
|
}
|
||||||
|
|
||||||
// Publish version to CDN bucket
|
// Publish version to CDN bucket
|
||||||
gulp.task("cdn", function () {
|
gulp.task("cdn", function () {
|
||||||
console.log("Uploading " + version + " to " + aws.cdn.bucket);
|
console.log("Uploading " + version + " to " + aws.cdn.bucket);
|
||||||
|
|
||||||
// Upload to CDN
|
// Upload to CDN
|
||||||
gulp.src(paths.upload)
|
gulp.src(paths.upload)
|
||||||
.pipe(rename(function (path) {
|
.pipe(size({
|
||||||
path.dirname = path.dirname.replace(".", version);
|
showFiles: true,
|
||||||
}))
|
gzip: true
|
||||||
.pipe(gzip())
|
}))
|
||||||
.pipe(s3(aws.cdn, options.cdn));
|
.pipe(rename(function (path) {
|
||||||
|
path.dirname = path.dirname.replace(".", version);
|
||||||
|
}))
|
||||||
|
.pipe(gzip())
|
||||||
|
.pipe(s3(aws.cdn, options.cdn));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Publish to Docs bucket
|
// Publish to Docs bucket
|
||||||
gulp.task("docs", function () {
|
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
|
// Replace versioned files in readme.md
|
||||||
gulp.src([paths.docs.root + "*.html"])
|
gulp.src([root + "/readme.md"])
|
||||||
.pipe(replace(cdnpath, aws.cdn.bucket + "/" + version))
|
.pipe(replace(cdnpath, aws.cdn.bucket + "/" + version))
|
||||||
.pipe(gulp.dest(paths.docs.root))
|
.pipe(gulp.dest(root));
|
||||||
.pipe(gzip())
|
|
||||||
.pipe(s3(aws.docs, options.docs));
|
|
||||||
|
|
||||||
// Upload error.html to cdn using docs options
|
// Replace local file paths with remote paths in docs
|
||||||
gulp.src([paths.docs.root + "error.html"])
|
// e.g. "../dist/plyr.js" to "https://cdn.plyr.io/x.x.x/plyr.js"
|
||||||
.pipe(gzip())
|
gulp.src([paths.docs.root + "*.html"])
|
||||||
.pipe(s3(aws.cdn, options.docs));
|
.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(gzip())
|
||||||
|
.pipe(s3(aws.cdn, options.docs));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Open the docs site to check it's sweet
|
// Open the docs site to check it's sweet
|
||||||
gulp.task("open", function () {
|
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
|
// A file must be specified or gulp will skip the task
|
||||||
// Doesn't matter which file since we set the URL above
|
// Doesn't matter which file since we set the URL above
|
||||||
// Weird, I know...
|
// Weird, I know...
|
||||||
gulp.src([paths.docs.root + "index.html"])
|
gulp.src([paths.docs.root + "index.html"])
|
||||||
.pipe(open("", {
|
.pipe(open("", {
|
||||||
url: "http://" + aws.docs.bucket
|
url: "http://" + aws.docs.bucket
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Do everything
|
// Do everything
|
||||||
gulp.task("publish", function () {
|
gulp.task("publish", function () {
|
||||||
run("templates", tasks.js, tasks.less, "sprite", "cdn", "docs", "open");
|
run(tasks.js, tasks.less, tasks.sprite, "cdn", "docs");
|
||||||
});
|
});
|
9
notes.md
@ -1,9 +0,0 @@
|
|||||||
Loading
|
|
||||||
--------------
|
|
||||||
http://stackoverflow.com/questions/8685038/tell-whether-video-is-loaded-or-not-in-javascript
|
|
||||||
http://stackoverflow.com/questions/5181865/checking-if-a-html5-video-is-ready
|
|
||||||
|
|
||||||
Events
|
|
||||||
--------------
|
|
||||||
https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement
|
|
||||||
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events
|
|
24
package.json
@ -1,28 +1,28 @@
|
|||||||
{
|
{
|
||||||
"name": "plyr",
|
"name": "plyr",
|
||||||
"version": "1.0.21",
|
"version": "1.5.0",
|
||||||
"description": "A simple HTML5 media player using custom controls",
|
"description": "A simple HTML5 media player using custom controls",
|
||||||
"homepage": "http://plyr.io",
|
"homepage": "http://plyr.io",
|
||||||
"main": "gulpfile.js",
|
"main": "gulpfile.js",
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"gulp": "~3.8.6",
|
"gulp": "^3.9.0",
|
||||||
"gulp-autoprefixer": "^0.0.8",
|
"gulp-autoprefixer": "^3.1.0",
|
||||||
"gulp-concat": "~2.3.3",
|
"gulp-concat": "^2.3.3",
|
||||||
"gulp-gzip": "^1.0.0",
|
"gulp-gzip": "^1.0.0",
|
||||||
"gulp-hogan-compile": "^0.4.1",
|
"gulp-less": "^3.0.5",
|
||||||
"gulp-less": "~1.3.1",
|
"gulp-minify-css": "^1.2.1",
|
||||||
"gulp-minify-css": "~0.3.6",
|
"gulp-open": "^1.0.0",
|
||||||
"gulp-open": "^0.3.2",
|
|
||||||
"gulp-rename": "^1.2.0",
|
"gulp-rename": "^1.2.0",
|
||||||
"gulp-replace": "^0.5.3",
|
"gulp-replace": "^0.5.3",
|
||||||
"gulp-s3": "^0.3.0",
|
"gulp-s3": "^0.3.0",
|
||||||
"gulp-sass": "^1.3.3",
|
"gulp-sass": "^2.1.0",
|
||||||
|
"gulp-size": "^2.0.0",
|
||||||
"gulp-svgmin": "^1.0.0",
|
"gulp-svgmin": "^1.0.0",
|
||||||
"gulp-svgstore": "^5.0.0",
|
"gulp-svgstore": "^5.0.0",
|
||||||
"gulp-uglify": "~0.3.1",
|
"gulp-uglify": "^1.5.1",
|
||||||
"gulp-util": "~2.2.20",
|
"gulp-util": "^3.0.7",
|
||||||
"run-sequence": "^0.3.6"
|
"run-sequence": "^1.1.5"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"preinstall": "npm install -g gulp"
|
"preinstall": "npm install -g gulp"
|
||||||
|
503
readme.md
@ -1,43 +1,46 @@
|
|||||||
# Plyr
|
# Plyr
|
||||||
A simple, accessible HTML5 media player.
|
A simple, accessible HTML5 media player.
|
||||||
|
|
||||||
[Checkout the demo](http://plyr.io)
|
Checkout the [demo](http://plyr.io).
|
||||||
|
|
||||||
[](http://plyr.io)
|
[](http://plyr.io)
|
||||||
|
|
||||||
## Why?
|
## 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 just supports [*modern*](#browser-support) browsers. Sure, there are many other players out there but we wanted to keep things simple, using the right elements for the job.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- **Accessible** - full support for captions and screen readers.
|
- **Accessible** - full support for VTT captions and screen readers.
|
||||||
- **Lightweight** - just 5.3KB minified and gzipped.
|
- **Lightweight** - just 8KB minified and gzipped.
|
||||||
- **Customisable** - make the player look how you want with the markup you want.
|
- **[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.
|
- **Semantic** - uses the *right* elements. `<input type="range">` for volume and `<progress>` for progress and well, `<button>`s for buttons. There's no `<span>` or `<a href="#">` button hacks.
|
||||||
- **Responsive** - as you'd expect these days.
|
- **Responsive** - as you'd expect these days.
|
||||||
- **Audio & Video** - support for both formats.
|
- **Audio & Video** - support for both formats.
|
||||||
- **API** - toggle playback, volume, seeking, and more.
|
- **[Embedded Video](#embeds)** - support for YouTube and Vimeo (beta).
|
||||||
- **Fullscreen** - supports native fullscreen with fallback to "full window" modes.
|
- **[API](#api)** - toggle playback, volume, seeking, and more.
|
||||||
|
- **[Fullscreen](#fullscreen)** - supports native fullscreen with fallback to "full window" modes.
|
||||||
|
- **i18n support** - support for internationalization of controls.
|
||||||
- **No dependencies** - written in vanilla JavaScript, no jQuery required.
|
- **No dependencies** - written in vanilla JavaScript, no jQuery required.
|
||||||
|
|
||||||
Oh and yes, it works with Bootstrap.
|
Oh and yes, it works with Bootstrap.
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
Check out [the changelog](changelog.md)
|
Check out the [changelog](changelog.md) to see what's been new with Plyr.
|
||||||
|
|
||||||
## Planned development
|
## Planned Development
|
||||||
- Accept a string selector, a node, or a nodelist for the `container` property of `selectors`.
|
- Playback speed
|
||||||
|
- Playlists
|
||||||
- Multiple language captions (with selection)
|
- Multiple language captions (with selection)
|
||||||
- Playlists (audio and video)
|
- Audio captions
|
||||||
- Set source by API
|
|
||||||
- Tooltip option (for seeking and controls)
|
|
||||||
... and whatever else has been raised in [issues](https://github.com/Selz/plyr/issues)
|
... 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
|
## 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.5.0/plyr.js` to `https://cdn.plyr.io/1.5.0/plyr.js`
|
||||||
|
|
||||||
### Bower
|
### Bower
|
||||||
If bower is your thang, you can grab Plyr using:
|
If bower is your thang, you can grab Plyr using:
|
||||||
```
|
```
|
||||||
@ -45,42 +48,55 @@ bower install plyr
|
|||||||
```
|
```
|
||||||
More info on setting up dependencies can be found in the [Bower Docs](http://bower.io/docs/creating-packages/#maintaining-dependencies)
|
More info on setting up dependencies can be found in the [Bower Docs](http://bower.io/docs/creating-packages/#maintaining-dependencies)
|
||||||
|
|
||||||
|
### Ember
|
||||||
|
The awesome [@louisrudner](https://twitter.com/louisrudner) has created an ember component, available by running:
|
||||||
|
```
|
||||||
|
ember addon:install ember-cli-plyr
|
||||||
|
```
|
||||||
|
More info is on [npm](https://www.npmjs.com/package/ember-cli-plyr) and [GitHub](https://github.com/louisrudner/ember-cli-plyr)
|
||||||
|
|
||||||
### CDN
|
### CDN
|
||||||
If you want to use our CDN, you can use the following. HTTPS (SSL) is supported.
|
If you want to use our CDN, you can use the following:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<link rel="stylesheet" href="//cdn.plyr.io/1.0.21/plyr.css">
|
<link rel="stylesheet" href="https://cdn.plyr.io/1.5.0/plyr.css">
|
||||||
<script src="//cdn.plyr.io/1.0.21/plyr.js"></script>
|
<script src="https://cdn.plyr.io/1.5.0/plyr.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also access the `sprite.svg` file at `//cdn.plyr.io/1.0.21/sprite.svg`.
|
You can also access the `sprite.svg` file at `https://cdn.plyr.io/1.5.0/sprite.svg`.
|
||||||
|
|
||||||
### CSS
|
### 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.sass` file included in `/src` in your build to save a request.
|
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.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<link rel="stylesheet" href="dist/plyr.css">
|
<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
|
### 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 is loaded in by AJAX to help with performance. This is best added before the closing `</body>`, before any other scripts.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script>
|
<script>
|
||||||
(function(d,p){
|
(function(d, p){
|
||||||
var a=new XMLHttpRequest(),
|
var a = new XMLHttpRequest(),
|
||||||
b=d.body;
|
b = d.body;
|
||||||
a.open("GET",p,!0);
|
a.open('GET', p, true);
|
||||||
a.send();
|
a.send();
|
||||||
a.onload=function(){
|
a.onload = function() {
|
||||||
var c=d.createElement("div");
|
var c = d.createElement('div');
|
||||||
c.style.display="none";
|
c.setAttribute('hidden', '');
|
||||||
c.innerHTML=a.responseText;
|
c.innerHTML = a.responseText;
|
||||||
b.insertBefore(c,b.childNodes[0])
|
b.insertBefore(c, b.childNodes[0]);
|
||||||
}
|
};
|
||||||
})(document,"dist/sprite.svg");
|
})(document, 'path/to/sprite.svg');
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you're using the `<base>` tag on your site, you may need to use something like this:
|
||||||
|
[https://gist.github.com/leonderijke/c5cf7c5b2e424c0061d2](svgfixer.js)
|
||||||
|
|
||||||
More info on SVG sprites here:
|
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/)
|
[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:
|
and the AJAX technique here:
|
||||||
@ -89,60 +105,87 @@ and the AJAX technique here:
|
|||||||
### HTML
|
### 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.
|
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
|
```html
|
||||||
<div class="player">
|
<div class="plyr">
|
||||||
<video poster="//cdn.selz.com/plyr/1.0/poster.jpg" controls crossorigin>
|
<video poster="/path/to/poster.jpg" controls>
|
||||||
<!-- Video files -->
|
<!-- Video files -->
|
||||||
<source src="//cdn.selz.com/plyr/1.0/movie.mp4" type="video/mp4">
|
<source src="/path/to/video.mp4" type="video/mp4">
|
||||||
<source src="//cdn.selz.com/plyr/1.0/movie.webm" type="video/webm">
|
<source src="/path/to/video.webm" type="video/webm">
|
||||||
|
|
||||||
<!-- Text track file -->
|
<!-- 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 -->
|
<!-- Fallback for browsers that don't support the <video> element -->
|
||||||
<div>
|
<a href="/path/to/movie.mp4">Download</a>
|
||||||
<a href="//cdn.selz.com/plyr/1.0/movie.mp4">Download</a>
|
|
||||||
</div>
|
|
||||||
</video>
|
</video>
|
||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
And the same for `<audio>`
|
And the same for `<audio>`
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<div class="player">
|
<div class="plyr">
|
||||||
<audio controls>
|
<audio controls>
|
||||||
<!-- Audio files -->
|
<!-- Audio files -->
|
||||||
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3" type="audio/mp3">
|
<source src="/path/to/audio.mp3" type="audio/mp3">
|
||||||
<source src="//cdn.selz.com/plyr/1.0/logistics-96-sample.ogg" type="audio/ogg">
|
<source src="/path/to/audio.ogg" type="audio/ogg">
|
||||||
|
|
||||||
<!-- Fallback for browsers that don't support the <audio> element -->
|
<!-- Fallback for browsers that don't support the <audio> element -->
|
||||||
<div>
|
<a href="/path/to/audio.mp3">Download</a>
|
||||||
<a href="//cdn.selz.com/plyr/1.0/logistics-96-sample.mp3">Download</a>
|
|
||||||
</div>
|
|
||||||
</audio>
|
</audio>
|
||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For YouTube, Plyr uses the standard YouTube API markup (an empty `<div>`):
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="plyr">
|
||||||
|
<div data-video-id="L1h9xxCU20g" data-type="youtube"></div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
#### Cross Origin (CORS)
|
#### 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:
|
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)
|
[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
|
### JavaScript
|
||||||
Much of the behaviour of the player is configurable when initialising the library. Below is an example of a default instance.
|
|
||||||
|
#### Quick setup
|
||||||
|
|
||||||
|
Here's an example of a default setup:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="dist/plyr.js"></script>
|
<script src="https://cdn.plyr.io/1.5.0/plyr.js"></script>
|
||||||
<script>
|
<script>plyr.setup();</script>
|
||||||
plyr.setup({
|
```
|
||||||
*options*
|
|
||||||
});
|
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).
|
||||||
</script>
|
|
||||||
|
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);
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Options
|
#### Options
|
||||||
|
|
||||||
You can pass the following options to the setup method.
|
Options must be passed as an object to the `setup()` method as above.
|
||||||
|
|
||||||
<table class="table" width="100%">
|
<table class="table" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
@ -158,7 +201,7 @@ You can pass the following options to the setup method.
|
|||||||
<td><code>enabled</code></td>
|
<td><code>enabled</code></td>
|
||||||
<td>Boolean</td>
|
<td>Boolean</td>
|
||||||
<td><code>true</code></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>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>html</code></td>
|
<td><code>html</code></td>
|
||||||
@ -166,6 +209,24 @@ You can pass the following options to the setup method.
|
|||||||
<td><code><a href="controls.md">See controls.md</a></code></td>
|
<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>
|
<td>See <a href="controls.md">controls.md</a> for more info on how the html needs to be structured.</td>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td><code>debug</code></td>
|
<td><code>debug</code></td>
|
||||||
<td>Boolean</td>
|
<td>Boolean</td>
|
||||||
@ -188,13 +249,31 @@ You can pass the following options to the setup method.
|
|||||||
<td><code>click</code></td>
|
<td><code>click</code></td>
|
||||||
<td>Boolean</td>
|
<td>Boolean</td>
|
||||||
<td><code>true</code></td>
|
<td><code>true</code></td>
|
||||||
<td>Click (or tap) will toggle pause/play of a `<video>`.</td>
|
<td>Click (or tap) will toggle pause/play of a <code><video></code>.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>tooltips</code></td>
|
||||||
|
<td>Boolean</td>
|
||||||
|
<td><code>false</code></td>
|
||||||
|
<td>Display control labels as tooltips on :hover & :focus (by default, the labels are screen reader only).</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>displayDuration</code></td>
|
||||||
|
<td>Boolean</td>
|
||||||
|
<td><code>true</code></td>
|
||||||
|
<td>Displays the duration of the media on the "metadataloaded" event (on startup) in the current time display. This will only work if the `preload` attribute is not set to `none` (or is not set at all) and you choose not to display the duration (see <code>controls</code> option).</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>selectors</code></td>
|
<td><code>selectors</code></td>
|
||||||
<td>Object</td>
|
<td>Object</td>
|
||||||
<td>—</td>
|
<td>—</td>
|
||||||
<td>See `plyr.js` in `/src` for more info. The only option you might want to change is `player` which is the hook used for Plyr, the default is `.player`.</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>handlers</code></td>
|
||||||
|
<td>Object</td>
|
||||||
|
<td>—</td>
|
||||||
|
<td>Allows early binding of handlers to Plyr's 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>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>classes</code></td>
|
<td><code>classes</code></td>
|
||||||
@ -206,29 +285,91 @@ You can pass the following options to the setup method.
|
|||||||
<td><code>captions</code></td>
|
<td><code>captions</code></td>
|
||||||
<td>Object</td>
|
<td>Object</td>
|
||||||
<td>—</td>
|
<td>—</td>
|
||||||
<td>This currently contains one property `defaultActive` which toggles if captions should be on by default. The default value is `false`.</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>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>fullscreen</code></td>
|
<td><code>fullscreen</code></td>
|
||||||
<td>Object</td>
|
<td>Object</td>
|
||||||
<td>—</td>
|
<td>—</td>
|
||||||
<td>This currently contains two properties; `enabled` which toggles if fullscreen should be enabled (if the browser supports it). The default value is `true`. Also an extra property called `fallback` which will enable a 'full window' view for older browsers. The default value is `true`.</td>
|
<td>See <a href="#fullscreen-options">below</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>storage</code></td>
|
<td><code>storage</code></td>
|
||||||
<td>Object</td>
|
<td>Object</td>
|
||||||
<td>—</td>
|
<td>—</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>
|
||||||
|
<tr>
|
||||||
|
<td><code>onSetup</code></td>
|
||||||
|
<td>Function</td>
|
||||||
|
<td>—</td>
|
||||||
|
<td>This callback function is called on every new plyr instance created. The context (<code>this</code>) is the plyr instance itself.</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</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>hideControls</code></td>
|
||||||
|
<td>Boolean</td>
|
||||||
|
<td><code>true</code></td>
|
||||||
|
<td>Hide the controls when fullscreen is active and the video is playing, after 1s. The controls reappear on hover of the progress bar (mouse), focusing a child control or pausing the video (by tap/click of video if `click` is `true`).</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
|
## 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
|
```javascript
|
||||||
document.querySelectorAll(".player")[0].plyr.pause();
|
var player = document.querySelector('.js-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 also use the `onSetup` callback documented below which will return each instance one by one, as they are setup.
|
||||||
|
|
||||||
|
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:
|
Here's a list of the methods supported:
|
||||||
@ -240,62 +381,230 @@ Here's a list of the methods supported:
|
|||||||
<th width="15%">Parameters</th>
|
<th width="15%">Parameters</th>
|
||||||
<th width="65%">Description</th>
|
<th width="65%">Description</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>play</code></td>
|
<td><code>play()</code></td>
|
||||||
<td>—</td>
|
<td>—</td>
|
||||||
<td>Plays the media</td>
|
<td>Plays the media</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>pause</code></td>
|
<td><code>pause()</code></td>
|
||||||
<td>—</td>
|
<td>—</td>
|
||||||
<td>Pauses the media</td>
|
<td>Pauses the media</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>restart</code></td>
|
<td><code>restart()</code></td>
|
||||||
<td>—</td>
|
<td>—</td>
|
||||||
<td>Restarts playback</td>
|
<td>Restarts playback</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>rewind</code></td>
|
<td><code>rewind(...)</code></td>
|
||||||
<td>Number</td>
|
<td>Number</td>
|
||||||
<td>Rewinds by the provided parameter, in seconds. If no parameter is provided, the default seekInterval is used (10 seconds).</td>
|
<td>Rewinds by the provided parameter, in seconds. If no parameter is provided, the default seekInterval is used (10 seconds).</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>forward</code></td>
|
<td><code>forward(...)</code></td>
|
||||||
<td>Number</td>
|
<td>Number</td>
|
||||||
<td>Fast forwards by the provided parameter, in seconds. If no parameter is provided, the default seekInterval is used (10 seconds).</td>
|
<td>Fast forwards by the provided parameter, in seconds. If no parameter is provided, the default seekInterval is used (10 seconds).</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>seek</code></td>
|
<td><code>seek(...)</code></td>
|
||||||
<td>Number</td>
|
<td>Number</td>
|
||||||
<td>Seeks the media to the provided parameter, time in seconds.</td>
|
<td>Seeks the media to the provided parameter, time in seconds.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>setVolume</code></td>
|
<td><code>setVolume(...)</code></td>
|
||||||
<td>Number</td>
|
<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>
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>toggleMute</code></td>
|
<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>—</td>
|
<td>—</td>
|
||||||
<td>Toggles mute for the player.</td>
|
<td>Toggles mute for the player.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code>toggleCaptions</code></td>
|
<td><code>toggleCaptions()</code></td>
|
||||||
<td>—</td>
|
<td>—</td>
|
||||||
<td>Toggles whether captions are enabled.</td>
|
<td>Toggles whether captions are enabled.</td>
|
||||||
</tr>
|
</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>—</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. This is not supported for embedded content (YouTube).</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>source(...)</code></td>
|
||||||
|
<td>Array or undefined</td>
|
||||||
|
<td>
|
||||||
|
Get/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.
|
||||||
|
<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.
|
||||||
|
<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>
|
||||||
|
<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>—</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>—</td>
|
||||||
|
<td>Reverses the effects of the <code>destroy()</code> method, restoring the UI and listeners.</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
#### .source() method
|
||||||
|
|
||||||
|
This allows changing the plyr source and type on the fly.
|
||||||
|
|
||||||
|
Video example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
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 or String</td>
|
||||||
|
<td>This is an array of sources or optionally a string for embedded players (YouTube and Vimeo). `type` is also 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/Callbacks
|
## Events/Callbacks
|
||||||
|
|
||||||
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:
|
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:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var media = document.querySelectorAll(".player")[0].plyr.media;
|
var media = document.querySelector(".js-plyr").plyr.media;
|
||||||
|
|
||||||
media.addEventListener("playing", function() {
|
media.addEventListener("playing", function() {
|
||||||
console.log("playing");
|
console.log("playing");
|
||||||
@ -304,12 +613,33 @@ media.addEventListener("playing", function() {
|
|||||||
A complete list of events can be found here:
|
A complete list of events can be found here:
|
||||||
[Media Events - W3.org](http://www.w3.org/2010/05/video/mediaevents.html)
|
[Media Events - W3.org](http://www.w3.org/2010/05/video/mediaevents.html)
|
||||||
|
|
||||||
|
## Embeds
|
||||||
|
|
||||||
|
Currently only YouTube is supported. Vimeo will be coming soon. Some HTML5 media events are triggered on the `media` property of the `plyr` object:
|
||||||
|
- `play`
|
||||||
|
- `pause`
|
||||||
|
- `timeupdate`
|
||||||
|
- `progress`
|
||||||
|
|
||||||
|
Due to the way the YouTube API works, the `timeupdate` and `progress` events are triggered by polling every 200ms so the event may trigger without an actual value change. Buffering progress is `media.buffered` in the `plyr` object. It is a a number between 0 and 1 that specifies the percentage of the video that the player shows as buffered.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
document.querySelector(".js-plyr").plyr.media.addEventListener("play", function() {
|
||||||
|
console.log("play");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
The `.source()` API method can also be used but the video id must be passed as the argument.
|
||||||
|
|
||||||
|
Currently caption control is not supported but I will work on this.
|
||||||
|
|
||||||
## Fullscreen
|
## Fullscreen
|
||||||
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
|
## Browser support
|
||||||
|
|
||||||
<table width="100%" style="text-align: center;">
|
<table width="100%" style="text-align: center">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Safari</td>
|
<td>Safari</td>
|
||||||
@ -322,19 +652,21 @@ Fullscreen in Plyr is supported for all browsers that [currently support it](htt
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td>✔¹</td>
|
||||||
<td>✔</td>
|
<td>✔</td>
|
||||||
<td>✔</td>
|
<td>✔</td>
|
||||||
<td>✔</td>
|
<td>✔</td>
|
||||||
<td>✔</td>
|
<td>API²</td>
|
||||||
<td>✖¹</td>
|
<td>✔³</td>
|
||||||
<td>✔²</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
¹ Native player used (no support for `<progress>` or `<input type="range">`)
|
¹ Mobile Safari on the iPhone forces the native player for `<video>` so no useful customisation is possible. `<audio>` elements have volume controls disabled.
|
||||||
|
|
||||||
² IE10 has no native fullscreen support, fallback can be used (see options)
|
² Native player used (no support for `<progress>` or `<input type="range">`) but the API is supported (v1.0.28+)
|
||||||
|
|
||||||
|
³ 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:
|
||||||
|
|
||||||
@ -345,19 +677,24 @@ 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.
|
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
|
## Issues
|
||||||
If you find anything weird with Plyr, please let us know using the GitHub issues tracker.
|
If you find anything weird with Plyr, please let us know using the GitHub issues tracker.
|
||||||
|
|
||||||
## Author
|
## 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
|
## Mentions
|
||||||
- [The Changelog](http://thechangelog.com/plyr-simple-html5-media-player-custom-controls-webvtt-captions/)
|
- [The Changelog](http://thechangelog.com/plyr-simple-html5-media-player-custom-controls-webvtt-captions/)
|
||||||
- [HTML5 Weekly #177](http://html5weekly.com/issues/177)
|
- [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/)
|
- [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)
|
- [Hacker News](https://news.ycombinator.com/item?id=9136774)
|
||||||
- [Web Platform Daily](http://webplatformdaily.org/releases/2015-03-04)
|
- [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)
|
- [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)
|
||||||
|
|
||||||
## Used by
|
## Used by
|
||||||
- [Selz.com](https://selz.com)
|
- [Selz.com](https://selz.com)
|
||||||
|
2741
src/js/plyr.js
1040
src/less/plyr.less
1053
src/sass/plyr.scss
@ -1,10 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?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">
|
<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">
|
||||||
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
<title>Captions Off</title>
|
||||||
<title>icon-captions-off</title>
|
<g>
|
||||||
<desc>Created with Sketch.</desc>
|
<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>
|
||||||
<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>
|
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 747 B After Width: | Height: | Size: 474 B |
@ -1,13 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?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">
|
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
<title>Captions On</title>
|
||||||
<title>icon-captions-on</title>
|
<g>
|
||||||
<desc>Created with Sketch.</desc>
|
<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>
|
||||||
<defs></defs>
|
<rect x="3" y="11" width="3" height="2"></rect>
|
||||||
<g id="Page-1" stroke="none" stroke-width="1" sketch:type="MSPage">
|
<rect x="12" y="11" width="3" height="2"></rect>
|
||||||
<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 x="7" y="11" width="4" height="2"></rect>
|
||||||
<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>
|
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 587 B |
@ -1,13 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?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">
|
<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">
|
||||||
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
<title>Enter Fullscreen</title>
|
||||||
<title>expand</title>
|
<g>
|
||||||
<desc>Created with Sketch.</desc>
|
<g transform="translate(9.000000, 9.000000) rotate(-180.000000) translate(-9.000000, -9.000000) translate(0.000000, 2.000000)">
|
||||||
<defs></defs>
|
<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>
|
||||||
<g id="Page-1" stroke="none" stroke-width="1" sketch:type="MSPage">
|
<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 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>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 787 B |
@ -1,13 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?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">
|
<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">
|
||||||
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
<title>Exit Fullscreen</title>
|
||||||
<title>collapse</title>
|
<g>
|
||||||
<desc>Created with Sketch.</desc>
|
<g transform="translate(0.000000, 2.000000)">
|
||||||
<defs></defs>
|
<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>
|
||||||
<g id="Page-1" stroke="none" stroke-width="1">
|
<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 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>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 704 B |
@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Generated by IcoMoon.io -->
|
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
<title>Fast Forward</title>
|
||||||
<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>
|
||||||
<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>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 635 B After Width: | Height: | Size: 510 B |
@ -1,14 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?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">
|
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
<title>Muted</title>
|
||||||
<title>muted</title>
|
<g transform="translate(0.000000, 2.000000)">
|
||||||
<desc>Created with Sketch.</desc>
|
<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>
|
||||||
<defs></defs>
|
<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>
|
||||||
<g id="Page-1" stroke="none" stroke-width="1" sketch:type="MSPage">
|
<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 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>
|
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.8 KiB |
@ -1,13 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?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">
|
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
<title>Pause</title>
|
||||||
<title>pause</title>
|
<g transform="translate(2.000000, 2.000000)">
|
||||||
<desc>Created with Sketch.</desc>
|
<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"></path>
|
||||||
<defs></defs>
|
<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"></path>
|
||||||
<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>
|
</g>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 666 B |
@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Generated by IcoMoon.io -->
|
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
<title>Play</title>
|
||||||
<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>
|
||||||
<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>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 515 B After Width: | Height: | Size: 382 B |
17
src/sprite/icon-restart.svg
Normal file → Executable file
@ -1,10 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<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: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
<title>icon-restart</title>
|
<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"
|
||||||
<desc>Created with Sketch.</desc>
|
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
|
||||||
<defs></defs>
|
<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
|
||||||
<g id="Page-1" stroke="none" stroke-width="1" sketch:type="MSPage">
|
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
|
||||||
<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>
|
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"/>
|
||||||
</g>
|
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 760 B |
@ -1,10 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?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">
|
<svg viewBox="0 0 18 21" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||||
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
|
<title>Rewind</title>
|
||||||
<title>rewind</title>
|
<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" transform="translate(9.000000, 10.000000) rotate(-180.000000) translate(-9.000000, -10.000000) "></path>
|
||||||
<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>
|
</svg>
|
Before Width: | Height: | Size: 1021 B After Width: | Height: | Size: 729 B |
@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Generated by IcoMoon.io -->
|
<svg viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
<title>Volume</title>
|
||||||
<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="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>
|
||||||
<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>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.0 KiB |