Compare commits
599 Commits
Author | SHA1 | Date | |
---|---|---|---|
efe70ab48e | |||
1e1874d86b | |||
16624b90d3 | |||
ed14b656a8 | |||
1d0cf16254 | |||
05b85da3f4 | |||
a4caba120c | |||
969a877a34 | |||
fb22a90d33 | |||
108bd3dfa0 | |||
5a445ae647 | |||
56668f58b6 | |||
eec96e5879 | |||
c6c9d877e4 | |||
61f4b998e1 | |||
25a319d884 | |||
4bf678fe6c | |||
359acd6bb9 | |||
2fce385691 | |||
a82c61c539 | |||
a8fa125a96 | |||
6435ced707 | |||
94dc0d176c | |||
23c21252e8 | |||
41c7dff0e8 | |||
e3bae562fc | |||
1c1668bfc3 | |||
e0c09c51f2 | |||
8de06fb862 | |||
64412868d8 | |||
450958c290 | |||
963fe11ad6 | |||
ce199e4b6b | |||
9d798893b5 | |||
64399e0717 | |||
f58e23b325 | |||
812e07b734 | |||
c9298fde76 | |||
0109454a34 | |||
813f703211 | |||
7aad747c25 | |||
d70a787af1 | |||
69bb0917ad | |||
6f256d09b2 | |||
e9684c2021 | |||
bf91a0e73f | |||
14b6309aef | |||
6391ced99f | |||
fac8a185ba | |||
c69aa8a42b | |||
f34bf22125 | |||
f0be913dc3 | |||
cd51788b98 | |||
edd67b0da3 | |||
d733454d7f | |||
41f9a87e0e | |||
f4858f0c62 | |||
121093ae71 | |||
aa8fc313a9 | |||
723298a07b | |||
f8c89e3e95 | |||
333435a9c2 | |||
3ab2295fe7 | |||
c41bb657ac | |||
55bbf64f2b | |||
3bba65f2c2 | |||
1bab0d07b5 | |||
602353f4d9 | |||
51814249af | |||
37c5fbfe16 | |||
d7356726a1 | |||
4db6bf7a2e | |||
28826f6402 | |||
c845558d96 | |||
16c3a7d9e5 | |||
90d5b48845 | |||
d1acc4abb3 | |||
797b70998f | |||
4a01027da0 | |||
7ca2169790 | |||
054f522aa9 | |||
f2fc3f5ea5 | |||
765c01e83d | |||
33a11fb53a | |||
d1d41ca49a | |||
c06e0ee5e9 | |||
83f80ccc40 | |||
069065ea3a | |||
1672e78041 | |||
34401de3d0 | |||
f687b81b70 | |||
bbb11e611e | |||
90919411e9 | |||
1491b017a0 | |||
1655150092 | |||
ceb6c9a100 | |||
00bbce08fb | |||
91a4b86860 | |||
5aece6fa06 | |||
a70b94afe2 | |||
9ebc2719d3 | |||
b46aae1833 | |||
30e6a40865 | |||
403df36af6 | |||
5ca769807e | |||
72a71a605b | |||
24d833a5d1 | |||
44b30380f7 | |||
261cd086c7 | |||
9e19b526b9 | |||
6c617a0ef1 | |||
a812650fea | |||
fec7a77d6f | |||
971e261067 | |||
27407ba021 | |||
ef8e58ede4 | |||
f13260c10a | |||
e1183d6049 | |||
f1b275aedc | |||
b647af256c | |||
d2e9ed3467 | |||
5b39986835 | |||
a97b08e8ea | |||
56d1be9447 | |||
a241cb5215 | |||
042b1a8294 | |||
6d79b8cd4c | |||
88d766aeae | |||
119b471b84 | |||
7f079e0ec3 | |||
46fe3eecff | |||
3061a701d5 | |||
e45109e1d7 | |||
e138e6d51e | |||
aef1363b04 | |||
766dd03d81 | |||
ab393651ec | |||
ffd265d0ae | |||
72155472dd | |||
9b7170834e | |||
3e57a87bf7 | |||
a15d1c9f1c | |||
a095a64f90 | |||
2374d6b1c4 | |||
5ed3ff9084 | |||
385be55510 | |||
3082d0d128 | |||
f7e242f054 | |||
2874505004 | |||
ed9e0c13d7 | |||
10be94fa99 | |||
ee79c46145 | |||
384010a2c0 | |||
1e47019122 | |||
536c65e82c | |||
cdf14932ec | |||
3b20dbd9fd | |||
e4d975af00 | |||
2782a00e7c | |||
91d192dd7c | |||
b1e3abc795 | |||
3395e8df90 | |||
cce143a7da | |||
d593005b32 | |||
7be9d5d4d3 | |||
d7141d5ed7 | |||
0d0ece94d3 | |||
1c06f6d06d | |||
dda8e30b92 | |||
c4e2e24643 | |||
e020a105a3 | |||
2b7fe9a4f9 | |||
951df64b7f | |||
0976afe282 | |||
7b1e4abda7 | |||
0cf75eed3f | |||
d96957d086 | |||
1a032ea498 | |||
5d079da1b8 | |||
9c1bc6ab08 | |||
3d2ba8c009 | |||
e872ce3f77 | |||
b77756da04 | |||
9b23e13ce8 | |||
5eafe9baff | |||
c251c94131 | |||
17041efc71 | |||
05b8e8a6e0 | |||
f998b996fa | |||
958b47c435 | |||
a27248d3b6 | |||
1b1f7be7ff | |||
59d4a27240 | |||
75e9f3c2e3 | |||
7132eccf50 | |||
e953c6398c | |||
bb7eea27e5 | |||
595c5e95bc | |||
43e6dcd41d | |||
b06c8ae43f | |||
c7ea13c0c7 | |||
0f8c6e147b | |||
e566365288 | |||
a06e0f5890 | |||
3bccc0da01 | |||
a0173d991e | |||
600f0eb8a3 | |||
5db73b1327 | |||
5cb1628cd8 | |||
c74b75e8e1 | |||
0538476d6f | |||
5ebe18d081 | |||
207adde36d | |||
1b13ddaa54 | |||
9981c349be | |||
b3365a7373 | |||
9a0c1c830d | |||
ef27ba16f4 | |||
e206edc1f6 | |||
c734bc4957 | |||
572b8a7aca | |||
eebae4a227 | |||
6a2ca534d2 | |||
7adc2bc6c8 | |||
ba8d7831a7 | |||
69ffcbad27 | |||
819f7d1080 | |||
409b588458 | |||
e90a603d57 | |||
6f061621ad | |||
0300610108 | |||
2fba5f152c | |||
317b08c703 | |||
bfb550b8d0 | |||
174234c166 | |||
24b4220de5 | |||
f1895a4cce | |||
c2a6306d46 | |||
7ac732f45b | |||
c90f1bdf08 | |||
6a9be8d16b | |||
58c2c52c95 | |||
73a39769d4 | |||
7221e26eca | |||
98adb8e784 | |||
a59dcb2f53 | |||
d21b58e1c9 | |||
d6e84cbabb | |||
fcccf1d479 | |||
211db12a3d | |||
ce1d5a60d6 | |||
f67315e20c | |||
2150c44036 | |||
70c9fbdde3 | |||
f3ea31c515 | |||
1ee88cba16 | |||
af3ae75229 | |||
d76ef3ff91 | |||
2691c7c9d6 | |||
26b1d8ce8f | |||
6fae148fc1 | |||
bb51647fe2 | |||
71efbe7a92 | |||
afd695cb39 | |||
c4eb4c97ac | |||
8f7a8940f3 | |||
5e68f8c8dd | |||
b4e22e2e7b | |||
d4234da9aa | |||
1f53b27d4e | |||
cc128e6088 | |||
3c8acb4e9e | |||
ebf53d14b1 | |||
b298587c0b | |||
26e9aaceb8 | |||
384f3d6eda | |||
3aa5747c90 | |||
5671235fd9 | |||
1dd5c9efd9 | |||
5fad152cbf | |||
f33ca846f2 | |||
986c802acd | |||
98dd818bf6 | |||
021f6c8460 | |||
392f837398 | |||
6831c30534 | |||
ed6048034b | |||
8af312fe3c | |||
d87ada4f58 | |||
31c8166562 | |||
0cb2f95888 | |||
896ea7c689 | |||
1d1eb02bd7 | |||
3583165b30 | |||
d822f0c6bf | |||
9e52296dc6 | |||
12a7a4142c | |||
8348f79742 | |||
ec73d34bd3 | |||
1cef48d4f8 | |||
c24c05226d | |||
4b0005c28e | |||
8064405dbc | |||
22e8892993 | |||
cfc86bcb7c | |||
5f96ec6ac2 | |||
bbdf225d7b | |||
025fc1090b | |||
d9ec1d1b8e | |||
2e5d06ad85 | |||
bacd049eb0 | |||
6fd7b26bb2 | |||
1df79cf7f8 | |||
e6badacf0d | |||
a0d9d5eca8 | |||
8786377a75 | |||
f0322e8d94 | |||
3f2ac3fca0 | |||
9872207e87 | |||
58d942e737 | |||
dd190155c4 | |||
ebb3b83b27 | |||
2b36ab7ef5 | |||
eb38e0394d | |||
e14e2cfaff | |||
04119b27e6 | |||
92cb9e22e2 | |||
6b9106ddb1 | |||
965fc0b2f5 | |||
98ac98b4c2 | |||
178b0d8020 | |||
3bd1c1ff56 | |||
7d4bf91a35 | |||
ac3d1d1242 | |||
742018a716 | |||
a2ef691b4b | |||
9e0c406a4a | |||
f3df7aba15 | |||
6bc3592381 | |||
6864149989 | |||
aab53fa91f | |||
423f67b4f4 | |||
82f81f4f73 | |||
c8990bd379 | |||
de54929bb7 | |||
fd77831303 | |||
cda574e627 | |||
fda1977119 | |||
f7bf0961cf | |||
61325bbad1 | |||
921cefd212 | |||
de6f0f1b77 | |||
7382553a78 | |||
4b82e89845 | |||
d3b31e595a | |||
f33bc5a5c6 | |||
f518ec108b | |||
edfc6cd475 | |||
92cd67effb | |||
da1e987444 | |||
2d4a166218 | |||
feae00224e | |||
000afdd300 | |||
0dc9681ae8 | |||
dc391c98c6 | |||
4b62a5c74d | |||
3f744ef63a | |||
5a244b7fed | |||
4dca4bf93c | |||
6984d6fb16 | |||
d7a1c44281 | |||
c64b8f6940 | |||
022b436c3f | |||
6058bb0245 | |||
3ade86537d | |||
d80be3b903 | |||
1a26681d87 | |||
9171297764 | |||
ebd1a52e5d | |||
743c84188e | |||
4879bea4a0 | |||
66917fd39b | |||
fd97607e55 | |||
f878581c8f | |||
f9602acf61 | |||
86a5724bdb | |||
63c963d726 | |||
88bfa35b99 | |||
bb66be98da | |||
c948e95ade | |||
1a5f4b1b9e | |||
3f41a0cf54 | |||
966ca1acc3 | |||
e2c7491ccd | |||
fae4ca12e0 | |||
84505da84b | |||
2497e25b3c | |||
9c4b7e7094 | |||
3a9beaed59 | |||
1578525ee3 | |||
62c1b368cf | |||
f8ecea8fb7 | |||
0068710740 | |||
5fe477340b | |||
45df319823 | |||
6bebbe4153 | |||
374de800a4 | |||
60084a17f8 | |||
4d417d0396 | |||
e2d8bd2b73 | |||
1c693df00b | |||
8aaa932050 | |||
3cd6c2acf6 | |||
3930ebb339 | |||
b102714067 | |||
13d3037a53 | |||
1e7a60ee5c | |||
8d80f6b05d | |||
597b3fe0db | |||
d920de2a25 | |||
069c8093ae | |||
1cc2930dc0 | |||
3d50936b47 | |||
dd9d5c8898 | |||
71db66d802 | |||
959b5a20e3 | |||
9de5c0cf39 | |||
1a3868a6c6 | |||
378aa159b8 | |||
6876a9163d | |||
34d28a69ad | |||
0715d3ae67 | |||
542095f5eb | |||
57517a9dcc | |||
751708ff23 | |||
fcf944788a | |||
36a84c5c2d | |||
4392abfc49 | |||
3238b6a36a | |||
18a5edef0e | |||
02cb093f7b | |||
d6977473b1 | |||
15cffad89e | |||
0d96601d1a | |||
7959297a98 | |||
6dd010ea34 | |||
f89ddb2f1b | |||
2e5cc272e3 | |||
ebd13c63e8 | |||
ec091266aa | |||
ad105877ed | |||
c84f666b55 | |||
2bba1f30e2 | |||
2196665495 | |||
0148c76c30 | |||
18b2cbb2e9 | |||
f6a7555a1d | |||
f7144dc0cb | |||
a9957211f4 | |||
7b60e473fa | |||
dfc516baf6 | |||
b0d3bcd15a | |||
03c3960e93 | |||
21f444ed61 | |||
40b4f8e840 | |||
bc61dac4c5 | |||
3605989226 | |||
a49d77afab | |||
7daa08c32f | |||
aaab9ad082 | |||
86c9004183 | |||
857dfe838c | |||
e1a19faf26 | |||
f3bda17fa0 | |||
966c3d875d | |||
fe9383bed5 | |||
2c31770030 | |||
8d3e160166 | |||
408cfe5b97 | |||
279fee3595 | |||
28dddfcff2 | |||
9e2580ec6a | |||
aba5a9dc0e | |||
9999828505 | |||
b04301c211 | |||
97157efcfa | |||
3756476809 | |||
b3d798eeee | |||
b499622eb8 | |||
04b8d0bac8 | |||
8ea4cbd942 | |||
7889ae1126 | |||
897d49ad87 | |||
1960d35d8b | |||
0b7d0dedf6 | |||
948e2cc66c | |||
396b816a1f | |||
0a58cbfd59 | |||
bbe4b7e565 | |||
2ecca2cbe3 | |||
f5d80fa888 | |||
f2bbe4eb12 | |||
60e51b7077 | |||
01d1ac9ab9 | |||
9b2396f5ff | |||
da15980b8a | |||
452678867f | |||
ff2d27f8e5 | |||
546cdaad92 | |||
5d38497f07 | |||
808a3af3cf | |||
889712761a | |||
46fab972a0 | |||
535c046b62 | |||
55dfab8394 | |||
18bf4d84b9 | |||
ef1d73df15 | |||
684107da5c | |||
2a97a9a9c5 | |||
ca12343b16 | |||
a974fbf31c | |||
6eaf33ec6c | |||
33fef7faee | |||
b083bf4297 | |||
ebc7ed538a | |||
a60868bfe8 | |||
4a2866d05f | |||
1a05f352c7 | |||
ba27de0669 | |||
e21e7054ce | |||
bc323e905c | |||
afa1fe9d5f | |||
2444efc834 | |||
7b6257ff20 | |||
13973125fb | |||
ddf9104349 | |||
47b53fffb4 | |||
9ba3753f80 | |||
a353194fe1 | |||
c205c47509 | |||
9c867edfbc | |||
9919d80782 | |||
8464ffe6ad | |||
6537225c61 | |||
dcbf59bd89 | |||
21d478d396 | |||
054c243416 | |||
d57e453541 | |||
3f45ef4908 | |||
1fd742464d | |||
9c599884a8 | |||
cbef45841c | |||
96d9f302c2 | |||
afcdf17a72 | |||
1bcdbe4c00 | |||
45c0ded88c | |||
ea30ad9494 | |||
7608615702 | |||
cc5f37392f | |||
413fcbcb8c | |||
c49d0a99e4 | |||
5a0cb9289c | |||
bce1d983cb | |||
047fc43f8f | |||
0cbfc9252c | |||
d02e57bdb3 | |||
663c1fb627 | |||
a7969b8e9e | |||
4ca3f030cc | |||
02bc8c8445 | |||
7965b82cca | |||
bae04a492a | |||
72404e77e5 | |||
c7310c21fb | |||
ed9e27b64f | |||
801ed63be5 | |||
2aa9b267ab | |||
90338d9600 | |||
5cecf16d4f | |||
21a30f1b6f | |||
613c45ede9 | |||
8743c6a08d | |||
eba0831538 | |||
1ad103c29f | |||
ca37b4c9ac | |||
d3bbf09d12 | |||
f608317eec | |||
c8b9c9bcaa | |||
d638cdcdd3 | |||
46f82a4af3 | |||
42a2642d40 | |||
37840c3844 | |||
28335ef3d8 | |||
78ec5b3322 | |||
ac7e1ab299 | |||
ea60fd0f45 | |||
c291e8c5d9 | |||
f0ac542a7f | |||
a412085785 |
10
.editorconfig
Normal file
@ -0,0 +1,10 @@
|
||||
# See editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
42
.eslintrc.json
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"parser": "babel-eslint",
|
||||
"extends": ["airbnb-base", "prettier"],
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true
|
||||
},
|
||||
"globals": { "Plyr": false, "jQuery": false },
|
||||
"rules": {
|
||||
"no-const-assign": 1,
|
||||
"no-shadow": 0,
|
||||
"no-this-before-super": 1,
|
||||
"no-undef": 1,
|
||||
"no-unreachable": 1,
|
||||
"no-unused-vars": 1,
|
||||
"constructor-super": 1,
|
||||
"valid-typeof": 1,
|
||||
"indent": [2, 4, { "SwitchCase": 1 }],
|
||||
"quotes": [2, "single", "avoid-escape"],
|
||||
"semi": [2, "always"],
|
||||
"eqeqeq": [2, "always"],
|
||||
"one-var": [2, "never"],
|
||||
"comma-dangle": [2, "always-multiline"],
|
||||
"no-restricted-globals": [
|
||||
"error",
|
||||
{
|
||||
"name": "event",
|
||||
"message": "Use local parameter instead."
|
||||
},
|
||||
{
|
||||
"name": "error",
|
||||
"message": "Use local parameter instead."
|
||||
}
|
||||
],
|
||||
"no-param-reassign": [2, { "props": false }],
|
||||
"array-bracket-newline": [2, { "minItems": 2 }],
|
||||
"array-element-newline": [2, { "minItems": 2 }]
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
}
|
||||
}
|
25
.github/issue_template.md
vendored
@ -1,28 +1,17 @@
|
||||
<!---
|
||||
Please use this issue template as it makes replicating and fixing the issue easier!
|
||||
<!---
|
||||
Please use this issue template as it makes replicating and fixing the issue easier!
|
||||
--->
|
||||
|
||||
- [ ] Issue does not already exist
|
||||
- [ ] Issue observed on https://plyr.io
|
||||
|
||||
### Expected behaviour
|
||||
### Expected behaviour
|
||||
|
||||
### Actual behaviour
|
||||
|
||||
### Environment
|
||||
|
||||
- Browser:
|
||||
- Version:
|
||||
- Version:
|
||||
- Operating System:
|
||||
- Version:
|
||||
- Version:
|
||||
|
||||
Players affected:
|
||||
- [ ] HTML5 Video
|
||||
- [ ] HTML5 Audio
|
||||
- [ ] YouTube
|
||||
- [ ] Vimeo
|
||||
|
||||
### Steps to reproduce
|
||||
-
|
||||
|
||||
### Relevant links
|
||||
### Steps to reproduce
|
||||
-
|
10
.github/pull_request_template.md
vendored
@ -1,8 +1,8 @@
|
||||
### Link to related issue (if applicable)
|
||||
|
||||
### Sumary of proposed changes
|
||||
### Summary of proposed changes
|
||||
|
||||
### Task list
|
||||
|
||||
- [ ] Tested on [supported browsers](https://github.com/sampotts/plyr#browser-support)
|
||||
- [ ] Gulp build completed
|
||||
### Checklist
|
||||
- [ ] Use `develop` as the base branch
|
||||
- [ ] Exclude the gulp build from the PR
|
||||
- [ ] Test on [supported browsers](https://github.com/sampotts/plyr#browser-support)
|
||||
|
14
.gitignore
vendored
@ -1,11 +1,11 @@
|
||||
node_modules
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.DS_Store
|
||||
aws.json
|
||||
docs/index.dev.html
|
||||
*.mp4
|
||||
index-dev.html
|
||||
notes.txt
|
||||
*.vtt
|
||||
docs/index.dev.php
|
||||
!dist/blank.mp4
|
||||
index-*.html
|
||||
npm-debug.log
|
||||
*.webm
|
||||
/package-lock.json
|
||||
.idea/
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"html": {
|
||||
"allowed_file_extensions": []
|
||||
},
|
||||
"css": {
|
||||
"allowed_file_extensions": []
|
||||
},
|
||||
"js": {
|
||||
"allowed_file_extensions": []
|
||||
}
|
||||
}
|
55
.jshintrc
@ -1,55 +0,0 @@
|
||||
{
|
||||
// Settings
|
||||
"passfail" : false, // Stop on first error.
|
||||
"maxerr" : 100, // Maximum error before stopping.
|
||||
|
||||
// Predefined globals whom JSHint will ignore.
|
||||
"browser" : true, // Standard browser globals e.g. `window`, `document`.
|
||||
"node" : false,
|
||||
"rhino" : false,
|
||||
"couch" : false,
|
||||
"wsh" : false, // Windows Scripting Host.
|
||||
"jquery" : false,
|
||||
|
||||
// Development.
|
||||
"debug" : true, // Allow debugger statements e.g. browser breakpoints.
|
||||
"devel" : true, // Allow developments statements e.g. `console.log();`.
|
||||
|
||||
// ECMAScript 5.
|
||||
"strict" : false, // Require `use strict` pragma in every file.
|
||||
"globalstrict" : false, // Allow global "use strict" (also enables 'strict').
|
||||
|
||||
// The Good Parts.
|
||||
"asi" : true, // Tolerate Automatic Semicolon Insertion (no semicolons).
|
||||
"laxbreak" : true, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons.
|
||||
"bitwise" : false, // Prohibit bitwise operators (&, |, ^, etc.).
|
||||
"boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments.
|
||||
"curly" : true, // Require {} for every new block or scope.
|
||||
"eqeqeq" : true, // Require triple equals i.e. `===`.
|
||||
"eqnull" : false, // Tolerate use of `== null`.
|
||||
"evil" : false, // Tolerate use of `eval`.
|
||||
"expr" : false, // Tolerate `ExpressionStatement` as Programs.
|
||||
"forin" : false, // Tolerate `for in` loops without `hasOwnPrototype`.
|
||||
"immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );`
|
||||
"latedef" : false, // Prohipit variable use before definition.
|
||||
"loopfunc" : true, // Allow functions to be defined within loops.
|
||||
"noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`.
|
||||
"regexp" : true, // Prohibit `.` and `[^...]` in regular expressions.
|
||||
"regexdash" : false, // Tolerate unescaped last dash i.e. `[-...]`.
|
||||
"scripturl" : true, // Tolerate script-targeted URLs.
|
||||
"shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`.
|
||||
"supernew" : false, // Tolerate `new function () { ... };` and `new Object;`.
|
||||
"undef" : true, // Require all non-global variables be declared before they are used.
|
||||
|
||||
// Personal styling preferences.
|
||||
"newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`.
|
||||
"noempty" : true, // Prohibit use of empty blocks.
|
||||
"nonew" : true, // Prohibit use of constructors for side-effects.
|
||||
"nomen" : true, // Prohibit use of initial or trailing underbars in names.
|
||||
"onevar" : false, // Allow only one `var` statement per function.
|
||||
"plusplus" : false, // Prohibit use of `++` & `--`.
|
||||
"sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`.
|
||||
"trailing" : true, // Prohibit trailing whitespaces.
|
||||
"white" : true, // Check against strict whitespace and indentation rules.
|
||||
"indent" : 4 // Specify indentation spacing
|
||||
}
|
4
.npmignore
Normal file
@ -0,0 +1,4 @@
|
||||
demo
|
||||
.github
|
||||
.vscode
|
||||
*.code-workspace
|
7
.prettierrc
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"useTabs": false,
|
||||
"tabWidth": 4,
|
||||
"printWidth": 160,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
25
.stylelintrc.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"plugins": ["stylelint-selector-bem-pattern", "stylelint-scss"],
|
||||
"extends": ["stylelint-config-recommended", "stylelint-config-sass-guidelines", "stylelint-config-prettier"],
|
||||
"rules": {
|
||||
"selector-class-pattern": null,
|
||||
"selector-no-qualifying-type": [
|
||||
true,
|
||||
{
|
||||
"ignore": ["attribute", "class"]
|
||||
}
|
||||
],
|
||||
"string-no-newline": null,
|
||||
"indentation": 4,
|
||||
"string-quotes": "single",
|
||||
"max-nesting-depth": 2,
|
||||
"plugin/selector-bem-pattern": {
|
||||
"preset": "bem",
|
||||
"componentName": "(([a-z0-9]+(?!-$)-?)+)",
|
||||
"componentSelectors": {
|
||||
"initial": "\\.{componentName}(((__|--)(([a-z0-9\\[\\]'=]+(?!-$)-?)+))+)?$"
|
||||
},
|
||||
"ignoreSelectors": [".*\\.has-.*", ".*\\.is-.*"]
|
||||
}
|
||||
}
|
||||
}
|
7
.travis.yml
Normal file
@ -0,0 +1,7 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 'lts/*'
|
||||
|
||||
script:
|
||||
- npm run lint
|
||||
- npm run build
|
12
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||
"dbaeumer.vscode-eslint",
|
||||
"wix.vscode-import-cost",
|
||||
"esbenp.prettier-vscode",
|
||||
"shinnn.stylelint",
|
||||
"wayou.vscode-todo-highlight"
|
||||
]
|
||||
}
|
15
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost/dev/plyr/demo",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
3
.vscode/settings.json
vendored
@ -1,2 +1 @@
|
||||
{
|
||||
}
|
||||
{}
|
52
CONTRIBUTING.md
Normal file
@ -0,0 +1,52 @@
|
||||
# Contributing
|
||||
|
||||
We welcome bug reports, feature requests and pull requests. If you want to help us out, please follow these guidelines, in order to avoid redundant work.
|
||||
|
||||
## Reporting issues
|
||||
|
||||
Our GitHub issue tracker is for bug reports and feature requests. Don't create support issues here. Use [Stack Overflow](https://stackoverflow.com/) or [our Slack](https://bit.ly/plyr-chat) for that.
|
||||
|
||||
Please verify that your issue hasn't already been answered by our FAQ (https://github.com/sampotts/plyr/wiki/FAQ), or that there isn't already an open issue for it.
|
||||
|
||||
When applicable, check that your problem doesn't happen without Plyr (see [FAQ#1](https://github.com/sampotts/plyr/wiki/FAQ#1-does-plyr-work-with--)).
|
||||
|
||||
Verify that you are following the documentation, are using the latest version of Plyr, and aren't getting any errors in your own code, causing the issues.
|
||||
|
||||
Describe the issue as detailed as possible, answering these questions:
|
||||
|
||||
* Does it happen only with specific options and/or specific browsers?
|
||||
* Does is happen only with HTML5 video, audio, youtube, vimeo or a specific library?
|
||||
* Does the issue happen on [our demo](https://plyr.io/)? If not, please recreate it with a **minimal** example online. You can use our Codepen templates to get started:
|
||||
* [HTML5 video](https://codepen.io/pen?template=bKeqpr)
|
||||
* [HTML5 audio](https://codepen.io/pen?template=rKLywR)
|
||||
* [YouTube](https://codepen.io/pen?template=GGqbbJ)
|
||||
* [Vimeo](https://codepen.io/pen?template=bKeXNq)
|
||||
* [Dash.js integration](https://codepen.io/pen?template=zaBgBy)
|
||||
* [Hls.js integration](https://codepen.io/pen?template=oyLKQb)
|
||||
* [Shaka Player integration](https://codepen.io/pen?template=ZRpzZO)
|
||||
|
||||
It's important that you keep the issue description and replication demo **minimal**. If your implementation is using a framework, library or custom methods, which aren't needed to reproduce the issue, this makes it harder to debug and understand the issue. While it may be relevant to bring this up (ex: "I need Plyr to trigger the event sooner or it breaks Framework X") it also means that the person who is trying to fix the issue either has to know or learn your frameworks, libraries and custom methods, or that no one will try to fix your issue because it's too much work.
|
||||
|
||||
In order to keep things on topic and to avoid bothering people with github notifications, please don't combine multiple problems or bugs into one issue, don't comment on issues unless your comment is related to that issue, and don't post "+1" or "I agree" type of comments. Use the emojis instead.
|
||||
|
||||
Last but not least: Keep a civil tone in issues and comments. Non-constructive comments may be removed.
|
||||
|
||||
## Requesting features and improvements
|
||||
|
||||
If you are missing something in Plyr, you can create a GitHub issue for this as well. Since we prioritize fixing bugs first, and may have a lot of other suggestions and architectural changes to work on as well, these may not be at the top of our list. If it's important or urgent to you, you may want to first ensure it's something we want to have in Plyr, and then contribute it as a pull request.
|
||||
|
||||
## Contributing features and documentation
|
||||
|
||||
* Fork Plyr, and create a new branch in your fork, based on the **develop** branch
|
||||
|
||||
* To test locally, you can use the demo. First make sure you have installed the dependencies with `npm install` or `yarn`. Run `gulp` to build while you are working, and run a local server from the repository root directory. If you have Python installed, this command should work: `python -m SimpleHTTPServer 8080`. Then go to `http://localhost:8080/demo/`
|
||||
|
||||
* Develop and test your modifications.
|
||||
|
||||
* Preferably commit your changes as independent logical chunks, with meaningful messages. Make sure you do not commit unnecessary files or changes, such as logging or breakpoints you added for testing, and the build output.
|
||||
|
||||
* If your modifications changes the documented behavior or add new features, document these changes in readme.md.
|
||||
|
||||
* When finished, push the changes to your GitHub repository and send a pull request to **develop**. Describe what your PR does.
|
||||
|
||||
* If the Travis build fails, or if you get a code review with change requests, you can fix these by pushing new or rebased commits to the branch.
|
@ -6,7 +6,7 @@
|
||||
"Audio",
|
||||
"Video",
|
||||
"HTML5 Audio",
|
||||
"HTml5 Video"
|
||||
"HTML5 Video"
|
||||
],
|
||||
"authors": [
|
||||
"Sam Potts <sam@potts.es>"
|
||||
@ -30,4 +30,4 @@
|
||||
"url": "git://github.com/sampotts/plyr.git"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
20
bundles.json
@ -1,24 +1,20 @@
|
||||
{
|
||||
"plyr": {
|
||||
"less": {
|
||||
"plyr.css": ["src/less/plyr.less"]
|
||||
},
|
||||
"scss": {
|
||||
"plyr.css": ["src/scss/plyr.scss"]
|
||||
"sass": {
|
||||
"plyr.css": "src/sass/plyr.scss"
|
||||
},
|
||||
"js": {
|
||||
"plyr.js": ["src/js/plyr.js"]
|
||||
"plyr.js": "src/js/plyr.js",
|
||||
"plyr.polyfilled.js": "src/js/plyr.polyfilled.js"
|
||||
}
|
||||
},
|
||||
"demo": {
|
||||
"less": {
|
||||
"demo.css": ["demo/src/less/demo.less"]
|
||||
"sass": {
|
||||
"demo.css": "demo/src/sass/bundles/demo.scss",
|
||||
"error.css": "demo/src/sass/bundles/error.scss"
|
||||
},
|
||||
"js": {
|
||||
"demo.js": [
|
||||
"demo/src/js/lib/classlist.js",
|
||||
"demo/src/js/main.js"
|
||||
]
|
||||
"demo.js": "demo/src/js/demo.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
939
changelog.md
208
controls.md
@ -1,27 +1,73 @@
|
||||
# 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. You can pass the following to the `controls` option:
|
||||
|
||||
## Internationalization using default controls
|
||||
* `Array` of options (this builds the default controls based on your choices)
|
||||
* `String` containing the desired HTML
|
||||
* `Function` that will be executed and should return one of the above
|
||||
|
||||
## Using default controls
|
||||
|
||||
If you want to use the standard controls as they are, you don't need to pass any options. If you want to turn on off controls, here's the full list:
|
||||
|
||||
```javascript
|
||||
controls: [
|
||||
'play-large', // The large play button in the center
|
||||
'restart', // Restart playback
|
||||
'rewind', // Rewind by the seek time (default 10 seconds)
|
||||
'play', // Play/pause playback
|
||||
'fast-forward', // Fast forward by the seek time (default 10 seconds)
|
||||
'progress', // The progress bar and scrubber for playback and buffering
|
||||
'current-time', // The current time of playback
|
||||
'duration', // The full duration of the media
|
||||
'mute', // Toggle mute
|
||||
'volume', // Volume control
|
||||
'captions', // Toggle captions
|
||||
'settings', // Settings menu
|
||||
'pip', // Picture-in-picture (currently Safari only)
|
||||
'airplay', // Airplay (currently Safari only)
|
||||
'fullscreen', // Toggle fullscreen
|
||||
];
|
||||
```
|
||||
|
||||
### Internationalization using default controls
|
||||
|
||||
You can provide an `i18n` object as one of your options when initialising the plugin which we be used when rendering the controls.
|
||||
|
||||
### Example
|
||||
#### Example
|
||||
|
||||
```javascript
|
||||
i18n: {
|
||||
restart: "Restart",
|
||||
rewind: "Rewind {seektime} secs",
|
||||
play: "Play",
|
||||
pause: "Pause",
|
||||
forward: "Forward {seektime} secs",
|
||||
buffered: "buffered",
|
||||
currentTime: "Current time",
|
||||
duration: "Duration",
|
||||
volume: "Volume",
|
||||
toggleMute: "Toggle Mute",
|
||||
toggleCaptions: "Toggle Captions",
|
||||
toggleFullscreen: "Toggle Fullscreen"
|
||||
restart: 'Restart',
|
||||
rewind: 'Rewind {seektime} secs',
|
||||
play: 'Play',
|
||||
pause: 'Pause',
|
||||
fastForward: 'Forward {seektime} secs',
|
||||
seek: 'Seek',
|
||||
played: 'Played',
|
||||
buffered: 'Buffered',
|
||||
currentTime: 'Current time',
|
||||
duration: 'Duration',
|
||||
volume: 'Volume',
|
||||
mute: 'Mute',
|
||||
unmute: 'Unmute',
|
||||
enableCaptions: 'Enable captions',
|
||||
disableCaptions: 'Disable captions',
|
||||
enterFullscreen: 'Enter fullscreen',
|
||||
exitFullscreen: 'Exit fullscreen',
|
||||
frameTitle: 'Player for {title}',
|
||||
captions: 'Captions',
|
||||
settings: 'Settings',
|
||||
speed: 'Speed',
|
||||
normal: 'Normal',
|
||||
quality: 'Quality',
|
||||
loop: 'Loop',
|
||||
start: 'Start',
|
||||
end: 'End',
|
||||
all: 'All',
|
||||
reset: 'Reset',
|
||||
disabled: 'Disabled',
|
||||
advertisement: 'Ad',
|
||||
}
|
||||
```
|
||||
|
||||
@ -29,85 +75,77 @@ Note: `{seektime}` will be replaced with your configured seek time or the defaul
|
||||
|
||||
## Using custom HTML
|
||||
|
||||
You can specify the HTML for the controls using the `html` option.
|
||||
You can specify the HTML as a `String` or your `Function` return for the controls using the `controls` 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 if you change any.
|
||||
|
||||
You need to add several placeholders to your html template that are replaced when rendering:
|
||||
You need to add several placeholders to your HTML template that are replaced when rendering:
|
||||
|
||||
- `{id}` - the dynamically generated ID for the player (for form controls)
|
||||
- `{seektime}` - the seek time specified in options for fast forward and rewind
|
||||
- `{title}` - the title of your media, if specified
|
||||
* `{id}` - the dynamically generated ID for the player (for form controls)
|
||||
* `{seektime}` - the seek time specified in options for fast forward and rewind
|
||||
* `{title}` - the title of your media, if specified
|
||||
|
||||
You can include only the controls you need when specifying custom html.
|
||||
### Limitations
|
||||
|
||||
* Currently the settings menus are not supported with custom controls HTML
|
||||
* AirPlay and PiP buttons can be added but you will have to manage feature detection
|
||||
|
||||
### Example
|
||||
|
||||
This is an example `html` option with all controls.
|
||||
Here's an example of custom controls markup (this is just all default controls shown).
|
||||
|
||||
```javascript
|
||||
var controls = ["<div class='plyr__controls'>",
|
||||
"<button type='button' data-plyr='restart'>",
|
||||
"<svg><use xlink:href='#plyr-restart'></use></svg>",
|
||||
"<span class='plyr__sr-only'>Restart</span>",
|
||||
"</button>",
|
||||
"<button type='button' data-plyr='rewind'>",
|
||||
"<svg><use xlink:href='#plyr-rewind'></use></svg>",
|
||||
"<span class='plyr__sr-only'>Rewind {seektime} secs</span>",
|
||||
"</button>",
|
||||
"<button type='button' data-plyr='play'>",
|
||||
"<svg><use xlink:href='#plyr-play'></use></svg>",
|
||||
"<span class='plyr__sr-only'>Play</span>",
|
||||
"</button>",
|
||||
"<button type='button' data-plyr='pause'>",
|
||||
"<svg><use xlink:href='#plyr-pause'></use></svg>",
|
||||
"<span class='plyr__sr-only'>Pause</span>",
|
||||
"</button>",
|
||||
"<button type='button' data-plyr='fast-forward'>",
|
||||
"<svg><use xlink:href='#plyr-fast-forward'></use></svg>",
|
||||
"<span class='plyr__sr-only'>Forward {seektime} secs</span>",
|
||||
"</button>",
|
||||
"<span class='plyr__progress'>",
|
||||
"<label for='seek{id}' class='plyr__sr-only'>Seek</label>",
|
||||
"<input id='seek{id}' class='plyr__progress--seek' type='range' min='0' max='100' step='0.1' value='0' data-plyr='seek'>",
|
||||
"<progress class='plyr__progress--played' max='100' value='0' role='presentation'></progress>",
|
||||
"<progress class='plyr__progress--buffer' max='100' value='0'>",
|
||||
"<span>0</span>% buffered",
|
||||
"</progress>",
|
||||
"<span class='plyr__tooltip'>00:00</span>",
|
||||
"</span>",
|
||||
"<span class='plyr__time'>",
|
||||
"<span class='plyr__sr-only'>Current time</span>",
|
||||
"<span class='plyr__time--current'>00:00</span>",
|
||||
"</span>",
|
||||
"<span class='plyr__time'>",
|
||||
"<span class='plyr__sr-only'>Duration</span>",
|
||||
"<span class='plyr__time--duration'>00:00</span>",
|
||||
"</span>",
|
||||
"<button type='button' data-plyr='mute'>",
|
||||
"<svg class='icon--muted'><use xlink:href='#plyr-muted'></use></svg>",
|
||||
"<svg><use xlink:href='#plyr-volume'></use></svg>",
|
||||
"<span class='plyr__sr-only'>Toggle Mute</span>",
|
||||
"</button>",
|
||||
"<span class='plyr__volume'>",
|
||||
"<label for='volume{id}' class='plyr__sr-only'>Volume</label>",
|
||||
"<input id='volume{id}' class='plyr__volume--input' type='range' min='0' max='10' value='5' data-plyr='volume'>",
|
||||
"<progress class='plyr__volume--display' max='10' value='0' role='presentation'></progress>",
|
||||
"</span>",
|
||||
"<button type='button' data-plyr='captions'>",
|
||||
"<svg class='icon--captions-on'><use xlink:href='#plyr-captions-on'></use></svg>",
|
||||
"<svg><use xlink:href='#plyr-captions-off'></use></svg>",
|
||||
"<span class='plyr__sr-only'>Toggle Captions</span>",
|
||||
"</button>",
|
||||
"<button type='button' data-plyr='fullscreen'>",
|
||||
"<svg class='icon--exit-fullscreen'><use xlink:href='#plyr-exit-fullscreen'></use></svg>",
|
||||
"<svg><use xlink:href='#plyr-enter-fullscreen'></use></svg>",
|
||||
"<span class='plyr__sr-only'>Toggle Fullscreen</span>",
|
||||
"</button>",
|
||||
"</div>"].join("");
|
||||
const controls = `
|
||||
<div class="plyr__controls">
|
||||
<button type="button" class="plyr__control" data-plyr="restart">
|
||||
<svg role="presentation"><use xlink:href="#plyr-restart"></use></svg>
|
||||
<span class="plyr__tooltip" role="tooltip">Restart</span>
|
||||
</button>
|
||||
<button type="button" class="plyr__control" data-plyr="rewind">
|
||||
<svg role="presentation"><use xlink:href="#plyr-rewind"></use></svg>
|
||||
<span class="plyr__tooltip" role="tooltip">Rewind {seektime} secs</span>
|
||||
</button>
|
||||
<button type="button" class="plyr__control" aria-pressed="false" aria-label="Play, {title}" data-plyr="play">
|
||||
<svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-pause"></use></svg>
|
||||
<svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-play"></use></svg>
|
||||
<span class="label--pressed plyr__tooltip" role="tooltip">Pause</span>
|
||||
<span class="label--not-pressed plyr__tooltip" role="tooltip">Play</span>
|
||||
</button>
|
||||
<button type="button" class="plyr__control" data-plyr="fast-forward">
|
||||
<svg role="presentation"><use xlink:href="#plyr-fast-forward"></use></svg>
|
||||
<span class="plyr__tooltip" role="tooltip">Forward {seektime} secs</span>
|
||||
</button>
|
||||
<div class="plyr__progress">
|
||||
<input data-plyr="seek" type="range" min="0" max="100" step="0.01" value="0" aria-label="Seek">
|
||||
<progress class="plyr__progress__buffer" min="0" max="100" value="0">% buffered</progress>
|
||||
<span role="tooltip" class="plyr__tooltip">00:00</span>
|
||||
</div>
|
||||
<div class="plyr__time plyr__time--current" aria-label="Current time">00:00</div>
|
||||
<div class="plyr__time plyr__time--duration" aria-label="Duration">00:00</div>
|
||||
<button type="button" class="plyr__control" aria-pressed="false" aria-label="Mute" data-plyr="mute">
|
||||
<svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-muted"></use></svg>
|
||||
<svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-volume"></use></svg>
|
||||
<span class="label--pressed plyr__tooltip" role="tooltip">Unmute</span>
|
||||
<span class="label--not-pressed plyr__tooltip" role="tooltip">Mute</span>
|
||||
</button>
|
||||
<div class="plyr__volume">
|
||||
<input data-plyr="volume" type="range" min="0" max="1" step="0.05" value="1" autocomplete="off" aria-label="Volume">
|
||||
</div>
|
||||
<button type="button" class="plyr__control" aria-pressed="true" aria-label="Enable captions" data-plyr="captions">
|
||||
<svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-captions-on"></use></svg>
|
||||
<svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-captions-off"></use></svg>
|
||||
<span class="label--pressed plyr__tooltip" role="tooltip">Disable captions</span>
|
||||
<span class="label--not-pressed plyr__tooltip" role="tooltip">Enable captions</span>
|
||||
</button>
|
||||
<button type="button" class="plyr__control" aria-pressed="false" aria-label="Enter fullscreen" data-plyr="fullscreen">
|
||||
<svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-exit-fullscreen"></use></svg>
|
||||
<svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-enter-fullscreen"></use></svg>
|
||||
<span class="label--pressed plyr__tooltip" role="tooltip">Exit fullscreen</span>
|
||||
<span class="label--not-pressed plyr__tooltip" role="tooltip">Enter fullscreen</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Setup the player
|
||||
plyr.setup('.js-player', {
|
||||
html: controls
|
||||
});
|
||||
const player = new Plyr('#player', { controls });
|
||||
```
|
||||
|
2
demo/dist/demo.css
vendored
4373
demo/dist/demo.js
vendored
1
demo/dist/demo.js.map
vendored
Normal file
2
demo/dist/demo.min.js
vendored
Normal file
1
demo/dist/demo.min.js.map
vendored
Normal file
1
demo/dist/demo.svg
vendored
@ -1 +0,0 @@
|
||||
<?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>
|
Before Width: | Height: | Size: 1.7 KiB |
1
demo/dist/error.css
vendored
Normal file
@ -6,19 +6,25 @@
|
||||
<title>Doh. Looks like something went wrong.</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Icons -->
|
||||
<link rel="icon" href="https://cdn.plyr.io/static/icons/favicon.ico">
|
||||
<link rel="icon" type="image/png" href="https://cdn.plyr.io/static/icons/32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="https://cdn.plyr.io/static/icons/16x16.png" sizes="16x16">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="https://cdn.plyr.io/static/icons/180x180.png">
|
||||
|
||||
<!-- Docs styles -->
|
||||
<link rel="stylesheet" href="dist/demo.css">
|
||||
<link rel="stylesheet" href="dist/error.css?v=2">
|
||||
|
||||
<!-- Preload -->
|
||||
<link rel="preload" as="font" crossorigin type="font/woff2" href="https://cdn.plyr.io/static/fonts/avenir-medium.woff2">
|
||||
<link rel="preload" as="font" crossorigin type="font/woff2" href="https://cdn.plyr.io/static/fonts/avenir-bold.woff2">
|
||||
<link rel="preload" as="font" crossorigin type="font/woff2" href="https://cdn.plyr.io/static/fonts/gordita-medium.woff2">
|
||||
<link rel="preload" as="font" crossorigin type="font/woff2" href="https://cdn.plyr.io/static/fonts/gordita-bold.woff2">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main>
|
||||
<h1>Doh.</h1>
|
||||
<p>Looks like something went wrong.</p>
|
||||
<a href="http://plyr.io" class="btn btn--primary">Back to plyr.io</a>
|
||||
<a href="javascript:history.back()" class="button">Go back</a>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
|
227
demo/index.html
@ -3,101 +3,188 @@
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Plyr - A simple HTML5 media player</title>
|
||||
<meta name="description" content="A simple HTML5 media player with custom controls and WebVTT captions.">
|
||||
<title>Plyr - A simple, customizable HTML5 Video, Audio, YouTube and Vimeo player</title>
|
||||
<meta name="description" property="og:description" content="A simple HTML5 media player with custom controls and WebVTT captions.">
|
||||
<meta name="author" content="Sam Potts">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="../dist/plyr.css">
|
||||
<!-- Icons -->
|
||||
<link rel="icon" href="https://cdn.plyr.io/static/icons/favicon.ico">
|
||||
<link rel="icon" type="image/png" href="https://cdn.plyr.io/static/icons/32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="https://cdn.plyr.io/static/icons/16x16.png" sizes="16x16">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="https://cdn.plyr.io/static/icons/180x180.png">
|
||||
|
||||
<!-- Opengraph -->
|
||||
<meta property="og:title" content="Plyr - A simple, customizable HTML5 Video, Audio, YouTube and Vimeo player">
|
||||
<meta property="og:site_name" content="Plyr">
|
||||
<meta property="og:url" content="https://plyr.io">
|
||||
<meta property="og:image" content="https://cdn.plyr.io/static/icons/1200x630.png">
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:site" content="@sam_potts">
|
||||
<meta name="twitter:creator" content="@sam_potts">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
|
||||
<!-- Docs styles -->
|
||||
<link rel="stylesheet" href="dist/demo.css">
|
||||
<link rel="stylesheet" href="dist/demo.css?v=2">
|
||||
|
||||
<!-- Preload -->
|
||||
<link rel="preload" as="font" crossorigin type="font/woff2" href="https://cdn.plyr.io/static/fonts/avenir-medium.woff2">
|
||||
<link rel="preload" as="font" crossorigin type="font/woff2" href="https://cdn.plyr.io/static/fonts/avenir-bold.woff2">
|
||||
<link rel="preload" as="font" crossorigin type="font/woff2" href="https://cdn.plyr.io/static/fonts/gordita-medium.woff2">
|
||||
<link rel="preload" as="font" crossorigin type="font/woff2" href="https://cdn.plyr.io/static/fonts/gordita-bold.woff2">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<h1>Plyr</h1>
|
||||
<p>A simple, accessible HTML5 media player by <a href="https://twitter.com/sam_potts" target="_blank">@sam_potts</a></p>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://github.com/sampotts/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>
|
||||
<div class="grid">
|
||||
<header>
|
||||
<h1>Plyr</h1>
|
||||
<p>A simple, accessible and customisable media player for
|
||||
<button type="button" class="faux-link" data-source="video">
|
||||
<svg class="icon">
|
||||
<title>HTML5</title>
|
||||
<path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path>
|
||||
</svg>Video</button>,
|
||||
<button type="button" class="faux-link" data-source="audio">
|
||||
<svg class="icon">
|
||||
<title>HTML5</title>
|
||||
<path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path>
|
||||
</svg>Audio</button>,
|
||||
<button type="button" class="faux-link" data-source="youtube">
|
||||
<svg class="icon" role="presentation">
|
||||
<title>YouTube</title>
|
||||
<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"></path>
|
||||
</svg>YouTube</button> and
|
||||
<button type="button" class="faux-link" data-source="vimeo">
|
||||
<svg class="icon" role="presentation">
|
||||
<title>Vimeo</title>
|
||||
<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"></path>
|
||||
</svg>Vimeo</button>
|
||||
</p>
|
||||
|
||||
<main role="main" id="main">
|
||||
<nav class="btn__bar">
|
||||
<ul>
|
||||
<li class="active">
|
||||
<button type="button" class="btn" data-source="video">Video</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="btn" data-source="audio">Audio</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="btn btn--youtube" data-source="youtube"><svg class="icon"><use xlink:href="#icon-youtube"/></svg>YouTube</button>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="btn btn--vimeo" data-source="vimeo"><svg class="icon"><use xlink:href="#icon-vimeo"/></svg>Vimeo</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<section>
|
||||
<video poster="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg?v1" controls crossorigin>
|
||||
<p>Premium video monitization from
|
||||
<a href="https://vi.ai/publisher-video-monetization/?aid=plyrio" target="_blank" class="no-border">
|
||||
<img src="https://cdn.plyr.io/static/vi-logo-24x24.svg" alt="ai.vi">
|
||||
<span class="sr-only">ai.vi</span>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<div class="call-to-action">
|
||||
<span class="button--with-count">
|
||||
<a href="https://github.com/sampotts/plyr" target="_blank" class="button" data-shr-network="github">
|
||||
<svg class="icon" role="presentation">
|
||||
<title>GitHub</title>
|
||||
<path 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"></path>
|
||||
</svg>
|
||||
Download on GitHub
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<video controls crossorigin playsinline poster="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg" id="player">
|
||||
<!-- Video files -->
|
||||
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4" type="video/mp4">
|
||||
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.webm" type="video/webm">
|
||||
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4" type="video/mp4" size="576">
|
||||
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4" type="video/mp4" size="720">
|
||||
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1080p.mp4" type="video/mp4" size="1080">
|
||||
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1440p.mp4" type="video/mp4" size="1440">
|
||||
|
||||
<!-- Text track file -->
|
||||
<!-- Caption files -->
|
||||
<track kind="captions" label="English" srclang="en" src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt"
|
||||
default>
|
||||
<track kind="captions" label="Français" srclang="fr" src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt">
|
||||
|
||||
<!-- Fallback for browsers that don't support the <video> element -->
|
||||
<a href="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4" download>Download</a>
|
||||
<a href="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4" download>Download</a>
|
||||
</video>
|
||||
|
||||
<ul>
|
||||
<li class="plyr__cite plyr__cite--video"><small><a href="http://viewfromabluemoon.com/" target="_blank">View From A Blue Moon</a> © Brainfarm</small></li>
|
||||
<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>
|
||||
<li class="plyr__cite plyr__cite--youtube"><small><a href="https://www.youtube.com/watch?v=bTqVqk7FSmY" target="_blank">View From A Blue Moon</a> on <span class="color--youtube"><svg class="icon"><use xlink:href="#icon-youtube"/></svg>YouTube</span></small></li>
|
||||
<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></li>
|
||||
<li class="plyr__cite plyr__cite--video" hidden>
|
||||
<small>
|
||||
<svg class="icon">
|
||||
<title>HTML5</title>
|
||||
<path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path>
|
||||
</svg>
|
||||
<a href="https://itunes.apple.com/au/movie/view-from-a-blue-moon/id1041586323" target="_blank">View From A Blue Moon</a> © Brainfarm
|
||||
</small>
|
||||
</li>
|
||||
<li class="plyr__cite plyr__cite--audio" hidden>
|
||||
<small>
|
||||
<svg class="icon" title="HTML5">
|
||||
<title>HTML5</title>
|
||||
<path d="M14.738.326C14.548.118 14.28 0 14 0H2c-.28 0-.55.118-.738.326S.98.81 1.004 1.09l1 11c.03.317.208.603.48.767l5 3c.16.095.338.143.516.143s.356-.048.515-.143l5-3c.273-.164.452-.45.48-.767l1-11c.026-.28-.067-.557-.257-.764zM12 4H6v2h6v5.72l-4 1.334-4-1.333V9h2v1.28l2 .666 2-.667V8H4V2h8v2z"></path>
|
||||
</svg>
|
||||
<a href="http://www.kishibashi.com/" target="_blank">Kishi Bashi – “It All Began With A Burst”</a> © Kishi Bashi
|
||||
</small>
|
||||
</li>
|
||||
<li class="plyr__cite plyr__cite--youtube" hidden>
|
||||
<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" role="presentation">
|
||||
<title>YouTube</title>
|
||||
<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"></path>
|
||||
</svg>YouTube
|
||||
</span>
|
||||
</small>
|
||||
</li>
|
||||
<li class="plyr__cite plyr__cite--vimeo" hidden>
|
||||
<small>
|
||||
<a href="https://vimeo.com/76979871" target="_blank">The New Vimeo Player</a> on
|
||||
<span class="color--vimeo">
|
||||
<svg class="icon" role="presentation">
|
||||
<title>Vimeo</title>
|
||||
<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"></path>
|
||||
</svg>Vimeo
|
||||
</span>
|
||||
</small>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</main>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<aside>
|
||||
<svg class="icon">
|
||||
<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"></path>
|
||||
</svg>
|
||||
<p>If you think Plyr's good,
|
||||
<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" data-shr-network="twitter">tweet it</a>
|
||||
</p>
|
||||
</aside>
|
||||
|
||||
<!-- Polyfills -->
|
||||
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=es6,Array.prototype.includes,CustomEvent,Object.entries,Object.values,URL"
|
||||
crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Plyr core script -->
|
||||
<script src="../dist/plyr.js"></script>
|
||||
|
||||
<!-- Docs script -->
|
||||
<script src="dist/demo.js"></script>
|
||||
|
||||
<!-- Rangetouch to fix <input type="range"> on touch devices (see https://rangetouch.com) -->
|
||||
<script src="https://cdn.rangetouch.com/1.0.1/rangetouch.js" async></script>
|
||||
<script src="../dist/plyr.js" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Sharing libary (https://shr.one) -->
|
||||
<script src="https://cdn.shr.one/1.0.1/shr.js"></script>
|
||||
<script>
|
||||
if (window.shr) { window.shr.setup({ count: { classname: 'btn__count' } }); }
|
||||
</script>
|
||||
<script src="https://cdn.shr.one/1.0.1/shr.js" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Rangetouch to fix <input type="range"> on touch devices (see https://rangetouch.com) -->
|
||||
<script src="https://cdn.rangetouch.com/1.0.1/rangetouch.js" async crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Docs script -->
|
||||
<script src="dist/demo.js" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
29
demo/media/View_From_A_Blue_Moon_Trailer-HD.en.vtt
Normal file
@ -0,0 +1,29 @@
|
||||
WEBVTT FILE
|
||||
|
||||
1
|
||||
00:00:09.500 --> 00:00:12.000
|
||||
The ocean floor rises 5 miles to the shores
|
||||
|
||||
2
|
||||
00:00:12.001 --> 00:00:16.500
|
||||
of what people call, the seven mile miracle
|
||||
|
||||
3
|
||||
00:00:25.500 --> 00:00:28.000
|
||||
What would it be like to be born on this island?
|
||||
|
||||
4
|
||||
00:00:32.500 --> 00:00:34.500
|
||||
To grow up on these shores
|
||||
|
||||
5
|
||||
00:00:37.500 --> 00:00:40.000
|
||||
To witness this water, every day
|
||||
|
||||
6
|
||||
00:00:43.500 --> 00:00:46.000
|
||||
You're about to meet someone, who did
|
||||
|
||||
7
|
||||
00:02:45.500 --> 00:02:49.000
|
||||
This is a film about John John Florence
|
29
demo/media/View_From_A_Blue_Moon_Trailer-HD.fr.vtt
Normal file
@ -0,0 +1,29 @@
|
||||
WEBVTT FILE
|
||||
|
||||
1
|
||||
00:00:09.500 --> 00:00:12.000
|
||||
Le fond de l'océan monte 5 miles des rives
|
||||
|
||||
2
|
||||
00:00:12.001 --> 00:00:16.500
|
||||
de ce que les gens appellent le miracle de sept mile
|
||||
|
||||
3
|
||||
00:00:25.500 --> 00:00:28.000
|
||||
Que serait-il d'être né sur cette île?
|
||||
|
||||
4
|
||||
00:00:32.500 --> 00:00:34.500
|
||||
Pour grandir sur ces rivages
|
||||
|
||||
5
|
||||
00:00:37.500 --> 00:00:40.000
|
||||
Pour assister à cette eau, tous les jours
|
||||
|
||||
6
|
||||
00:00:43.500 --> 00:00:46.000
|
||||
Vous êtes sur le point de rencontrer quelqu'un, qui ne
|
||||
|
||||
7
|
||||
00:02:45.500 --> 00:02:49.000
|
||||
Ceci est un film sur John John Florence
|
BIN
demo/media/View_From_A_Blue_Moon_Trailer-HD.jpg
Normal file
After Width: | Height: | Size: 154 KiB |
327
demo/src/js/demo.js
Normal file
@ -0,0 +1,327 @@
|
||||
// ==========================================================================
|
||||
// Plyr.io demo
|
||||
// This code is purely for the https://plyr.io website
|
||||
// Please see readme.md in the root or github.com/sampotts/plyr
|
||||
// ==========================================================================
|
||||
|
||||
import Raven from 'raven-js';
|
||||
|
||||
(() => {
|
||||
const isLive = window.location.host === 'plyr.io';
|
||||
|
||||
// Raven / Sentry
|
||||
// For demo site (https://plyr.io) only
|
||||
if (isLive) {
|
||||
Raven.config('https://d4ad9866ad834437a4754e23937071e4@sentry.io/305555').install();
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
Raven.context(() => {
|
||||
if (window.shr) {
|
||||
window.shr.setup({
|
||||
count: {
|
||||
classname: 'button__count',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Setup tab focus
|
||||
const tabClassName = 'tab-focus';
|
||||
|
||||
// Remove class on blur
|
||||
document.addEventListener('focusout', event => {
|
||||
event.target.classList.remove(tabClassName);
|
||||
});
|
||||
|
||||
// Add classname to tabbed elements
|
||||
document.addEventListener('keydown', event => {
|
||||
if (event.keyCode !== 9) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delay the adding of classname until the focus has changed
|
||||
// This event fires before the focusin event
|
||||
setTimeout(() => {
|
||||
document.activeElement.classList.add(tabClassName);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
// Setup the player
|
||||
const player = new Plyr('#player', {
|
||||
debug: true,
|
||||
title: 'View From A Blue Moon',
|
||||
iconUrl: '../dist/plyr.svg',
|
||||
keyboard: {
|
||||
global: true,
|
||||
},
|
||||
tooltips: {
|
||||
controls: true,
|
||||
},
|
||||
/* controls: [
|
||||
'play-large',
|
||||
'restart',
|
||||
'rewind',
|
||||
'play',
|
||||
'fast-forward',
|
||||
'progress',
|
||||
'current-time',
|
||||
'duration',
|
||||
'mute',
|
||||
'volume',
|
||||
'captions',
|
||||
'settings',
|
||||
'pip',
|
||||
'airplay',
|
||||
'fullscreen',
|
||||
], */
|
||||
/* i18n: {
|
||||
restart: '重新開始',
|
||||
rewind: '快退{seektime}秒',
|
||||
play: '播放',
|
||||
pause: '暫停',
|
||||
fastForward: '快進{seektime}秒',
|
||||
seek: '尋求',
|
||||
played: '發揮',
|
||||
buffered: '緩衝的',
|
||||
currentTime: '當前時間戳',
|
||||
duration: '長短',
|
||||
volume: '音量',
|
||||
mute: '靜音',
|
||||
unmute: '取消靜音',
|
||||
enableCaptions: '開啟字幕',
|
||||
disableCaptions: '關閉字幕',
|
||||
enterFullscreen: '進入全螢幕',
|
||||
exitFullscreen: '退出全螢幕',
|
||||
frameTitle: '球員為{title}',
|
||||
captions: '字幕',
|
||||
settings: '設定',
|
||||
speed: '速度',
|
||||
normal: '正常',
|
||||
quality: '質量',
|
||||
loop: '循環',
|
||||
start: 'Start',
|
||||
end: 'End',
|
||||
all: 'All',
|
||||
reset: '重啟',
|
||||
disabled: '殘',
|
||||
enabled: '啟用',
|
||||
advertisement: '廣告',
|
||||
}, */
|
||||
captions: {
|
||||
active: true,
|
||||
},
|
||||
keys: {
|
||||
google: 'AIzaSyDrNwtN3nLH_8rjCmu5Wq3ZCm4MNAVdc0c',
|
||||
},
|
||||
ads: {
|
||||
enabled: true,
|
||||
publisherId: '918848828995742',
|
||||
},
|
||||
});
|
||||
|
||||
// Expose for tinkering in the console
|
||||
window.player = player;
|
||||
|
||||
// Setup type toggle
|
||||
const buttons = document.querySelectorAll('[data-source]');
|
||||
const types = {
|
||||
video: 'video',
|
||||
audio: 'audio',
|
||||
youtube: 'youtube',
|
||||
vimeo: 'vimeo',
|
||||
};
|
||||
let currentType = window.location.hash.replace('#', '');
|
||||
const historySupport = window.history && window.history.pushState;
|
||||
|
||||
// Toggle class on an element
|
||||
function toggleClass(element, className, state) {
|
||||
if (element) {
|
||||
element.classList[state ? 'add' : 'remove'](className);
|
||||
}
|
||||
}
|
||||
|
||||
// Set a new source
|
||||
function newSource(type, init) {
|
||||
// Bail if new type isn't known, it's the current type, or current type is empty (video is default) and new type is video
|
||||
if (!(type in types) || (!init && type === currentType) || (!currentType.length && type === types.video)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case types.video:
|
||||
player.source = {
|
||||
type: 'video',
|
||||
title: 'View From A Blue Moon',
|
||||
sources: [
|
||||
{
|
||||
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4',
|
||||
type: 'video/mp4',
|
||||
size: 576,
|
||||
},
|
||||
{
|
||||
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4',
|
||||
type: 'video/mp4',
|
||||
size: 720,
|
||||
},
|
||||
{
|
||||
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1080p.mp4',
|
||||
type: 'video/mp4',
|
||||
size: 1080,
|
||||
},
|
||||
{
|
||||
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1440p.mp4',
|
||||
type: 'video/mp4',
|
||||
size: 1440,
|
||||
},
|
||||
],
|
||||
poster: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg',
|
||||
tracks: [
|
||||
{
|
||||
kind: 'captions',
|
||||
label: 'English',
|
||||
srclang: 'en',
|
||||
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
kind: 'captions',
|
||||
label: 'French',
|
||||
srclang: 'fr',
|
||||
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
break;
|
||||
|
||||
case types.audio:
|
||||
player.source = {
|
||||
type: 'audio',
|
||||
title: 'Kishi Bashi – “It All Began With A Burst”',
|
||||
sources: [
|
||||
{
|
||||
src: 'https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3',
|
||||
type: 'audio/mp3',
|
||||
},
|
||||
{
|
||||
src: 'https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg',
|
||||
type: 'audio/ogg',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
break;
|
||||
|
||||
case types.youtube:
|
||||
player.source = {
|
||||
type: 'video',
|
||||
sources: [{
|
||||
src: 'https://youtube.com/watch?v=bTqVqk7FSmY',
|
||||
provider: 'youtube',
|
||||
}],
|
||||
};
|
||||
|
||||
break;
|
||||
|
||||
case types.vimeo:
|
||||
player.source = {
|
||||
type: 'video',
|
||||
sources: [{
|
||||
src: 'https://vimeo.com/76979871',
|
||||
provider: 'vimeo',
|
||||
}],
|
||||
};
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the current type for next time
|
||||
currentType = type;
|
||||
|
||||
// Remove active classes
|
||||
Array.from(buttons).forEach(button => toggleClass(button.parentElement, 'active', false));
|
||||
|
||||
// Set active on parent
|
||||
toggleClass(document.querySelector(`[data-source="${type}"]`), 'active', true);
|
||||
|
||||
// Show cite
|
||||
Array.from(document.querySelectorAll('.plyr__cite')).forEach(cite => {
|
||||
cite.setAttribute('hidden', '');
|
||||
});
|
||||
document.querySelector(`.plyr__cite--${type}`).removeAttribute('hidden');
|
||||
}
|
||||
|
||||
// Bind to each button
|
||||
Array.from(buttons).forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const type = button.getAttribute('data-source');
|
||||
|
||||
newSource(type);
|
||||
|
||||
if (historySupport) {
|
||||
window.history.pushState({ type }, '', `#${type}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// List for backwards/forwards
|
||||
window.addEventListener('popstate', event => {
|
||||
if (event.state && 'type' in event.state) {
|
||||
newSource(event.state.type);
|
||||
}
|
||||
});
|
||||
|
||||
// On load
|
||||
if (historySupport) {
|
||||
const video = !currentType.length;
|
||||
|
||||
// If there's no current type set, assume video
|
||||
if (video) {
|
||||
currentType = types.video;
|
||||
}
|
||||
|
||||
// Replace current history state
|
||||
if (currentType in types) {
|
||||
window.history.replaceState(
|
||||
{
|
||||
type: currentType,
|
||||
},
|
||||
'',
|
||||
video ? '' : `#${currentType}`,
|
||||
);
|
||||
}
|
||||
|
||||
// If it's not video, load the source
|
||||
if (currentType !== types.video) {
|
||||
newSource(currentType, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Google analytics
|
||||
// For demo site (https://plyr.io) only
|
||||
/* eslint-disable */
|
||||
if (isLive) {
|
||||
(function(i, s, o, g, r, a, m) {
|
||||
i.GoogleAnalyticsObject = r;
|
||||
i[r] =
|
||||
i[r] ||
|
||||
function() {
|
||||
(i[r].q = i[r].q || []).push(arguments);
|
||||
};
|
||||
i[r].l = 1 * new Date();
|
||||
a = s.createElement(o);
|
||||
m = s.getElementsByTagName(o)[0];
|
||||
a.async = 1;
|
||||
a.src = g;
|
||||
m.parentNode.insertBefore(a, m);
|
||||
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
|
||||
window.ga('create', 'UA-40881672-11', 'auto');
|
||||
window.ga('send', 'pageview');
|
||||
}
|
||||
/* eslint-enable */
|
||||
})();
|
@ -1,237 +0,0 @@
|
||||
/*
|
||||
* 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,203 +0,0 @@
|
||||
// ==========================================================================
|
||||
// Plyr.io demo
|
||||
// This code is purely for the plyr.io website
|
||||
// Please see readme.md in the root or github.com/selz/plyr
|
||||
// ==========================================================================
|
||||
|
||||
/*global plyr*/
|
||||
|
||||
// General functions
|
||||
(function() {
|
||||
//document.body.addEventListener('ready', function(event) { console.log(event); });
|
||||
|
||||
// Setup the player
|
||||
var instances = plyr.setup({
|
||||
debug: true,
|
||||
title: "Video demo",
|
||||
iconUrl: "../dist/plyr.svg",
|
||||
tooltips: {
|
||||
controls: true
|
||||
},
|
||||
captions: {
|
||||
defaultActive: true
|
||||
}
|
||||
});
|
||||
plyr.loadSprite("dist/demo.svg");
|
||||
|
||||
// Plyr returns an array regardless
|
||||
var player = instances[0];
|
||||
|
||||
// Setup type toggle
|
||||
var buttons = document.querySelectorAll("[data-source]"),
|
||||
types = {
|
||||
video: "video",
|
||||
audio: "audio",
|
||||
youtube: "youtube",
|
||||
vimeo: "vimeo"
|
||||
},
|
||||
currentType = window.location.hash.replace("#", ""),
|
||||
historySupport = window.history && window.history.pushState;
|
||||
|
||||
// Bind to each button
|
||||
for (var i = buttons.length - 1; i >= 0; i--) {
|
||||
buttons[i].addEventListener("click", function() {
|
||||
var type = this.getAttribute("data-source");
|
||||
|
||||
newSource(type);
|
||||
|
||||
if (historySupport) {
|
||||
history.pushState({ type: type }, "", "#" + type);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// List for backwards/forwards
|
||||
window.addEventListener("popstate", function(event) {
|
||||
if (event.state && "type" in event.state) {
|
||||
newSource(event.state.type);
|
||||
}
|
||||
});
|
||||
|
||||
// On load
|
||||
if (historySupport) {
|
||||
var video = !currentType.length;
|
||||
|
||||
// If there's no current type set, assume video
|
||||
if (video) {
|
||||
currentType = types.video;
|
||||
}
|
||||
|
||||
// Replace current history state
|
||||
if (currentType in types) {
|
||||
history.replaceState({ type: currentType }, "", video ? "" : "#" + currentType);
|
||||
}
|
||||
|
||||
// If it's not video, load the source
|
||||
if (currentType !== types.video) {
|
||||
newSource(currentType, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle class on an element
|
||||
function toggleClass(element, className, state) {
|
||||
if (element) {
|
||||
if (element.classList) {
|
||||
element.classList[state ? "add" : "remove"](className);
|
||||
} else {
|
||||
var name = (" " + element.className + " ").replace(/\s+/g, " ").replace(" " + className + " ", "");
|
||||
element.className = name + (state ? " " + className : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set a new source
|
||||
function newSource(type, init) {
|
||||
// Bail if new type isn't known, it's the current type, or current type is empty (video is default) and new type is video
|
||||
if (!(type in types) || (!init && type === currentType) || (!currentType.length && type === types.video)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case types.video:
|
||||
player.source({
|
||||
type: "video",
|
||||
title: "View From A Blue Moon",
|
||||
sources: [
|
||||
{
|
||||
src: "https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4",
|
||||
type: "video/mp4"
|
||||
},
|
||||
{
|
||||
src: "https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.webm",
|
||||
type: "video/webm"
|
||||
}
|
||||
],
|
||||
poster: "https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg",
|
||||
tracks: [
|
||||
{
|
||||
kind: "captions",
|
||||
label: "English",
|
||||
srclang: "en",
|
||||
src: "https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt",
|
||||
default: true
|
||||
}
|
||||
]
|
||||
});
|
||||
break;
|
||||
|
||||
case types.audio:
|
||||
player.source({
|
||||
type: "audio",
|
||||
title: "Kishi Bashi – “It All Began With A Burst”",
|
||||
sources: [
|
||||
{
|
||||
src: "https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3",
|
||||
type: "audio/mp3"
|
||||
},
|
||||
{
|
||||
src: "https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg",
|
||||
type: "audio/ogg"
|
||||
}
|
||||
]
|
||||
});
|
||||
break;
|
||||
|
||||
case types.youtube:
|
||||
player.source({
|
||||
type: "video",
|
||||
title: "View From A Blue Moon",
|
||||
sources: [
|
||||
{
|
||||
src: "bTqVqk7FSmY",
|
||||
type: "youtube"
|
||||
}
|
||||
]
|
||||
});
|
||||
break;
|
||||
|
||||
case types.vimeo:
|
||||
player.source({
|
||||
type: "video",
|
||||
title: "View From A Blue Moon",
|
||||
sources: [
|
||||
{
|
||||
src: "147865858",
|
||||
type: "vimeo"
|
||||
}
|
||||
]
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the current type for next time
|
||||
currentType = type;
|
||||
|
||||
// Remove active classes
|
||||
for (var x = buttons.length - 1; x >= 0; x--) {
|
||||
toggleClass(buttons[x].parentElement, "active", false);
|
||||
}
|
||||
|
||||
// Set active on parent
|
||||
toggleClass(document.querySelector('[data-source="' + type + '"]').parentElement, "active", true);
|
||||
}
|
||||
})();
|
||||
|
||||
// Google analytics
|
||||
// For demo site (http://[www.]plyr.io) only
|
||||
if (document.domain.indexOf("plyr.io") > -1) {
|
||||
(function(i, s, o, g, r, a, m) {
|
||||
i.GoogleAnalyticsObject = r;
|
||||
(i[r] =
|
||||
i[r] ||
|
||||
function() {
|
||||
(i[r].q = i[r].q || []).push(arguments);
|
||||
}),
|
||||
(i[r].l = 1 * new Date());
|
||||
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
|
||||
a.async = 1;
|
||||
a.src = g;
|
||||
m.parentNode.insertBefore(a, m);
|
||||
})(window, document, "script", "//www.google-analytics.com/analytics.js", "ga");
|
||||
ga("create", "UA-40881672-11", "auto");
|
||||
ga("send", "pageview");
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
// ==========================================================================
|
||||
// Base layout
|
||||
// ==========================================================================
|
||||
|
||||
// BORDER-BOX ALL THE THINGS!
|
||||
// http://paulirish.com/2012/box-sizing-border-box-ftw/
|
||||
*, *::after, *::before {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
// Hidden
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Base
|
||||
html {
|
||||
height: 100%;
|
||||
background: @body-background fixed;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: (@padding-base / 2);
|
||||
}
|
||||
|
||||
// Header
|
||||
header {
|
||||
padding: @padding-base;
|
||||
margin-bottom: @padding-base;
|
||||
|
||||
p {
|
||||
.font-size(18);
|
||||
}
|
||||
@media (min-width: @screen-sm) {
|
||||
padding-top: (@padding-base * 3);
|
||||
padding-bottom: (@padding-base * 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Sections
|
||||
section {
|
||||
max-width: @example-width-video;
|
||||
margin: 0 auto @padding-base;
|
||||
|
||||
@media (min-width: @screen-sm) {
|
||||
margin-bottom: (@padding-base * 2);
|
||||
}
|
||||
}
|
@ -1,172 +0,0 @@
|
||||
// ==========================================================================
|
||||
// Buttons
|
||||
// ==========================================================================
|
||||
|
||||
nav {
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 0;
|
||||
}
|
||||
li {
|
||||
display: inline-block;
|
||||
margin-top: (@padding-base / 2);
|
||||
.font-size();
|
||||
white-space: nowrap;
|
||||
}
|
||||
li + li {
|
||||
margin-left: @padding-base;
|
||||
}
|
||||
}
|
||||
|
||||
// Tabs
|
||||
.btn__bar {
|
||||
position: relative;
|
||||
margin: 0 auto @padding-base;
|
||||
max-width: @example-width-video;
|
||||
white-space: nowrap;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 1px;
|
||||
background: @gray-lighter;
|
||||
}
|
||||
|
||||
ul {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: inline-block;
|
||||
user-select: none;
|
||||
}
|
||||
li {
|
||||
margin: 0;
|
||||
|
||||
&:first-child .btn {
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
&:last-child .btn {
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
& + li .btn {
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
&.active .btn {
|
||||
&:extend(.btn--primary);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0, .2);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
.icon {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
&.active + li .btn:hover {
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
position: relative;
|
||||
display: block;
|
||||
border-radius: 0;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 560px) {
|
||||
margin-bottom: (@padding-base * 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Shared
|
||||
.btn,
|
||||
.btn__count {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
border-radius: @border-radius-base;
|
||||
user-select: none;
|
||||
font-weight: @font-weight-bold;
|
||||
}
|
||||
|
||||
// Buttons
|
||||
.btn {
|
||||
padding: (@padding-base / 2) ((@padding-base / 2) + 2);
|
||||
background: linear-gradient(lighten(@off-white, 2%), darken(@off-white, 3%));
|
||||
border: 1px solid @gray-light;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0, .05);
|
||||
text-shadow: 0 1px 1px #fff;
|
||||
color: @gray;
|
||||
transition: background .1s ease, color .1s ease;
|
||||
.font-size(@font-size-small);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
border-color: darken(@gray-light, 8%);
|
||||
color: @gray;
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Sizes
|
||||
.btn--large {
|
||||
padding: (@padding-base / 2) @padding-base;
|
||||
.font-size();
|
||||
}
|
||||
|
||||
// Styles
|
||||
.btn--primary {
|
||||
background-image: linear-gradient(@link-color, darken(@link-color, 5%));
|
||||
background-color: @link-color;
|
||||
border-color: darken(@link-color, 10%);
|
||||
box-shadow: 0 1px 1px rgba(0,0,0, .15);
|
||||
text-shadow: 0 1px 1px rgba(0,0,0, .1);
|
||||
color: #fff;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #fff;
|
||||
border-color: darken(@link-color, 20%);
|
||||
}
|
||||
}
|
||||
.btn--youtube .icon {
|
||||
color: @color-youtube;
|
||||
}
|
||||
.btn--vimeo .icon {
|
||||
color: @color-vimeo;
|
||||
}
|
||||
.btn--twitter .icon {
|
||||
color: @color-twitter;
|
||||
}
|
||||
|
||||
// Count bubble
|
||||
.btn__count {
|
||||
position: relative;
|
||||
margin-left: (@padding-base / 2);
|
||||
padding: (@padding-base / 2) (@padding-base * .75);
|
||||
background: #fff;
|
||||
border: 1px solid @gray-light;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: @arrow-size;
|
||||
height: @arrow-size;
|
||||
left: 1px;
|
||||
top: 50%;
|
||||
margin-top: -(@arrow-size / 2);
|
||||
|
||||
background: inherit;
|
||||
border: inherit;
|
||||
border-width: 1px 0 0 1px;
|
||||
transform: rotate(-45deg) translate(-50%, -50%);
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
// ==========================================================================
|
||||
// Typography
|
||||
// ==========================================================================
|
||||
|
||||
// Base
|
||||
html {
|
||||
font-size: 100%;
|
||||
}
|
||||
body {
|
||||
font-family: "Avenir", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
color: @gray;
|
||||
font-weight: @font-weight-base;
|
||||
.font-smoothing();
|
||||
}
|
||||
|
||||
// Headings
|
||||
h1,
|
||||
h2 {
|
||||
letter-spacing: -.025em;
|
||||
color: @brand-primary;
|
||||
margin: 0 0 (@padding-base / 2);
|
||||
line-height: 1.2;
|
||||
font-weight: @font-weight-bold;
|
||||
}
|
||||
h1 {
|
||||
.font-size(@font-size-h1);
|
||||
}
|
||||
|
||||
// Paragraph and small
|
||||
p,
|
||||
small {
|
||||
margin: 0 0 @padding-base;
|
||||
}
|
||||
small {
|
||||
display: block;
|
||||
padding: 0 (@padding-base / 2);
|
||||
.font-size(@font-size-small);
|
||||
}
|
||||
|
||||
// Lists
|
||||
ul,
|
||||
li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// Links
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: @link-color;
|
||||
border-bottom: 1px dotted currentColor;
|
||||
transition: background .3s ease, color .3s ease, border .3s ease;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: @gray-dark;
|
||||
border-bottom-color: rgba(0,0,0,0);
|
||||
}
|
||||
&:focus {
|
||||
.tab-focus();
|
||||
}
|
||||
&.logo {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.color--vimeo {
|
||||
color: @color-vimeo;
|
||||
}
|
||||
.color--youtube {
|
||||
color: @color-youtube;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
// ==========================================================================
|
||||
// Plyr.io Demo Page
|
||||
// ==========================================================================
|
||||
|
||||
// CSS Reset
|
||||
@import "lib/normalize.less";
|
||||
|
||||
// Mixins
|
||||
@import "lib/mixins.less";
|
||||
|
||||
// Variables
|
||||
@import "variables.less";
|
||||
|
||||
// Animation
|
||||
@import "lib/animation.less";
|
||||
|
||||
// Type
|
||||
@import "lib/fontface.less";
|
||||
@import "components/type.less";
|
||||
|
||||
// Components
|
||||
@import "components/base.less";
|
||||
@import "components/icons.less";
|
||||
@import "components/buttons.less";
|
||||
@import "components/error.less";
|
||||
@import "components/examples.less";
|
@ -1,18 +0,0 @@
|
||||
// ==========================================================================
|
||||
// Fonts
|
||||
// ==========================================================================
|
||||
|
||||
@font-face {
|
||||
font-family: 'Avenir';
|
||||
src: url('https://cdn.plyr.io/static/fonts/avenir-medium.woff2') format('woff2'), url('https://cdn.plyr.io/static/fonts/avenir-medium.woff') format('woff');
|
||||
font-style: normal;
|
||||
font-weight: @font-weight-base;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Avenir';
|
||||
src: url('https://cdn.plyr.io/static/fonts/avenir-bold.woff2') format('woff2'), url('https://cdn.plyr.io/static/fonts/avenir-bold.woff') format('woff');
|
||||
font-style: normal;
|
||||
font-weight: @font-weight-bold;
|
||||
font-display: swap;
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
// ==========================================================================
|
||||
// Mixins
|
||||
// ==========================================================================
|
||||
|
||||
// Contain floats: nicolasgallagher.com/micro-clearfix-hack/
|
||||
// ---------------------------------------
|
||||
.clearfix() {
|
||||
zoom: 1;
|
||||
&:before,
|
||||
&:after { content: ""; display: table; }
|
||||
&:after { clear: both; }
|
||||
}
|
||||
|
||||
// Webkit-style focus
|
||||
// ---------------------------------------
|
||||
.tab-focus() {
|
||||
// Default
|
||||
outline: thin dotted @gray-dark;
|
||||
// Webkit
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
// Use rems for font sizing
|
||||
// Leave <body> at 100%/16px
|
||||
// ---------------------------------------
|
||||
.font-size(@font-size: 16){
|
||||
@rem: round((@font-size / 16), 3);
|
||||
font-size: (@font-size * 1px);
|
||||
font-size: ~"@{rem}rem";
|
||||
}
|
||||
|
||||
// Font smoothing
|
||||
// ---------------------------------------
|
||||
.font-smoothing(@mode: on) when (@mode = on) {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
.font-smoothing(@mode: on) when (@mode = off) {
|
||||
-moz-osx-font-smoothing: auto;
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
}
|
406
demo/src/less/lib/normalize.less
vendored
@ -1,406 +0,0 @@
|
||||
/*! normalize.css v2.1.3 | MIT License | git.io/normalize */
|
||||
|
||||
/* ==========================================================================
|
||||
HTML5 display definitions
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Correct `block` display not defined in IE 8/9.
|
||||
*/
|
||||
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
main,
|
||||
nav,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct `inline-block` display not defined in IE 8/9.
|
||||
*/
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
video {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent modern browsers from displaying `audio` without controls.
|
||||
* Remove excess height in iOS 5 devices.
|
||||
*/
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `[hidden]` styling not present in IE 8/9.
|
||||
* Hide the `template` element in IE, Safari, and Firefox < 22.
|
||||
*/
|
||||
|
||||
[hidden],
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Base
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Set default font family to sans-serif.
|
||||
* 2. Prevent iOS text size adjust after orientation change, without disabling
|
||||
* user zoom.
|
||||
*/
|
||||
|
||||
html {
|
||||
font-family: sans-serif; /* 1 */
|
||||
-ms-text-size-adjust: 100%; /* 2 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default margin.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Links
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the gray background color from active links in IE 10.
|
||||
*/
|
||||
|
||||
a {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `outline` inconsistency between Chrome and other browsers.
|
||||
*/
|
||||
|
||||
a:focus {
|
||||
outline: thin dotted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Improve readability when focused and also mouse hovered in all browsers.
|
||||
*/
|
||||
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Typography
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address variable `h1` font-size and margin within `section` and `article`
|
||||
* contexts in Firefox 4+, Safari 5, and Chrome.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9, Safari 5, and Chrome.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in Safari 5 and Chrome.
|
||||
*/
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address differences between Firefox and other browsers.
|
||||
*/
|
||||
|
||||
hr {
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9.
|
||||
*/
|
||||
|
||||
mark {
|
||||
background: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct font family set oddly in Safari 5 and Chrome.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-family: monospace, serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Improve readability of pre-formatted text in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set consistent quote types.
|
||||
*/
|
||||
|
||||
q {
|
||||
quotes: "\201C" "\201D" "\2018" "\2019";
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent and variable font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove border when inside `a` element in IE 8/9.
|
||||
*/
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct overflow displayed oddly in IE 9.
|
||||
*/
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Figures
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address margin not present in IE 8/9 and Safari 5.
|
||||
*/
|
||||
|
||||
figure {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Define consistent border, margin, and padding.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #c0c0c0;
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `color` not being inherited in IE 8/9.
|
||||
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
||||
*/
|
||||
|
||||
legend {
|
||||
border: 0; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct font family not being inherited in all browsers.
|
||||
* 2. Correct font size not being inherited in all browsers.
|
||||
* 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit; /* 1 */
|
||||
font-size: 100%; /* 2 */
|
||||
margin: 0; /* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
|
||||
* the UA stylesheet.
|
||||
*/
|
||||
|
||||
button,
|
||||
input {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent `text-transform` inheritance for `button` and `select`.
|
||||
* All other form control elements do not inherit `text-transform` values.
|
||||
* Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
|
||||
* Correct `select` style inheritance in Firefox 4+ and Opera.
|
||||
*/
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
||||
* and `video` controls.
|
||||
* 2. Correct inability to style clickable `input` types in iOS.
|
||||
* 3. Improve usability and consistency of cursor style between image-type
|
||||
* `input` and others.
|
||||
*/
|
||||
|
||||
button,
|
||||
html input[type="button"], /* 1 */
|
||||
input[type="reset"],
|
||||
input[type="submit"] {
|
||||
-webkit-appearance: button; /* 2 */
|
||||
cursor: pointer; /* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-set default cursor for disabled elements.
|
||||
*/
|
||||
|
||||
button[disabled],
|
||||
html input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Address box sizing set to `content-box` in IE 8/9/10.
|
||||
* 2. Remove excess padding in IE 8/9/10.
|
||||
*/
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
|
||||
* 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
|
||||
* (include `-moz` to future-proof).
|
||||
*/
|
||||
|
||||
input[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
-moz-box-sizing: content-box;
|
||||
-webkit-box-sizing: content-box; /* 2 */
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and search cancel button in Safari 5 and Chrome
|
||||
* on OS X.
|
||||
*/
|
||||
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and border in Firefox 4+.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Remove default vertical scrollbar in IE 8/9.
|
||||
* 2. Improve readability and alignment in all browsers.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto; /* 1 */
|
||||
vertical-align: top; /* 2 */
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Tables
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove most spacing between table cells.
|
||||
*/
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
// ==========================================================================
|
||||
// Variables
|
||||
// ==========================================================================
|
||||
|
||||
// Colors
|
||||
@gray-dark: #343f4a;
|
||||
@gray: #55646b;
|
||||
@gray-light: #cbd0d3;
|
||||
@gray-lighter: #dbe3e8;
|
||||
@off-white: #f2f5f7;
|
||||
|
||||
@brand-primary: #3498db;
|
||||
@brand-secondary: #02BD9B;
|
||||
|
||||
// Brands
|
||||
@color-twitter: #4BAAF4;
|
||||
@color-youtube: #cc181e;
|
||||
@color-vimeo: #19b7ed;
|
||||
|
||||
// Base
|
||||
@body-background: @off-white; //linear-gradient(to left top, @brand-secondary, @brand-primary);
|
||||
|
||||
// Type
|
||||
@font-size-base: 16;
|
||||
@font-size-small: 14;
|
||||
@font-size-h1: 64;
|
||||
@font-weight-base: 500;
|
||||
@font-weight-bold: 700;
|
||||
|
||||
// Elements
|
||||
@link-color: @brand-primary;
|
||||
@padding-base: 20px;
|
||||
@arrow-size: 8px;
|
||||
|
||||
// Icons
|
||||
@icon-size: 18px;
|
||||
|
||||
// Breakpoints
|
||||
@screen-sm: 480px;
|
||||
@screen-md: 768px;
|
||||
|
||||
// Radii
|
||||
@border-radius-base: 4px;
|
||||
@border-radius-large: 6px;
|
||||
|
||||
// Examples
|
||||
@example-width-audio: 520px;
|
||||
@example-width-video: 1200px;
|
46
demo/src/sass/bundles/demo.scss
Normal file
@ -0,0 +1,46 @@
|
||||
// ==========================================================================
|
||||
// Plyr.io Demo Page
|
||||
// ==========================================================================
|
||||
@charset 'UTF-8';
|
||||
|
||||
// Settings
|
||||
@import '../settings/breakpoints';
|
||||
@import '../settings/colors';
|
||||
@import '../settings/cosmetic';
|
||||
@import '../settings/icons';
|
||||
@import '../settings/layout';
|
||||
@import '../settings/plyr';
|
||||
@import '../settings/spacing';
|
||||
@import '../settings/type';
|
||||
|
||||
// Libs
|
||||
@import '../lib/fontface';
|
||||
@import '../lib/animation';
|
||||
@import '../lib/mixins';
|
||||
@import '../lib/normalize';
|
||||
@import '../lib/reset';
|
||||
|
||||
// Layout
|
||||
@import '../layout/core';
|
||||
@import '../layout/grid';
|
||||
|
||||
// Type
|
||||
@import '../type/base';
|
||||
@import '../type/headings';
|
||||
|
||||
// Components
|
||||
@import '../components/buttons';
|
||||
@import '../components/header';
|
||||
@import '../components/icons';
|
||||
@import '../components/links';
|
||||
@import '../components/lists';
|
||||
@import '../components/media';
|
||||
@import '../components/navigation';
|
||||
@import '../components/players';
|
||||
|
||||
// Plyr
|
||||
@import '../../../../src/sass/plyr';
|
||||
|
||||
// Utils
|
||||
@import '../utilities/cosmetic';
|
||||
@import '../utilities/hidden';
|
29
demo/src/sass/bundles/error.scss
Normal file
@ -0,0 +1,29 @@
|
||||
// ==========================================================================
|
||||
// Plyr.io Error Page
|
||||
// ==========================================================================
|
||||
@charset 'UTF-8';
|
||||
|
||||
// Settings
|
||||
@import '../settings/colors';
|
||||
@import '../settings/cosmetic';
|
||||
@import '../settings/icons';
|
||||
@import '../settings/layout';
|
||||
@import '../settings/spacing';
|
||||
@import '../settings/type';
|
||||
|
||||
// Libs
|
||||
@import '../lib/fontface';
|
||||
@import '../lib/mixins';
|
||||
@import '../lib/normalize';
|
||||
@import '../lib/reset';
|
||||
|
||||
// Layout
|
||||
@import '../layout/error';
|
||||
|
||||
// Type
|
||||
@import '../type/base';
|
||||
@import '../type/headings';
|
||||
|
||||
// Components
|
||||
@import '../components/buttons';
|
||||
@import '../components/links';
|
83
demo/src/sass/components/buttons.scss
Normal file
@ -0,0 +1,83 @@
|
||||
// ==========================================================================
|
||||
// Buttons
|
||||
// ==========================================================================
|
||||
|
||||
// Shared
|
||||
.button,
|
||||
.button__count {
|
||||
align-items: center;
|
||||
background: $color-button-background;
|
||||
border: 0;
|
||||
border-radius: $border-radius-base;
|
||||
box-shadow: 0 1px 1px rgba(#000, 0.1);
|
||||
color: $color-button-text;
|
||||
display: inline-flex;
|
||||
padding: ($spacing-base * 0.75);
|
||||
position: relative;
|
||||
text-shadow: none;
|
||||
user-select: none;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
// Buttons
|
||||
.button {
|
||||
font-weight: $font-weight-bold;
|
||||
padding-left: $spacing-base;
|
||||
padding-right: $spacing-base;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $gray-dark;
|
||||
|
||||
// Remove the underline/border
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 2px rgba(#000, 0.1);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
&.tab-focus {
|
||||
@include tab-focus();
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
}
|
||||
|
||||
// Button group
|
||||
.button--with-count {
|
||||
display: inline-flex;
|
||||
|
||||
.button .icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Count bubble
|
||||
.button__count {
|
||||
animation: fadein 0.2s ease;
|
||||
margin-left: ($spacing-base / 2);
|
||||
|
||||
&::before {
|
||||
border: $arrow-size solid transparent;
|
||||
border-left-width: 0;
|
||||
border-right-color: $color-button-background;
|
||||
content: '';
|
||||
height: 0;
|
||||
position: absolute;
|
||||
right: 100%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 0;
|
||||
}
|
||||
}
|
19
demo/src/sass/components/header.scss
Normal file
@ -0,0 +1,19 @@
|
||||
// ==========================================================================
|
||||
// Header
|
||||
// ==========================================================================
|
||||
|
||||
header {
|
||||
padding-bottom: $spacing-base;
|
||||
text-align: center;
|
||||
|
||||
.call-to-action {
|
||||
margin-top: ($spacing-base * 1.5);
|
||||
}
|
||||
|
||||
@media only screen and (min-width: $screen-md) {
|
||||
margin-right: ($spacing-base * 3);
|
||||
max-width: 360px;
|
||||
padding-bottom: ($spacing-base * 2);
|
||||
text-align: left;
|
||||
}
|
||||
}
|
@ -4,23 +4,20 @@
|
||||
|
||||
// Base size icon styles
|
||||
.icon {
|
||||
fill: currentColor;
|
||||
width: @icon-size;
|
||||
height: @icon-size;
|
||||
vertical-align: -3px;
|
||||
fill: currentColor;
|
||||
height: $icon-size;
|
||||
vertical-align: -3px;
|
||||
width: $icon-size;
|
||||
}
|
||||
|
||||
// Within elements
|
||||
a svg,
|
||||
button svg,
|
||||
label svg {
|
||||
pointer-events: none;
|
||||
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);
|
||||
margin-right: floor($spacing-base / 3);
|
||||
}
|
49
demo/src/sass/components/links.scss
Normal file
@ -0,0 +1,49 @@
|
||||
// ==========================================================================
|
||||
// Links
|
||||
// ==========================================================================
|
||||
|
||||
// Make a <button> look like an <a>
|
||||
button.faux-link {
|
||||
@extend a; // stylelint-disable-line
|
||||
@include cancel-button-styles();
|
||||
}
|
||||
|
||||
// Links
|
||||
a {
|
||||
border-bottom: 1px dotted currentColor;
|
||||
color: $color-link;
|
||||
font-weight: $font-weight-bold;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&::after {
|
||||
background: currentColor;
|
||||
content: '';
|
||||
height: 1px;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
transform: translateX(-50%);
|
||||
transition: width 0.2s ease;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
border-bottom-color: transparent;
|
||||
outline: 0;
|
||||
|
||||
&::after {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.tab-focus {
|
||||
@include tab-focus();
|
||||
}
|
||||
|
||||
&.no-border::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
11
demo/src/sass/components/lists.scss
Normal file
@ -0,0 +1,11 @@
|
||||
// ==========================================================================
|
||||
// Lists
|
||||
// ==========================================================================
|
||||
|
||||
// Lists
|
||||
ul,
|
||||
li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
10
demo/src/sass/components/media.scss
Normal file
@ -0,0 +1,10 @@
|
||||
// ==========================================================================
|
||||
// Basic media
|
||||
// ==========================================================================
|
||||
|
||||
img,
|
||||
video,
|
||||
audio {
|
||||
max-width: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
9
demo/src/sass/components/navigation.scss
Normal file
@ -0,0 +1,9 @@
|
||||
// ==========================================================================
|
||||
// Navigation
|
||||
// ==========================================================================
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: $spacing-base;
|
||||
}
|
@ -10,31 +10,35 @@ video {
|
||||
|
||||
// Example players
|
||||
.plyr {
|
||||
margin: 0 auto;
|
||||
border-radius: @border-radius-large;
|
||||
}
|
||||
.plyr--audio {
|
||||
max-width: @example-width-audio;
|
||||
border-radius: $border-radius-base;
|
||||
box-shadow: 0 2px 5px rgba(#000, 0.2);
|
||||
margin: $spacing-base auto;
|
||||
|
||||
&.plyr--audio {
|
||||
max-width: 480px;
|
||||
}
|
||||
}
|
||||
|
||||
.plyr__video-wrapper::after {
|
||||
content: "";
|
||||
border: 1px solid rgba(#000, 0.15);
|
||||
border-radius: inherit;
|
||||
bottom: 0;
|
||||
content: '';
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border: 1px solid fade(#000, 15%);
|
||||
border-radius: inherit;
|
||||
top: 0;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
// Style full supported player
|
||||
.plyr__cite {
|
||||
display: none;
|
||||
margin-top: @padding-base;
|
||||
margin-top: $spacing-base;
|
||||
|
||||
.icon {
|
||||
margin-right: (@padding-base / 4);
|
||||
margin-right: ceil($spacing-base / 6);
|
||||
}
|
||||
}
|
||||
|
64
demo/src/sass/layout/core.scss
Normal file
@ -0,0 +1,64 @@
|
||||
// ==========================================================================
|
||||
// Core
|
||||
// ==========================================================================
|
||||
|
||||
html,
|
||||
body {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
html {
|
||||
background: $page-background;
|
||||
background-attachment: fixed;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.grid {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
main {
|
||||
margin: auto;
|
||||
padding-bottom: 1px; // Collapsing margins
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
aside {
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
color: $gray;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
padding: ($spacing-base * 0.75);
|
||||
position: relative;
|
||||
text-align: center;
|
||||
text-shadow: none;
|
||||
width: 100%;
|
||||
|
||||
.icon {
|
||||
fill: $color-twitter;
|
||||
margin-right: ($spacing-base / 2);
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $color-twitter;
|
||||
|
||||
&.tab-focus {
|
||||
@include tab-focus($color-twitter);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,13 +7,24 @@ html.error,
|
||||
.error body {
|
||||
height: 100%;
|
||||
}
|
||||
.error body {
|
||||
width: 100%;
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
|
||||
html.error {
|
||||
background: $page-background;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
.error main {
|
||||
display: table-cell;
|
||||
|
||||
.error body {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.error main {
|
||||
padding: $spacing-base;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
|
||||
p {
|
||||
@include font-size($font-size-large);
|
||||
}
|
||||
}
|
19
demo/src/sass/layout/grid.scss
Normal file
@ -0,0 +1,19 @@
|
||||
// ==========================================================================
|
||||
// Super basic grid
|
||||
// ==========================================================================
|
||||
|
||||
.grid {
|
||||
margin: 0 auto;
|
||||
padding: $spacing-base;
|
||||
|
||||
@media only screen and (min-width: $screen-md) {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
max-width: $container-max-width;
|
||||
width: 100%;
|
||||
|
||||
> * {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,11 @@
|
||||
// ==========================================================================
|
||||
|
||||
// Fade
|
||||
@keyframes fade-in {
|
||||
0% { opacity: 0 }
|
||||
100% { opacity: 1 }
|
||||
}
|
||||
@keyframes fadein {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
45
demo/src/sass/lib/fontface.scss
Normal file
@ -0,0 +1,45 @@
|
||||
// ==========================================================================
|
||||
// Fonts
|
||||
// ==========================================================================
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Gordita';
|
||||
font-style: normal;
|
||||
font-weight: $font-weight-light;
|
||||
src: url('https://cdn.plyr.io/static/fonts/gordita-light.woff2') format('woff2'), url('https://cdn.plyr.io/static/fonts/gordita-light.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Gordita';
|
||||
font-style: normal;
|
||||
font-weight: $font-weight-regular;
|
||||
src: url('https://cdn.plyr.io/static/fonts/gordita-regular.woff2') format('woff2'),
|
||||
url('https://cdn.plyr.io/static/fonts/gordita-regular.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Gordita';
|
||||
font-style: normal;
|
||||
font-weight: $font-weight-medium;
|
||||
src: url('https://cdn.plyr.io/static/fonts/gordita-medium.woff2') format('woff2'),
|
||||
url('https://cdn.plyr.io/static/fonts/gordita-medium.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Gordita';
|
||||
font-style: normal;
|
||||
font-weight: $font-weight-bold;
|
||||
src: url('https://cdn.plyr.io/static/fonts/gordita-bold.woff2') format('woff2'), url('https://cdn.plyr.io/static/fonts/gordita-bold.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-display: swap;
|
||||
font-family: 'Gordita';
|
||||
font-style: normal;
|
||||
font-weight: $font-weight-black;
|
||||
src: url('https://cdn.plyr.io/static/fonts/gordita-black.woff2') format('woff2'), url('https://cdn.plyr.io/static/fonts/gordita-black.woff') format('woff');
|
||||
}
|
54
demo/src/sass/lib/mixins.scss
Normal file
@ -0,0 +1,54 @@
|
||||
// ==========================================================================
|
||||
// Mixins
|
||||
// ==========================================================================
|
||||
|
||||
// Convert a <button> into an <a>
|
||||
// ---------------------------------------
|
||||
@mixin cancel-button-styles() {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
line-height: $line-height-base;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
text-align: inherit;
|
||||
text-shadow: inherit;
|
||||
-moz-user-select: text; // stylelint-disable-line
|
||||
vertical-align: baseline;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
// Nicer focus styles
|
||||
// ---------------------------------------
|
||||
@mixin tab-focus($color: $tab-focus-default-color) {
|
||||
box-shadow: 0 0 0 3px rgba($color, 0.35);
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
// Use rems for font sizing
|
||||
// Leave <body> at 100%/16px
|
||||
// ---------------------------------------
|
||||
@function calculate-rem($size) {
|
||||
$rem: $size / 16;
|
||||
@return #{$rem}rem;
|
||||
}
|
||||
|
||||
@mixin font-size($size: 16) {
|
||||
font-size: $size * 1px; // Fallback in px
|
||||
font-size: calculate-rem($size);
|
||||
}
|
||||
|
||||
// Font smoothing
|
||||
// ---------------------------------------
|
||||
@mixin font-smoothing($enabled: true) {
|
||||
@if $enabled {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
} @else {
|
||||
-moz-osx-font-smoothing: auto;
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
}
|
||||
}
|
450
demo/src/sass/lib/normalize.scss
vendored
Normal file
@ -0,0 +1,450 @@
|
||||
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||
|
||||
/* Document
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Correct the line height in all browsers.
|
||||
* 2. Prevent adjustments of font size after orientation changes in
|
||||
* IE on Windows Phone and in iOS.
|
||||
*/
|
||||
|
||||
html {
|
||||
line-height: 1.15; /* 1 */
|
||||
-ms-text-size-adjust: 100%; /* 2 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/* Sections
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the margin in all browsers (opinionated).
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
*/
|
||||
|
||||
article,
|
||||
aside,
|
||||
footer,
|
||||
header,
|
||||
nav,
|
||||
section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the font size and margin on `h1` elements within `section` and
|
||||
* `article` contexts in Chrome, Firefox, and Safari.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
* 1. Add the correct display in IE.
|
||||
*/
|
||||
|
||||
figcaption,
|
||||
figure,
|
||||
main {
|
||||
/* 1 */
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct margin in IE 8.
|
||||
*/
|
||||
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in Firefox.
|
||||
* 2. Show the overflow in Edge and IE.
|
||||
*/
|
||||
|
||||
hr {
|
||||
box-sizing: content-box; /* 1 */
|
||||
height: 0; /* 1 */
|
||||
overflow: visible; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Remove the gray background on active links in IE 10.
|
||||
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent; /* 1 */
|
||||
-webkit-text-decoration-skip: objects; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Remove the bottom border in Chrome 57- and Firefox 39-.
|
||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: none; /* 1 */
|
||||
text-decoration: underline; /* 2 */
|
||||
text-decoration: underline dotted; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||
* 2. Correct the odd `em` font sizing in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace; /* 1 */
|
||||
font-size: 1em; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font style in Android 4.3-.
|
||||
*/
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct background and color in IE 9-.
|
||||
*/
|
||||
|
||||
mark {
|
||||
background-color: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||
* all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
*/
|
||||
|
||||
audio,
|
||||
video {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in iOS 4-7.
|
||||
*/
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the border on images inside links in IE 10-.
|
||||
*/
|
||||
|
||||
img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the overflow in IE.
|
||||
*/
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* 1. Change the font styles in all browsers (opinionated).
|
||||
* 2. Remove the margin in Firefox and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
font-family: sans-serif; /* 1 */
|
||||
font-size: 100%; /* 1 */
|
||||
line-height: 1.15; /* 1 */
|
||||
margin: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the overflow in IE.
|
||||
* 1. Show the overflow in Edge.
|
||||
*/
|
||||
|
||||
button,
|
||||
input {
|
||||
/* 1 */
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||
* 1. Remove the inheritance of text transform in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select {
|
||||
/* 1 */
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
|
||||
* controls in Android 4.
|
||||
* 2. Correct the inability to style clickable types in iOS and Safari.
|
||||
*/
|
||||
|
||||
button,
|
||||
html [type='button'],
|
||||
[type='reset'],
|
||||
[type='submit'] {
|
||||
-webkit-appearance: button; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner border and padding in Firefox.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type='button']::-moz-focus-inner,
|
||||
[type='reset']::-moz-focus-inner,
|
||||
[type='submit']::-moz-focus-inner {
|
||||
border-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the focus styles unset by the previous rule.
|
||||
*/
|
||||
|
||||
button:-moz-focusring,
|
||||
[type='button']:-moz-focusring,
|
||||
[type='reset']:-moz-focusring,
|
||||
[type='submit']:-moz-focusring {
|
||||
outline: 1px dotted ButtonText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the padding in Firefox.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
padding: 0.35em 0.75em 0.625em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the text wrapping in Edge and IE.
|
||||
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||
* 3. Remove the padding so developers are not caught out when they zero out
|
||||
* `fieldset` elements in all browsers.
|
||||
*/
|
||||
|
||||
legend {
|
||||
box-sizing: border-box; /* 1 */
|
||||
color: inherit; /* 2 */
|
||||
display: table; /* 1 */
|
||||
max-width: 100%; /* 1 */
|
||||
padding: 0; /* 3 */
|
||||
white-space: normal; /* 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct display in IE 9-.
|
||||
* 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
progress {
|
||||
display: inline-block; /* 1 */
|
||||
vertical-align: baseline; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default vertical scrollbar in IE.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Add the correct box sizing in IE 10-.
|
||||
* 2. Remove the padding in IE 10-.
|
||||
*/
|
||||
|
||||
[type='checkbox'],
|
||||
[type='radio'] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||
*/
|
||||
|
||||
[type='number']::-webkit-inner-spin-button,
|
||||
[type='number']::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the odd appearance in Chrome and Safari.
|
||||
* 2. Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type='search'] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
outline-offset: -2px; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
|
||||
*/
|
||||
|
||||
[type='search']::-webkit-search-cancel-button,
|
||||
[type='search']::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||
* 2. Change font properties to `inherit` in Safari.
|
||||
*/
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
-webkit-appearance: button; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
}
|
||||
|
||||
/* Interactive
|
||||
========================================================================== */
|
||||
|
||||
/*
|
||||
* Add the correct display in IE 9-.
|
||||
* 1. Add the correct display in Edge, IE, and Firefox.
|
||||
*/
|
||||
|
||||
details,
|
||||
menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the correct display in all browsers.
|
||||
*/
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/* Scripting
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 9-.
|
||||
*/
|
||||
|
||||
canvas {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the correct display in IE.
|
||||
*/
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hidden
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Add the correct display in IE 10-.
|
||||
*/
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
11
demo/src/sass/lib/reset.scss
Normal file
@ -0,0 +1,11 @@
|
||||
// ==========================================================================
|
||||
// Resets
|
||||
// ==========================================================================
|
||||
|
||||
// BORDER-BOX ALL THE THINGS!
|
||||
// http://paulirish.com/2012/box-sizing-border-box-ftw/
|
||||
*,
|
||||
*::after,
|
||||
*::before {
|
||||
box-sizing: border-box;
|
||||
}
|
6
demo/src/sass/settings/breakpoints.scss
Normal file
@ -0,0 +1,6 @@
|
||||
// ==========================================================================
|
||||
// Breakpoints
|
||||
// ==========================================================================
|
||||
|
||||
$screen-sm: 480px;
|
||||
$screen-md: 768px;
|
32
demo/src/sass/settings/colors.scss
Normal file
@ -0,0 +1,32 @@
|
||||
// ==========================================================================
|
||||
// Colors
|
||||
// ==========================================================================
|
||||
|
||||
// Greyscale
|
||||
$gray-dark: #343f4a;
|
||||
$gray: #55646b;
|
||||
$gray-light: #cbd0d3;
|
||||
$gray-lighter: #dbe3e8;
|
||||
$off-white: #f2f5f7;
|
||||
|
||||
// Text
|
||||
$color-text: #fff;
|
||||
|
||||
// Plyr
|
||||
$color-brand-primary: #1aafff;
|
||||
|
||||
// Brands
|
||||
$color-twitter: #4baaf4;
|
||||
$color-youtube: #cc181e;
|
||||
$color-vimeo: #19b7ed;
|
||||
|
||||
// Elements
|
||||
$color-link: #fff;
|
||||
$color-background: $color-brand-primary;
|
||||
|
||||
// Buttons
|
||||
$color-button-background: #fff;
|
||||
$color-button-text: $gray;
|
||||
|
||||
// Focus
|
||||
$tab-focus-default-color: #fff;
|
12
demo/src/sass/settings/cosmetic.scss
Normal file
@ -0,0 +1,12 @@
|
||||
// ==========================================================================
|
||||
// Misc cosmetic
|
||||
// ==========================================================================
|
||||
|
||||
// Button count arrow size
|
||||
$arrow-size: 5px;
|
||||
|
||||
// Radii
|
||||
$border-radius-base: 4px;
|
||||
|
||||
// Background
|
||||
$page-background: linear-gradient(to left top, lighten($color-background, 10%), darken($color-background, 20%));
|
5
demo/src/sass/settings/icons.scss
Normal file
@ -0,0 +1,5 @@
|
||||
// ==========================================================================
|
||||
// Icons
|
||||
// ==========================================================================
|
||||
|
||||
$icon-size: 16px;
|
5
demo/src/sass/settings/layout.scss
Normal file
@ -0,0 +1,5 @@
|
||||
// ==========================================================================
|
||||
// Layout
|
||||
// ==========================================================================
|
||||
|
||||
$container-max-width: 1260px;
|
19
demo/src/sass/settings/plyr.scss
Normal file
@ -0,0 +1,19 @@
|
||||
// ==========================================================================
|
||||
// Plyr Settings
|
||||
// ==========================================================================
|
||||
|
||||
// Font
|
||||
$plyr-font-family: inherit;
|
||||
|
||||
// Sizes
|
||||
$plyr-font-size-base: 13px;
|
||||
$plyr-font-size-small: 12px;
|
||||
$plyr-font-size-time: 11px;
|
||||
$plyr-font-size-badges: 9px;
|
||||
|
||||
// Captions
|
||||
$plyr-font-size-captions-base: $plyr-font-size-base;
|
||||
$plyr-font-size-captions-small: $plyr-font-size-small;
|
||||
$plyr-font-size-captions-medium: 18px;
|
||||
$plyr-font-size-captions-large: 21px;
|
||||
$plyr-font-size-menu: $plyr-font-size-base;
|
5
demo/src/sass/settings/spacing.scss
Normal file
@ -0,0 +1,5 @@
|
||||
// ==========================================================================
|
||||
// Colors
|
||||
// ==========================================================================
|
||||
|
||||
$spacing-base: 20px;
|
20
demo/src/sass/settings/type.scss
Normal file
@ -0,0 +1,20 @@
|
||||
// ==========================================================================
|
||||
// Typography
|
||||
// ==========================================================================
|
||||
|
||||
$font-sans-serif: 'Gordita', 'Avenir', 'Helvetica Neue', sans-serif;
|
||||
|
||||
$font-size-base: 15;
|
||||
$font-size-small: 13;
|
||||
$font-size-large: 18;
|
||||
$font-size-h1: 64;
|
||||
|
||||
$font-weight-light: 300;
|
||||
$font-weight-regular: 400;
|
||||
$font-weight-medium: 500;
|
||||
$font-weight-bold: 600;
|
||||
$font-weight-black: 900;
|
||||
|
||||
$line-height-base: 1.75;
|
||||
|
||||
$letter-spacing-headings: -0.025em;
|
35
demo/src/sass/type/base.scss
Normal file
@ -0,0 +1,35 @@
|
||||
// ==========================================================================
|
||||
// Base
|
||||
// ==========================================================================
|
||||
|
||||
// Set to 100% for rem sizing
|
||||
html {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
@include font-smoothing();
|
||||
@include font-size($font-size-base);
|
||||
color: $color-text;
|
||||
font-family: $font-sans-serif;
|
||||
font-weight: $font-weight-medium;
|
||||
line-height: $line-height-base;
|
||||
text-shadow: 0 1px 1px rgba(#000, 0.15);
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
p,
|
||||
small {
|
||||
margin: 0 0 $spacing-base;
|
||||
}
|
||||
|
||||
small {
|
||||
@include font-size($font-size-small);
|
||||
display: block;
|
||||
}
|
11
demo/src/sass/type/headings.scss
Normal file
@ -0,0 +1,11 @@
|
||||
// ==========================================================================
|
||||
// Headings
|
||||
// ==========================================================================
|
||||
|
||||
h1 {
|
||||
@include font-size($font-size-h1);
|
||||
font-weight: $font-weight-bold;
|
||||
letter-spacing: $letter-spacing-headings;
|
||||
line-height: 1.2;
|
||||
margin: 0 0 $spacing-base;
|
||||
}
|
7
demo/src/sass/utilities/cosmetic.scss
Normal file
@ -0,0 +1,7 @@
|
||||
// ==========================================================================
|
||||
// Misc cosmetic
|
||||
// ==========================================================================
|
||||
|
||||
.no-border {
|
||||
border: 0;
|
||||
}
|
20
demo/src/sass/utilities/hidden.scss
Normal file
@ -0,0 +1,20 @@
|
||||
// ==========================================================================
|
||||
// Hidden
|
||||
// ==========================================================================
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Hide only visually, but have it available for screen readers: h5bp.com/v
|
||||
.sr-only {
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
opacity: 0.001;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?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>
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1,11 +0,0 @@
|
||||
<?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>
|
Before Width: | Height: | Size: 981 B |
@ -1,9 +0,0 @@
|
||||
<?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>
|
Before Width: | Height: | Size: 779 B |
@ -1,9 +0,0 @@
|
||||
<?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>
|
Before Width: | Height: | Size: 739 B |
BIN
dist/blank.mp4
vendored
Normal file
2
dist/plyr.css
vendored
8158
dist/plyr.js
vendored
1
dist/plyr.js.map
vendored
Normal file
2
dist/plyr.min.js
vendored
Normal file
1
dist/plyr.min.js.map
vendored
Normal file
13542
dist/plyr.polyfilled.js
vendored
Normal file
1
dist/plyr.polyfilled.js.map
vendored
Normal file
2
dist/plyr.polyfilled.min.js
vendored
Normal file
1
dist/plyr.polyfilled.min.js.map
vendored
Normal file
2
dist/plyr.svg
vendored
@ -1 +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="plyr-captions-off" viewBox="0 0 18 18"><path d="M1 1c-.6 0-1 .4-1 1v11c0 .6.4 1 1 1h4.6l2.7 2.7c.2.2.4.3.7.3.3 0 .5-.1.7-.3l2.7-2.7H17c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1H1zm4.52 10.15c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41C8.47 4.96 7.46 3.76 5.5 3.76c-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69zm7.57 0c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41c-.28-1.15-1.29-2.35-3.25-2.35-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69z" fill-rule="evenodd" fill-opacity=".5"/></symbol><symbol id="plyr-captions-on" viewBox="0 0 18 18"><path d="M1 1c-.6 0-1 .4-1 1v11c0 .6.4 1 1 1h4.6l2.7 2.7c.2.2.4.3.7.3.3 0 .5-.1.7-.3l2.7-2.7H17c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1H1zm4.52 10.15c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41C8.47 4.96 7.46 3.76 5.5 3.76c-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69zm7.57 0c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41c-.28-1.15-1.29-2.35-3.25-2.35-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69z" fill-rule="evenodd"/></symbol><symbol id="plyr-enter-fullscreen" viewBox="0 0 18 18"><path d="M10 3h3.6l-4 4L11 8.4l4-4V8h2V1h-7zM7 9.6l-4 4V10H1v7h7v-2H4.4l4-4z"/></symbol><symbol id="plyr-exit-fullscreen" viewBox="0 0 18 18"><path d="M1 12h3.6l-4 4L2 17.4l4-4V17h2v-7H1zM16 .6l-4 4V1h-2v7h7V6h-3.6l4-4z"/></symbol><symbol id="plyr-fast-forward" viewBox="0 0 18 18"><path d="M7.875 7.171L0 1v16l7.875-6.171V17L18 9 7.875 1z"/></symbol><symbol id="plyr-muted" viewBox="0 0 18 18"><path d="M12.4 12.5l2.1-2.1 2.1 2.1 1.4-1.4L15.9 9 18 6.9l-1.4-1.4-2.1 2.1-2.1-2.1L11 6.9 13.1 9 11 11.1zM3.786 6.008H.714C.286 6.008 0 6.31 0 6.76v4.512c0 .452.286.752.714.752h3.072l4.071 3.858c.5.3 1.143 0 1.143-.602V2.752c0-.601-.643-.977-1.143-.601L3.786 6.008z"/></symbol><symbol id="plyr-pause" viewBox="0 0 18 18"><path d="M6 1H3c-.6 0-1 .4-1 1v14c0 .6.4 1 1 1h3c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1zM12 1c-.6 0-1 .4-1 1v14c0 .6.4 1 1 1h3c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1h-3z"/></symbol><symbol id="plyr-play" viewBox="0 0 18 18"><path d="M15.562 8.1L3.87.225C3.052-.337 2 .225 2 1.125v15.75c0 .9 1.052 1.462 1.87.9L15.563 9.9c.584-.45.584-1.35 0-1.8z"/></symbol><symbol id="plyr-restart" viewBox="0 0 18 18"><path d="M9.7 1.2l.7 6.4 2.1-2.1c1.9 1.9 1.9 5.1 0 7-.9 1-2.2 1.5-3.5 1.5-1.3 0-2.6-.5-3.5-1.5-1.9-1.9-1.9-5.1 0-7 .6-.6 1.4-1.1 2.3-1.3l-.6-1.9C6 2.6 4.9 3.2 4 4.1 1.3 6.8 1.3 11.2 4 14c1.3 1.3 3.1 2 4.9 2 1.9 0 3.6-.7 4.9-2 2.7-2.7 2.7-7.1 0-9.9L16 1.9l-6.3-.7z"/></symbol><symbol id="plyr-rewind" viewBox="0 0 18 18"><path d="M10.125 1L0 9l10.125 8v-6.171L18 17V1l-7.875 6.171z"/></symbol><symbol id="plyr-volume" viewBox="0 0 18 18"><path d="M15.6 3.3c-.4-.4-1-.4-1.4 0-.4.4-.4 1 0 1.4C15.4 5.9 16 7.4 16 9c0 1.6-.6 3.1-1.8 4.3-.4.4-.4 1 0 1.4.2.2.5.3.7.3.3 0 .5-.1.7-.3C17.1 13.2 18 11.2 18 9s-.9-4.2-2.4-5.7z"/><path d="M11.282 5.282a.909.909 0 0 0 0 1.316c.735.735.995 1.458.995 2.402 0 .936-.425 1.917-.995 2.487a.909.909 0 0 0 0 1.316c.145.145.636.262 1.018.156a.725.725 0 0 0 .298-.156C13.773 11.733 14.13 10.16 14.13 9c0-.17-.002-.34-.011-.51-.053-.992-.319-2.005-1.522-3.208a.909.909 0 0 0-1.316 0zM3.786 6.008H.714C.286 6.008 0 6.31 0 6.76v4.512c0 .452.286.752.714.752h3.072l4.071 3.858c.5.3 1.143 0 1.143-.602V2.752c0-.601-.643-.977-1.143-.601L3.786 6.008z"/></symbol></svg>
|
||||
<?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="plyr-airplay" viewBox="0 0 18 18"><path d="M16 1H2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h3v-2H3V3h12v8h-2v2h3a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1z"/><path d="M4 17h10l-5-6z"/></symbol><symbol id="plyr-captions-off" viewBox="0 0 18 18"><path d="M1 1c-.6 0-1 .4-1 1v11c0 .6.4 1 1 1h4.6l2.7 2.7c.2.2.4.3.7.3.3 0 .5-.1.7-.3l2.7-2.7H17c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1H1zm4.52 10.15c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41C8.47 4.96 7.46 3.76 5.5 3.76c-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69zm7.57 0c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41c-.28-1.15-1.29-2.35-3.25-2.35-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69z" fill-rule="evenodd" fill-opacity=".5"/></symbol><symbol id="plyr-captions-on" viewBox="0 0 18 18"><path d="M1 1c-.6 0-1 .4-1 1v11c0 .6.4 1 1 1h4.6l2.7 2.7c.2.2.4.3.7.3.3 0 .5-.1.7-.3l2.7-2.7H17c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1H1zm4.52 10.15c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41C8.47 4.96 7.46 3.76 5.5 3.76c-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69zm7.57 0c1.99 0 3.01-1.32 3.28-2.41l-1.29-.39c-.19.66-.78 1.45-1.99 1.45-1.14 0-2.2-.83-2.2-2.34 0-1.61 1.12-2.37 2.18-2.37 1.23 0 1.78.75 1.95 1.43l1.3-.41c-.28-1.15-1.29-2.35-3.25-2.35-1.9 0-3.61 1.44-3.61 3.7 0 2.26 1.65 3.69 3.63 3.69z" fill-rule="evenodd"/></symbol><symbol id="plyr-enter-fullscreen" viewBox="0 0 18 18"><path d="M10 3h3.6l-4 4L11 8.4l4-4V8h2V1h-7zM7 9.6l-4 4V10H1v7h7v-2H4.4l4-4z"/></symbol><symbol id="plyr-exit-fullscreen" viewBox="0 0 18 18"><path d="M1 12h3.6l-4 4L2 17.4l4-4V17h2v-7H1zM16 .6l-4 4V1h-2v7h7V6h-3.6l4-4z"/></symbol><symbol id="plyr-fast-forward" viewBox="0 0 18 18"><path d="M7.875 7.171L0 1v16l7.875-6.171V17L18 9 7.875 1z"/></symbol><symbol id="plyr-muted" viewBox="0 0 18 18"><path d="M12.4 12.5l2.1-2.1 2.1 2.1 1.4-1.4L15.9 9 18 6.9l-1.4-1.4-2.1 2.1-2.1-2.1L11 6.9 13.1 9 11 11.1zM3.786 6.008H.714C.286 6.008 0 6.31 0 6.76v4.512c0 .452.286.752.714.752h3.072l4.071 3.858c.5.3 1.143 0 1.143-.602V2.752c0-.601-.643-.977-1.143-.601L3.786 6.008z"/></symbol><symbol id="plyr-pause" viewBox="0 0 18 18"><path d="M6 1H3c-.6 0-1 .4-1 1v14c0 .6.4 1 1 1h3c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1zM12 1c-.6 0-1 .4-1 1v14c0 .6.4 1 1 1h3c.6 0 1-.4 1-1V2c0-.6-.4-1-1-1h-3z"/></symbol><symbol id="plyr-pip" viewBox="0 0 18 18"><path d="M13.293 3.293L7.022 9.564l1.414 1.414 6.271-6.271L17 7V1h-6z"/><path d="M13 15H3V5h5V3H2a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-6h-2v5z"/></symbol><symbol id="plyr-play" viewBox="0 0 18 18"><path d="M15.562 8.1L3.87.225C3.052-.337 2 .225 2 1.125v15.75c0 .9 1.052 1.462 1.87.9L15.563 9.9c.584-.45.584-1.35 0-1.8z"/></symbol><symbol id="plyr-restart" viewBox="0 0 18 18"><path d="M9.7 1.2l.7 6.4 2.1-2.1c1.9 1.9 1.9 5.1 0 7-.9 1-2.2 1.5-3.5 1.5-1.3 0-2.6-.5-3.5-1.5-1.9-1.9-1.9-5.1 0-7 .6-.6 1.4-1.1 2.3-1.3l-.6-1.9C6 2.6 4.9 3.2 4 4.1 1.3 6.8 1.3 11.2 4 14c1.3 1.3 3.1 2 4.9 2 1.9 0 3.6-.7 4.9-2 2.7-2.7 2.7-7.1 0-9.9L16 1.9l-6.3-.7z"/></symbol><symbol id="plyr-rewind" viewBox="0 0 18 18"><path d="M10.125 1L0 9l10.125 8v-6.171L18 17V1l-7.875 6.171z"/></symbol><symbol id="plyr-settings" viewBox="0 0 18 18"><path d="M16.135 7.784a2 2 0 0 1-1.23-2.969c.322-.536.225-.998-.094-1.316l-.31-.31c-.318-.318-.78-.415-1.316-.094a2 2 0 0 1-2.969-1.23C10.065 1.258 9.669 1 9.219 1h-.438c-.45 0-.845.258-.997.865a2 2 0 0 1-2.969 1.23c-.536-.322-.999-.225-1.317.093l-.31.31c-.318.318-.415.781-.093 1.317a2 2 0 0 1-1.23 2.969C1.26 7.935 1 8.33 1 8.781v.438c0 .45.258.845.865.997a2 2 0 0 1 1.23 2.969c-.322.536-.225.998.094 1.316l.31.31c.319.319.782.415 1.316.094a2 2 0 0 1 2.969 1.23c.151.607.547.865.997.865h.438c.45 0 .845-.258.997-.865a2 2 0 0 1 2.969-1.23c.535.321.997.225 1.316-.094l.31-.31c.318-.318.415-.781.094-1.316a2 2 0 0 1 1.23-2.969c.607-.151.865-.547.865-.997v-.438c0-.451-.26-.846-.865-.997zM9 12a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/></symbol><symbol id="plyr-volume" viewBox="0 0 18 18"><path d="M15.6 3.3c-.4-.4-1-.4-1.4 0-.4.4-.4 1 0 1.4C15.4 5.9 16 7.4 16 9c0 1.6-.6 3.1-1.8 4.3-.4.4-.4 1 0 1.4.2.2.5.3.7.3.3 0 .5-.1.7-.3C17.1 13.2 18 11.2 18 9s-.9-4.2-2.4-5.7z"/><path d="M11.282 5.282a.909.909 0 0 0 0 1.316c.735.735.995 1.458.995 2.402 0 .936-.425 1.917-.995 2.487a.909.909 0 0 0 0 1.316c.145.145.636.262 1.018.156a.725.725 0 0 0 .298-.156C13.773 11.733 14.13 10.16 14.13 9c0-.17-.002-.34-.011-.51-.053-.992-.319-2.005-1.522-3.208a.909.909 0 0 0-1.316 0zM3.786 6.008H.714C.286 6.008 0 6.31 0 6.76v4.512c0 .452.286.752.714.752h3.072l4.071 3.858c.5.3 1.143 0 1.143-.602V2.752c0-.601-.643-.977-1.143-.601L3.786 6.008z"/></symbol></svg>
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 4.9 KiB |
629
gulpfile.js
@ -1,353 +1,420 @@
|
||||
// ==========================================================================
|
||||
// Gulp build script
|
||||
// ==========================================================================
|
||||
/*global require, __dirname,Buffer*/
|
||||
/*jshint -W079 */
|
||||
/* global require, __dirname */
|
||||
/* eslint no-console: "off" */
|
||||
|
||||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
gulp = require('gulp'),
|
||||
gutil = require('gulp-util'),
|
||||
concat = require('gulp-concat'),
|
||||
uglify = require('gulp-uglify'),
|
||||
less = require('gulp-less'),
|
||||
sass = require('gulp-sass'),
|
||||
cleanCSS = require('gulp-clean-css'),
|
||||
run = require('run-sequence'),
|
||||
prefix = require('gulp-autoprefixer'),
|
||||
svgstore = require('gulp-svgstore'),
|
||||
svgmin = require('gulp-svgmin'),
|
||||
rename = require('gulp-rename'),
|
||||
s3 = require('gulp-s3'),
|
||||
replace = require('gulp-replace'),
|
||||
open = require('gulp-open'),
|
||||
size = require('gulp-size'),
|
||||
through = require('through2');
|
||||
const del = require('del');
|
||||
const path = require('path');
|
||||
const gulp = require('gulp');
|
||||
const gutil = require('gulp-util');
|
||||
const concat = require('gulp-concat');
|
||||
const filter = require('gulp-filter');
|
||||
const sass = require('gulp-sass');
|
||||
const cleancss = require('gulp-clean-css');
|
||||
const run = require('run-sequence');
|
||||
const header = require('gulp-header');
|
||||
const prefix = require('gulp-autoprefixer');
|
||||
const gitbranch = require('git-branch');
|
||||
const svgstore = require('gulp-svgstore');
|
||||
const svgmin = require('gulp-svgmin');
|
||||
const rename = require('gulp-rename');
|
||||
const s3 = require('gulp-s3');
|
||||
const replace = require('gulp-replace');
|
||||
const open = require('gulp-open');
|
||||
const size = require('gulp-size');
|
||||
const rollup = require('gulp-better-rollup');
|
||||
const babel = require('rollup-plugin-babel');
|
||||
const sourcemaps = require('gulp-sourcemaps');
|
||||
const uglify = require('gulp-uglify-es').default;
|
||||
const commonjs = require('rollup-plugin-commonjs');
|
||||
const resolve = require('rollup-plugin-node-resolve');
|
||||
|
||||
var root = __dirname,
|
||||
paths = {
|
||||
plyr: {
|
||||
// Source paths
|
||||
src: {
|
||||
less: path.join(root, 'src/less/**/*'),
|
||||
scss: path.join(root, 'src/scss/**/*'),
|
||||
js: path.join(root, 'src/js/**/*'),
|
||||
sprite: path.join(root, 'src/sprite/*.svg'),
|
||||
},
|
||||
// Output paths
|
||||
output: path.join(root, 'dist/'),
|
||||
},
|
||||
demo: {
|
||||
// Source paths
|
||||
src: {
|
||||
less: path.join(root, 'demo/src/less/**/*'),
|
||||
js: path.join(root, 'demo/src/js/**/*'),
|
||||
sprite: path.join(root, 'demo/src/sprite/**/*'),
|
||||
},
|
||||
// Output paths
|
||||
output: path.join(root, 'demo/dist/'),
|
||||
// Demo
|
||||
root: path.join(root, 'demo/'),
|
||||
},
|
||||
upload: [path.join(root, 'dist/**'), path.join(root, 'demo/dist/**')],
|
||||
},
|
||||
// Task arrays
|
||||
tasks = {
|
||||
less: [],
|
||||
scss: [],
|
||||
js: [],
|
||||
sprite: [],
|
||||
},
|
||||
// Fetch bundles from JSON
|
||||
bundles = loadJSON(path.join(root, 'bundles.json')),
|
||||
package = loadJSON(path.join(root, 'package.json'));
|
||||
const bundles = require('./bundles.json');
|
||||
const pkg = require('./package.json');
|
||||
|
||||
// Load json
|
||||
function loadJSON(path) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(path));
|
||||
} catch (err) {
|
||||
return {};
|
||||
}
|
||||
// Get AWS config
|
||||
let aws = {};
|
||||
try {
|
||||
aws = require('./aws.json'); //eslint-disable-line
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
// Create a file from a string
|
||||
// http://stackoverflow.com/questions/23230569/how-do-you-create-a-file-from-a-string-in-gulp
|
||||
function createFile(filename, string) {
|
||||
var src = require('stream').Readable({
|
||||
objectMode: true,
|
||||
});
|
||||
src._read = function() {
|
||||
this.push(
|
||||
new gutil.File({
|
||||
cwd: '',
|
||||
base: '',
|
||||
path: filename,
|
||||
contents: new Buffer(string),
|
||||
// stats also required for some functions
|
||||
// https://nodejs.org/api/fs.html#fs_class_fs_stats
|
||||
stat: {
|
||||
size: string.length,
|
||||
},
|
||||
}),
|
||||
);
|
||||
this.push(null);
|
||||
};
|
||||
return src;
|
||||
}
|
||||
const minSuffix = '.min';
|
||||
|
||||
var build = {
|
||||
js: function(files, bundle) {
|
||||
for (var key in files) {
|
||||
(function(key) {
|
||||
var name = 'js-' + key;
|
||||
tasks.js.push(name);
|
||||
// Paths
|
||||
const root = __dirname;
|
||||
const paths = {
|
||||
plyr: {
|
||||
// Source paths
|
||||
src: {
|
||||
sass: path.join(root, 'src/sass/**/*.scss'),
|
||||
js: path.join(root, 'src/js/**/*'),
|
||||
sprite: path.join(root, 'src/sprite/*.svg'),
|
||||
},
|
||||
|
||||
gulp.task(name, function() {
|
||||
return gulp
|
||||
.src(bundles[bundle].js[key])
|
||||
.pipe(concat(key))
|
||||
.pipe(uglify().on('error', gutil.log))
|
||||
.pipe(gulp.dest(paths[bundle].output));
|
||||
});
|
||||
})(key);
|
||||
}
|
||||
// Output paths
|
||||
output: path.join(root, 'dist/'),
|
||||
},
|
||||
less: function(files, bundle) {
|
||||
for (var key in files) {
|
||||
(function(key) {
|
||||
var name = 'less-' + key;
|
||||
tasks.less.push(name);
|
||||
demo: {
|
||||
// Source paths
|
||||
src: {
|
||||
sass: path.join(root, 'demo/src/sass/**/*.scss'),
|
||||
js: path.join(root, 'demo/src/js/**/*'),
|
||||
},
|
||||
|
||||
gulp.task(name, function() {
|
||||
return gulp
|
||||
.src(bundles[bundle].less[key])
|
||||
.pipe(less())
|
||||
.on('error', gutil.log)
|
||||
.pipe(concat(key))
|
||||
.pipe(prefix(['last 2 versions'], { cascade: true }))
|
||||
.pipe(cleanCSS())
|
||||
.pipe(gulp.dest(paths[bundle].output));
|
||||
});
|
||||
})(key);
|
||||
}
|
||||
},
|
||||
scss: function(files, bundle) {
|
||||
for (var key in files) {
|
||||
(function(key) {
|
||||
var name = 'scss-' + key;
|
||||
tasks.scss.push(name);
|
||||
// Output paths
|
||||
output: path.join(root, 'demo/dist/'),
|
||||
|
||||
gulp.task(name, function() {
|
||||
return gulp
|
||||
.src(bundles[bundle].scss[key])
|
||||
.pipe(sass())
|
||||
.on('error', gutil.log)
|
||||
.pipe(concat(key))
|
||||
.pipe(prefix(['last 2 versions'], { cascade: true }))
|
||||
.pipe(cleanCSS())
|
||||
.pipe(gulp.dest(paths[bundle].output));
|
||||
});
|
||||
})(key);
|
||||
}
|
||||
// Demo
|
||||
root: path.join(root, 'demo/'),
|
||||
},
|
||||
sprite: function(bundle) {
|
||||
var name = 'sprite-' + bundle;
|
||||
upload: [
|
||||
path.join(root, `dist/*${minSuffix}.*`),
|
||||
path.join(root, 'dist/*.css'),
|
||||
path.join(root, 'dist/*.svg'),
|
||||
path.join(root, `demo/dist/*${minSuffix}.*`),
|
||||
path.join(root, 'demo/dist/*.css'),
|
||||
],
|
||||
};
|
||||
|
||||
// Task arrays
|
||||
const tasks = {
|
||||
sass: [],
|
||||
js: [],
|
||||
sprite: [],
|
||||
clean: ['clean'],
|
||||
};
|
||||
|
||||
// Size plugin
|
||||
const sizeOptions = { showFiles: true, gzip: true };
|
||||
|
||||
// Browserlist
|
||||
const browsers = ['> 1%'];
|
||||
|
||||
// Babel config
|
||||
const babelrc = {
|
||||
presets: [[
|
||||
'env',
|
||||
{
|
||||
targets: {
|
||||
browsers,
|
||||
},
|
||||
useBuiltIns: true,
|
||||
modules: false,
|
||||
},
|
||||
]],
|
||||
plugins: ['external-helpers'],
|
||||
babelrc: false,
|
||||
exclude: 'node_modules/**',
|
||||
};
|
||||
|
||||
// Clean out /dist
|
||||
gulp.task('clean', () => {
|
||||
const dirs = [
|
||||
paths.plyr.output,
|
||||
paths.demo.output,
|
||||
].map(dir => path.join(dir, '**/*'));
|
||||
|
||||
// Don't delete the mp4
|
||||
dirs.push(`!${path.join(paths.plyr.output, '**/*.mp4')}`);
|
||||
|
||||
del(dirs);
|
||||
});
|
||||
|
||||
const build = {
|
||||
js(files, bundle, options) {
|
||||
Object.keys(files).forEach(key => {
|
||||
const name = `js:${key}`;
|
||||
tasks.js.push(name);
|
||||
const { output } = paths[bundle];
|
||||
|
||||
return gulp.task(name, () =>
|
||||
gulp
|
||||
.src(bundles[bundle].js[key])
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(concat(key))
|
||||
.pipe(
|
||||
rollup(
|
||||
{
|
||||
plugins: [
|
||||
resolve(),
|
||||
commonjs(),
|
||||
babel(babelrc),
|
||||
],
|
||||
},
|
||||
options,
|
||||
),
|
||||
)
|
||||
.pipe(header('typeof navigator === "object" && ')) // "Support" SSR (#935)
|
||||
.pipe(sourcemaps.write(''))
|
||||
.pipe(gulp.dest(output))
|
||||
.pipe(filter('**/*.js'))
|
||||
.pipe(uglify())
|
||||
.pipe(size(sizeOptions))
|
||||
.pipe(rename({ suffix: minSuffix }))
|
||||
.pipe(sourcemaps.write(''))
|
||||
.pipe(gulp.dest(output)),
|
||||
);
|
||||
});
|
||||
},
|
||||
sass(files, bundle) {
|
||||
Object.keys(files).forEach(key => {
|
||||
const name = `sass:${key}`;
|
||||
tasks.sass.push(name);
|
||||
|
||||
return gulp.task(name, () =>
|
||||
gulp
|
||||
.src(bundles[bundle].sass[key])
|
||||
.pipe(sass())
|
||||
.on('error', gutil.log)
|
||||
.pipe(concat(key))
|
||||
.pipe(prefix(browsers, { cascade: false }))
|
||||
.pipe(cleancss())
|
||||
.pipe(size(sizeOptions))
|
||||
.pipe(gulp.dest(paths[bundle].output)),
|
||||
);
|
||||
});
|
||||
},
|
||||
sprite(bundle) {
|
||||
const name = `svg:sprite:${bundle}`;
|
||||
tasks.sprite.push(name);
|
||||
|
||||
// Process Icons
|
||||
gulp.task(name, function() {
|
||||
return gulp
|
||||
return gulp.task(name, () =>
|
||||
gulp
|
||||
.src(paths[bundle].src.sprite)
|
||||
.pipe(
|
||||
svgmin({
|
||||
plugins: [
|
||||
{
|
||||
removeDesc: true,
|
||||
},
|
||||
],
|
||||
plugins: [{
|
||||
removeDesc: true,
|
||||
}],
|
||||
}),
|
||||
)
|
||||
.pipe(svgstore())
|
||||
.pipe(rename({ basename: bundle }))
|
||||
.pipe(gulp.dest(paths[bundle].output));
|
||||
});
|
||||
.pipe(size(sizeOptions))
|
||||
.pipe(gulp.dest(paths[bundle].output)),
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
// Plyr core files
|
||||
build.js(bundles.plyr.js, 'plyr');
|
||||
build.less(bundles.plyr.less, 'plyr');
|
||||
build.scss(bundles.plyr.scss, 'plyr');
|
||||
build.js(bundles.plyr.js, 'plyr', { name: 'Plyr', format: 'umd' });
|
||||
build.sass(bundles.plyr.sass, 'plyr');
|
||||
build.sprite('plyr');
|
||||
|
||||
// Demo files
|
||||
build.less(bundles.demo.less, 'demo');
|
||||
build.js(bundles.demo.js, 'demo');
|
||||
build.sprite('demo');
|
||||
build.sass(bundles.demo.sass, 'demo');
|
||||
build.js(bundles.demo.js, 'demo', { format: 'iife' });
|
||||
|
||||
// Build all JS
|
||||
gulp.task('js', function() {
|
||||
gulp.task('js', () => {
|
||||
run(tasks.js);
|
||||
});
|
||||
|
||||
// Build SCSS (for testing, default is LESS)
|
||||
gulp.task('scss', function() {
|
||||
run(tasks.scss);
|
||||
});
|
||||
|
||||
// Watch for file changes
|
||||
gulp.task('watch', function() {
|
||||
gulp.task('watch', () => {
|
||||
// Plyr core
|
||||
gulp.watch(paths.plyr.src.js, tasks.js);
|
||||
gulp.watch(paths.plyr.src.less, tasks.less);
|
||||
gulp.watch(paths.plyr.src.sass, tasks.sass);
|
||||
gulp.watch(paths.plyr.src.sprite, tasks.sprite);
|
||||
|
||||
// Demo
|
||||
gulp.watch(paths.demo.src.js, tasks.js);
|
||||
gulp.watch(paths.demo.src.less, tasks.less);
|
||||
gulp.watch(paths.demo.src.sprite, tasks.sprite);
|
||||
gulp.watch(paths.demo.src.sass, tasks.sass);
|
||||
});
|
||||
|
||||
// Build distribution
|
||||
gulp.task('build', () => {
|
||||
run(tasks.clean, tasks.js, tasks.sass, tasks.sprite);
|
||||
});
|
||||
|
||||
// Default gulp task
|
||||
gulp.task('default', function() {
|
||||
run(tasks.js, tasks.less, tasks.sprite, 'watch');
|
||||
gulp.task('default', () => {
|
||||
run('build', 'watch');
|
||||
});
|
||||
|
||||
// Publish a version to CDN and demo
|
||||
// --------------------------------------------
|
||||
// If aws is setup
|
||||
if (Object.keys(aws).includes('cdn') && Object.keys(aws).includes('demo')) {
|
||||
const { version } = pkg;
|
||||
|
||||
// Some options
|
||||
var aws = loadJSON(path.join(root, 'aws.json')),
|
||||
version = package.version,
|
||||
maxAge = 31536000, // seconds 1 year
|
||||
options = {
|
||||
// Get branch info
|
||||
const branch = {
|
||||
current: gitbranch.sync(),
|
||||
master: 'master',
|
||||
develop: 'develop',
|
||||
};
|
||||
const allowed = [
|
||||
branch.master,
|
||||
branch.develop,
|
||||
];
|
||||
|
||||
const maxAge = 31536000; // 1 year
|
||||
const options = {
|
||||
cdn: {
|
||||
headers: {
|
||||
'Cache-Control': 'max-age=' + maxAge,
|
||||
'Cache-Control': `max-age=${maxAge}`,
|
||||
Vary: 'Accept-Encoding',
|
||||
},
|
||||
},
|
||||
demo: {
|
||||
uploadPath: branch.current === branch.develop ? 'beta/' : null,
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0',
|
||||
Vary: 'Accept-Encoding',
|
||||
},
|
||||
},
|
||||
symlinks: function(version, filename) {
|
||||
symlinks(ver, filename) {
|
||||
return {
|
||||
headers: {
|
||||
// http://stackoverflow.com/questions/2272835/amazon-s3-object-redirect
|
||||
'x-amz-website-redirect-location': '/' + version + '/' + filename,
|
||||
'x-amz-website-redirect-location': `/${ver}/${filename}`,
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0',
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
// If aws is setup
|
||||
if ('cdn' in aws) {
|
||||
var regex = '(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*).(?:0|[1-9][0-9]*)(?:-[\\da-z\\-]+(?:.[\\da-z\\-]+)*)?(?:\\+[\\da-z\\-]+(?:.[\\da-z\\-]+)*)?',
|
||||
cdnpath = new RegExp(aws.cdn.domain + '/' + regex, 'gi'),
|
||||
semver = new RegExp('v' + regex, 'gi'),
|
||||
localPath = new RegExp('(../)?dist', 'gi'),
|
||||
versionPath = 'https://' + aws.cdn.domain + '/' + version;
|
||||
const regex = '(?:0|[1-9][0-9]*)\\.(?:0|[1-9][0-9]*).(?:0|[1-9][0-9]*)(?:-[\\da-z\\-]+(?:.[\\da-z\\-]+)*)?(?:\\+[\\da-z\\-]+(?:.[\\da-z\\-]+)*)?';
|
||||
const semver = new RegExp(`v${regex}`, 'gi');
|
||||
const localPath = new RegExp('(../)?dist', 'gi');
|
||||
const versionPath = `https://${aws.cdn.domain}/${version}`;
|
||||
const cdnpath = new RegExp(`${aws.cdn.domain}/${regex}/`, 'gi');
|
||||
|
||||
gulp.task('version', () => {
|
||||
console.log(`Updating versions to '${version}'...`);
|
||||
|
||||
// Replace versioned URLs in source
|
||||
const files = [
|
||||
'plyr.js',
|
||||
'plyr.polyfilled.js',
|
||||
'defaults.js',
|
||||
];
|
||||
|
||||
return gulp
|
||||
.src(files.map(file => path.join(root, `src/js/${file}`)))
|
||||
.pipe(replace(semver, `v${version}`))
|
||||
.pipe(replace(cdnpath, `${aws.cdn.domain}/${version}/`))
|
||||
.pipe(gulp.dest(path.join(root, 'src/js/')));
|
||||
});
|
||||
|
||||
// Publish version to CDN bucket
|
||||
gulp.task('cdn', () => {
|
||||
if (!allowed.includes(branch.current)) {
|
||||
console.error(`Must be on ${allowed.join(', ')} to publish! (current: ${branch.current})`);
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(`Uploading '${version}' to ${aws.cdn.domain}...`);
|
||||
|
||||
// Upload to CDN
|
||||
return (
|
||||
gulp
|
||||
.src(paths.upload)
|
||||
.pipe(
|
||||
rename(p => {
|
||||
p.basename = p.basename.replace(minSuffix, ''); // eslint-disable-line
|
||||
p.dirname = p.dirname.replace('.', version); // eslint-disable-line
|
||||
}),
|
||||
)
|
||||
// Remove min suffix from source map URL
|
||||
.pipe(replace(/sourceMappingURL=([\w-?.]+)/, (match, p1) => `sourceMappingURL=${p1.replace(minSuffix, '')}`))
|
||||
.pipe(
|
||||
size({
|
||||
showFiles: true,
|
||||
gzip: true,
|
||||
}),
|
||||
)
|
||||
.pipe(replace(localPath, versionPath))
|
||||
.pipe(s3(aws.cdn, options.cdn))
|
||||
);
|
||||
});
|
||||
|
||||
// Publish to demo bucket
|
||||
gulp.task('demo', () => {
|
||||
if (!allowed.includes(branch.current)) {
|
||||
console.error(`Must be on ${allowed.join(', ')} to publish! (current: ${branch.current})`);
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(`Uploading '${version}' demo to ${aws.demo.domain}...`);
|
||||
|
||||
// Replace versioned files in readme.md
|
||||
gulp
|
||||
.src([`${root}/readme.md`])
|
||||
.pipe(replace(cdnpath, `${aws.cdn.domain}/${version}/`))
|
||||
.pipe(gulp.dest(root));
|
||||
|
||||
// Replace local file paths with remote paths in demo HTML
|
||||
// e.g. "../dist/plyr.js" to "https://cdn.plyr.io/x.x.x/plyr.js"
|
||||
const index = `${paths.demo.root}index.html`;
|
||||
const error = `${paths.demo.root}error.html`;
|
||||
const pages = [index];
|
||||
|
||||
if (branch.current === branch.master) {
|
||||
pages.push(error);
|
||||
}
|
||||
|
||||
gulp
|
||||
.src(pages)
|
||||
.pipe(replace(localPath, versionPath))
|
||||
.pipe(s3(aws.demo, options.demo));
|
||||
|
||||
// Only update CDN for master (prod)
|
||||
if (branch.current !== branch.master) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Upload error.html to cdn (as well as demo site)
|
||||
return gulp
|
||||
.src([error])
|
||||
.pipe(replace(localPath, versionPath))
|
||||
.pipe(s3(aws.cdn, options.demo));
|
||||
});
|
||||
|
||||
// Update symlinks for latest
|
||||
/* gulp.task("symlinks", function () {
|
||||
console.log("Updating symlinks...");
|
||||
|
||||
return gulp.src(paths.upload)
|
||||
.pipe(through.obj(function (chunk, enc, callback) {
|
||||
if (chunk.stat.isFile()) {
|
||||
// Get the filename
|
||||
var filename = chunk.path.split("/").reverse()[0];
|
||||
|
||||
// Create the 0 byte redirect files to upload
|
||||
createFile(filename, "")
|
||||
.pipe(rename(function (path) {
|
||||
path.dirname = path.dirname.replace(".", "latest");
|
||||
}))
|
||||
// Upload to S3 with correct headers
|
||||
.pipe(s3(aws.cdn, options.symlinks(version, filename)));
|
||||
}
|
||||
|
||||
callback(null, chunk);
|
||||
}));
|
||||
}); */
|
||||
|
||||
// Open the demo site to check it's sweet
|
||||
gulp.task('open', () => {
|
||||
console.log(`Opening ${aws.demo.domain}...`);
|
||||
|
||||
// A file must be specified or gulp will skip the task
|
||||
// Doesn't matter which file since we set the URL above
|
||||
// Weird, I know...
|
||||
return gulp.src([`${paths.demo.root}index.html`]).pipe(
|
||||
open('', {
|
||||
url: `http://${aws.demo.domain}`,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
// Do everything
|
||||
gulp.task('publish', callback => {
|
||||
run('version', tasks.clean, tasks.js, tasks.sass, tasks.sprite, 'cdn', 'demo', callback);
|
||||
});
|
||||
}
|
||||
|
||||
// Publish version to CDN bucket
|
||||
gulp.task('cdn', function() {
|
||||
console.log('Uploading ' + version + ' to ' + aws.cdn.domain + '...');
|
||||
|
||||
// Upload to CDN
|
||||
return gulp
|
||||
.src(paths.upload)
|
||||
.pipe(
|
||||
size({
|
||||
showFiles: true,
|
||||
gzip: true,
|
||||
}),
|
||||
)
|
||||
.pipe(
|
||||
rename(function(path) {
|
||||
path.dirname = path.dirname.replace('.', version);
|
||||
}),
|
||||
)
|
||||
.pipe(replace(localPath, versionPath))
|
||||
.pipe(s3(aws.cdn, options.cdn));
|
||||
});
|
||||
|
||||
// Publish to demo bucket
|
||||
gulp.task('demo', function() {
|
||||
console.log('Uploading ' + version + ' demo to ' + aws.demo.domain + '...');
|
||||
|
||||
// Replace versioned files in readme.md
|
||||
gulp
|
||||
.src([root + '/readme.md'])
|
||||
.pipe(replace(cdnpath, aws.cdn.domain + '/' + version))
|
||||
.pipe(gulp.dest(root));
|
||||
|
||||
// Replace versioned files in plyr.js
|
||||
gulp
|
||||
.src(path.join(root, 'src/js/plyr.js'))
|
||||
.pipe(replace(semver, 'v' + version))
|
||||
.pipe(replace(cdnpath, aws.cdn.domain + '/' + version))
|
||||
.pipe(gulp.dest(path.join(root, 'src/js/')));
|
||||
|
||||
// Replace local file paths with remote paths in demo HTML
|
||||
// e.g. "../dist/plyr.js" to "https://cdn.plyr.io/x.x.x/plyr.js"
|
||||
gulp
|
||||
.src([paths.demo.root + '*.html'])
|
||||
.pipe(replace(localPath, versionPath))
|
||||
.pipe(s3(aws.demo, options.demo));
|
||||
|
||||
// Upload error.html to cdn (as well as demo site)
|
||||
return gulp
|
||||
.src([paths.demo.root + 'error.html'])
|
||||
.pipe(replace(localPath, versionPath))
|
||||
.pipe(s3(aws.cdn, options.demo));
|
||||
});
|
||||
|
||||
// Open the demo site to check it's sweet
|
||||
gulp.task('symlinks', function() {
|
||||
console.log('Updating symlinks...');
|
||||
|
||||
return gulp.src(paths.upload).pipe(
|
||||
through.obj(function(chunk, enc, callback) {
|
||||
if (chunk.stat.isFile()) {
|
||||
// Get the filename
|
||||
var filename = chunk.path.split('/').reverse()[0];
|
||||
|
||||
// Create the 0 byte redirect files to upload
|
||||
createFile(filename, '')
|
||||
.pipe(
|
||||
rename(function(path) {
|
||||
path.dirname = path.dirname.replace('.', 'latest');
|
||||
}),
|
||||
)
|
||||
// Upload to S3 with correct headers
|
||||
.pipe(s3(aws.cdn, options.symlinks(version, filename)));
|
||||
}
|
||||
|
||||
callback(null, chunk);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
// Open the demo site to check it's sweet
|
||||
gulp.task('open', function() {
|
||||
console.log('Opening ' + aws.demo.domain + '...');
|
||||
|
||||
// A file must be specified or gulp will skip the task
|
||||
// Doesn't matter which file since we set the URL above
|
||||
// Weird, I know...
|
||||
return gulp.src([paths.demo.root + 'index.html']).pipe(
|
||||
open('', {
|
||||
url: 'http://' + aws.demo.domain,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
// Do everything
|
||||
gulp.task('publish', function() {
|
||||
run(tasks.js, tasks.less, tasks.sprite, 'cdn', 'demo', 'symlinks');
|
||||
});
|
||||
|
4604
package-lock.json
generated
81
package.json
@ -1,38 +1,58 @@
|
||||
{
|
||||
"name": "plyr",
|
||||
"version": "2.0.18",
|
||||
"version": "3.3.11",
|
||||
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
|
||||
"homepage": "http://plyr.io",
|
||||
"main": "src/js/plyr.js",
|
||||
"dependencies": {},
|
||||
"homepage": "https://plyr.io",
|
||||
"main": "./dist/plyr.js",
|
||||
"browser": "./dist/plyr.min.js",
|
||||
"sass": "./src/sass/plyr.scss",
|
||||
"style": "./dist/plyr.css",
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-eslint": "^8.2.3",
|
||||
"babel-plugin-external-helpers": "^6.22.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"del": "^3.0.0",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-airbnb-base": "^12.1.0",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-plugin-import": "^2.12.0",
|
||||
"git-branch": "^2.0.1",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-autoprefixer": "^4.0.0",
|
||||
"gulp-clean-css": "^3.9.0",
|
||||
"gulp-autoprefixer": "^5.0.0",
|
||||
"gulp-better-rollup": "^3.1.0",
|
||||
"gulp-clean-css": "^3.9.4",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-less": "^3.3.2",
|
||||
"gulp-open": "^2.0.0",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-replace": "^0.6.1",
|
||||
"gulp-filter": "^5.1.0",
|
||||
"gulp-header": "^2.0.5",
|
||||
"gulp-open": "^3.0.1",
|
||||
"gulp-postcss": "^7.0.1",
|
||||
"gulp-rename": "^1.2.3",
|
||||
"gulp-replace": "^1.0.0",
|
||||
"gulp-s3": "^0.11.0",
|
||||
"gulp-sass": "^3.1.0",
|
||||
"gulp-size": "^2.1.0",
|
||||
"gulp-sass": "^4.0.1",
|
||||
"gulp-size": "^3.0.0",
|
||||
"gulp-sourcemaps": "^2.6.4",
|
||||
"gulp-svgmin": "^1.2.4",
|
||||
"gulp-svgstore": "^6.1.0",
|
||||
"gulp-uglify": "^3.0.0",
|
||||
"gulp-svgstore": "^6.1.1",
|
||||
"gulp-uglify-es": "^1.0.4",
|
||||
"gulp-util": "^3.0.8",
|
||||
"run-sequence": "^2.2.0",
|
||||
"through2": "^2.0.3"
|
||||
"postcss-custom-properties": "^7.0.0",
|
||||
"prettier-eslint": "^8.8.1",
|
||||
"prettier-stylelint": "^0.4.2",
|
||||
"rollup-plugin-babel": "^3.0.4",
|
||||
"rollup-plugin-commonjs": "^9.1.3",
|
||||
"rollup-plugin-node-resolve": "^3.3.0",
|
||||
"run-sequence": "^2.2.1",
|
||||
"stylelint": "^9.2.1",
|
||||
"stylelint-config-prettier": "^3.2.0",
|
||||
"stylelint-config-recommended": "^2.1.0",
|
||||
"stylelint-config-sass-guidelines": "^5.0.0",
|
||||
"stylelint-order": "^0.8.1",
|
||||
"stylelint-scss": "^3.1.0",
|
||||
"stylelint-selector-bem-pattern": "^2.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"HTML5 Video",
|
||||
"HTML5 Audio",
|
||||
"Media Player",
|
||||
"DASH",
|
||||
"Shaka",
|
||||
"WordPress",
|
||||
"HLS"
|
||||
],
|
||||
"keywords": ["HTML5 Video", "HTML5 Audio", "Media Player", "DASH", "Shaka", "WordPress", "HLS"],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/sampotts/plyr.git"
|
||||
@ -45,7 +65,16 @@
|
||||
"doc": "readme.md"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp build",
|
||||
"lint": "eslint src/js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Sam Potts <sam@potts.es>"
|
||||
"author": "Sam Potts <sam@potts.es>",
|
||||
"dependencies": {
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"custom-event-polyfill": "^0.3.0",
|
||||
"loadjs": "^3.5.4",
|
||||
"raven-js": "^3.26.1",
|
||||
"url-polyfill": "^1.0.13"
|
||||
}
|
||||
}
|
||||
|
31
plyr.code-workspace
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
// Exclude from the editor
|
||||
"files.exclude": {
|
||||
"**/node_modules": true
|
||||
},
|
||||
// Exclude from search
|
||||
"search.exclude": {
|
||||
"dist/": true
|
||||
},
|
||||
// Linting
|
||||
"stylelint.enable": true,
|
||||
"css.validate": false,
|
||||
"scss.validate": false,
|
||||
"javascript.validate.enable": false,
|
||||
// Prettier
|
||||
"prettier.eslintIntegration": true,
|
||||
"prettier.stylelintIntegration": true,
|
||||
// Formatting
|
||||
"editor.tabSize": 4,
|
||||
"editor.insertSpaces": true,
|
||||
"editor.formatOnSave": true,
|
||||
// Trim on save
|
||||
"files.trimTrailingWhitespace": true
|
||||
}
|
||||
}
|
250
src/js/captions.js
Normal file
@ -0,0 +1,250 @@
|
||||
// ==========================================================================
|
||||
// Plyr Captions
|
||||
// TODO: Create as class
|
||||
// ==========================================================================
|
||||
|
||||
import controls from './controls';
|
||||
import i18n from './i18n';
|
||||
import support from './support';
|
||||
import utils from './utils';
|
||||
|
||||
const captions = {
|
||||
// Setup captions
|
||||
setup() {
|
||||
// Requires UI support
|
||||
if (!this.supported.ui) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only Vimeo and HTML5 video supported at this point
|
||||
if (!this.isVideo || this.isYouTube || (this.isHTML5 && !support.textTracks)) {
|
||||
// Clear menu and hide
|
||||
if (utils.is.array(this.config.controls) && this.config.controls.includes('settings') && this.config.settings.includes('captions')) {
|
||||
controls.setCaptionsMenu.call(this);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Inject the container
|
||||
if (!utils.is.element(this.elements.captions)) {
|
||||
this.elements.captions = utils.createElement('div', utils.getAttributesFromSelector(this.config.selectors.captions));
|
||||
|
||||
utils.insertAfter(this.elements.captions, this.elements.wrapper);
|
||||
}
|
||||
|
||||
// Get browser info
|
||||
const browser = utils.getBrowser();
|
||||
|
||||
// Fix IE captions if CORS is used
|
||||
// Fetch captions and inject as blobs instead (data URIs not supported!)
|
||||
if (browser.isIE && window.URL) {
|
||||
const elements = this.media.querySelectorAll('track');
|
||||
|
||||
Array.from(elements).forEach(track => {
|
||||
const src = track.getAttribute('src');
|
||||
const href = utils.parseUrl(src);
|
||||
|
||||
if (href.hostname !== window.location.href.hostname && [
|
||||
'http:',
|
||||
'https:',
|
||||
].includes(href.protocol)) {
|
||||
utils
|
||||
.fetch(src, 'blob')
|
||||
.then(blob => {
|
||||
track.setAttribute('src', window.URL.createObjectURL(blob));
|
||||
})
|
||||
.catch(() => {
|
||||
utils.removeElement(track);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Try to load the value from storage
|
||||
let active = this.storage.get('captions');
|
||||
|
||||
// Otherwise fall back to the default config
|
||||
if (!utils.is.boolean(active)) {
|
||||
({ active } = this.config.captions);
|
||||
}
|
||||
|
||||
// Set toggled state
|
||||
this.toggleCaptions(active);
|
||||
|
||||
// Watch changes to textTracks and update captions menu
|
||||
if (this.config.captions.update) {
|
||||
utils.on(this.media.textTracks, 'addtrack removetrack', captions.update.bind(this));
|
||||
}
|
||||
|
||||
// Update available languages in list next tick (the event must not be triggered before the listeners)
|
||||
setTimeout(captions.update.bind(this), 0);
|
||||
},
|
||||
|
||||
update() {
|
||||
// Update tracks
|
||||
const tracks = captions.getTracks.call(this);
|
||||
this.options.captions = tracks.map(({language}) => language);
|
||||
|
||||
// Set language if it hasn't been set already
|
||||
if (!this.language) {
|
||||
let { language } = this.config.captions;
|
||||
if (language === 'auto') {
|
||||
[ language ] = (navigator.language || navigator.userLanguage).split('-');
|
||||
}
|
||||
this.language = this.storage.get('language') || (language || '').toLowerCase();
|
||||
}
|
||||
|
||||
// Toggle the class hooks
|
||||
utils.toggleClass(this.elements.container, this.config.classNames.captions.enabled, !utils.is.empty(captions.getTracks.call(this)));
|
||||
|
||||
// Update available languages in list
|
||||
if ((this.config.controls || []).includes('settings') && this.config.settings.includes('captions')) {
|
||||
controls.setCaptionsMenu.call(this);
|
||||
}
|
||||
},
|
||||
|
||||
// Set the captions language
|
||||
setLanguage() {
|
||||
// Setup HTML5 track rendering
|
||||
if (this.isHTML5 && this.isVideo) {
|
||||
captions.getTracks.call(this).forEach(track => {
|
||||
// Show track
|
||||
utils.on(track, 'cuechange', event => captions.setCue.call(this, event));
|
||||
|
||||
// Turn off native caption rendering to avoid double captions
|
||||
// eslint-disable-next-line
|
||||
track.mode = 'hidden';
|
||||
});
|
||||
|
||||
// Get current track
|
||||
const currentTrack = captions.getCurrentTrack.call(this);
|
||||
|
||||
// Check if suported kind
|
||||
if (utils.is.track(currentTrack)) {
|
||||
// If we change the active track while a cue is already displayed we need to update it
|
||||
if (Array.from(currentTrack.activeCues || []).length) {
|
||||
captions.setCue.call(this, currentTrack);
|
||||
}
|
||||
}
|
||||
} else if (this.isVimeo && this.captions.active) {
|
||||
this.embed.enableTextTrack(this.language);
|
||||
}
|
||||
},
|
||||
|
||||
// Get the tracks
|
||||
getTracks() {
|
||||
// Return empty array at least
|
||||
if (utils.is.nullOrUndefined(this.media)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Only get accepted kinds
|
||||
return Array.from(this.media.textTracks || []).filter(track => [
|
||||
'captions',
|
||||
'subtitles',
|
||||
].includes(track.kind));
|
||||
},
|
||||
|
||||
// Get the current track for the current language
|
||||
getCurrentTrack() {
|
||||
const tracks = captions.getTracks.call(this);
|
||||
|
||||
if (!tracks.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get track based on current language
|
||||
let track = tracks.find(track => track.language.toLowerCase() === this.language);
|
||||
|
||||
// Get the <track> with default attribute
|
||||
if (!track) {
|
||||
track = utils.getElement.call(this, 'track[default]');
|
||||
}
|
||||
|
||||
// Get the first track
|
||||
if (!track) {
|
||||
[track] = tracks;
|
||||
}
|
||||
|
||||
return track;
|
||||
},
|
||||
|
||||
// Get UI label for track
|
||||
getLabel(track) {
|
||||
let currentTrack = track;
|
||||
|
||||
if (!utils.is.track(currentTrack) && support.textTracks && this.captions.active) {
|
||||
currentTrack = captions.getCurrentTrack.call(this);
|
||||
}
|
||||
|
||||
if (utils.is.track(currentTrack)) {
|
||||
if (!utils.is.empty(currentTrack.label)) {
|
||||
return currentTrack.label;
|
||||
}
|
||||
|
||||
if (!utils.is.empty(currentTrack.language)) {
|
||||
return track.language.toUpperCase();
|
||||
}
|
||||
|
||||
return i18n.get('enabled', this.config);
|
||||
}
|
||||
|
||||
return i18n.get('disabled', this.config);
|
||||
},
|
||||
|
||||
// Display active caption if it contains text
|
||||
setCue(input) {
|
||||
// Get the track from the event if needed
|
||||
const track = utils.is.event(input) ? input.target : input;
|
||||
const { activeCues } = track;
|
||||
const active = activeCues.length && activeCues[0];
|
||||
const currentTrack = captions.getCurrentTrack.call(this);
|
||||
|
||||
// Only display current track
|
||||
if (track !== currentTrack) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Display a cue, if there is one
|
||||
if (utils.is.cue(active)) {
|
||||
captions.setText.call(this, active.getCueAsHTML());
|
||||
} else {
|
||||
captions.setText.call(this, null);
|
||||
}
|
||||
|
||||
utils.dispatchEvent.call(this, this.media, 'cuechange');
|
||||
},
|
||||
|
||||
// Set the current caption
|
||||
setText(input) {
|
||||
// Requires UI
|
||||
if (!this.supported.ui) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils.is.element(this.elements.captions)) {
|
||||
const content = utils.createElement('span');
|
||||
|
||||
// Empty the container
|
||||
utils.emptyElement(this.elements.captions);
|
||||
|
||||
// Default to empty
|
||||
const caption = !utils.is.nullOrUndefined(input) ? input : '';
|
||||
|
||||
// Set the span content
|
||||
if (utils.is.string(caption)) {
|
||||
content.innerText = caption.trim();
|
||||
} else {
|
||||
content.appendChild(caption);
|
||||
}
|
||||
|
||||
// Set new caption text
|
||||
this.elements.captions.appendChild(content);
|
||||
} else {
|
||||
this.debug.warn('No captions element to render to');
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default captions;
|
28
src/js/console.js
Normal file
@ -0,0 +1,28 @@
|
||||
// ==========================================================================
|
||||
// Console wrapper
|
||||
// ==========================================================================
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
export default class Console {
|
||||
constructor(enabled = false) {
|
||||
this.enabled = window.console && enabled;
|
||||
|
||||
if (this.enabled) {
|
||||
this.log('Debugging enabled');
|
||||
}
|
||||
}
|
||||
|
||||
get log() {
|
||||
// eslint-disable-next-line no-console
|
||||
return this.enabled ? Function.prototype.bind.call(console.log, console) : noop;
|
||||
}
|
||||
get warn() {
|
||||
// eslint-disable-next-line no-console
|
||||
return this.enabled ? Function.prototype.bind.call(console.warn, console) : noop;
|
||||
}
|
||||
get error() {
|
||||
// eslint-disable-next-line no-console
|
||||
return this.enabled ? Function.prototype.bind.call(console.error, console) : noop;
|
||||
}
|
||||
}
|
1481
src/js/controls.js
vendored
Normal file
405
src/js/defaults.js
Normal file
@ -0,0 +1,405 @@
|
||||
// ==========================================================================
|
||||
// Plyr default config
|
||||
// ==========================================================================
|
||||
|
||||
const defaults = {
|
||||
// Disable
|
||||
enabled: true,
|
||||
|
||||
// Custom media title
|
||||
title: '',
|
||||
|
||||
// Logging to console
|
||||
debug: false,
|
||||
|
||||
// Auto play (if supported)
|
||||
autoplay: false,
|
||||
|
||||
// Only allow one media playing at once (vimeo only)
|
||||
autopause: true,
|
||||
|
||||
// Default time to skip when rewind/fast forward
|
||||
seekTime: 10,
|
||||
|
||||
// Default volume
|
||||
volume: 1,
|
||||
muted: false,
|
||||
|
||||
// Pass a custom duration
|
||||
duration: null,
|
||||
|
||||
// Display the media duration on load in the current time position
|
||||
// If you have opted to display both duration and currentTime, this is ignored
|
||||
displayDuration: true,
|
||||
|
||||
// Invert the current time to be a countdown
|
||||
invertTime: true,
|
||||
|
||||
// Clicking the currentTime inverts it's value to show time left rather than elapsed
|
||||
toggleInvert: true,
|
||||
|
||||
// Aspect ratio (for embeds)
|
||||
ratio: '16:9',
|
||||
|
||||
// Click video container to play/pause
|
||||
clickToPlay: true,
|
||||
|
||||
// Auto hide the controls
|
||||
hideControls: true,
|
||||
|
||||
// Reset to start when playback ended
|
||||
resetOnEnd: false,
|
||||
|
||||
// Disable the standard context menu
|
||||
disableContextMenu: true,
|
||||
|
||||
// Sprite (for icons)
|
||||
loadSprite: true,
|
||||
iconPrefix: 'plyr',
|
||||
iconUrl: 'https://cdn.plyr.io/3.3.11/plyr.svg',
|
||||
|
||||
// Blank video (used to prevent errors on source change)
|
||||
blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
|
||||
|
||||
// Quality default
|
||||
quality: {
|
||||
default: 576,
|
||||
options: [
|
||||
4320,
|
||||
2880,
|
||||
2160,
|
||||
1440,
|
||||
1080,
|
||||
720,
|
||||
576,
|
||||
480,
|
||||
360,
|
||||
240,
|
||||
'default', // YouTube's "auto"
|
||||
],
|
||||
},
|
||||
|
||||
// Set loops
|
||||
loop: {
|
||||
active: false,
|
||||
// start: null,
|
||||
// end: null,
|
||||
},
|
||||
|
||||
// Speed default and options to display
|
||||
speed: {
|
||||
selected: 1,
|
||||
options: [
|
||||
0.5,
|
||||
0.75,
|
||||
1,
|
||||
1.25,
|
||||
1.5,
|
||||
1.75,
|
||||
2,
|
||||
],
|
||||
},
|
||||
|
||||
// Keyboard shortcut settings
|
||||
keyboard: {
|
||||
focused: true,
|
||||
global: false,
|
||||
},
|
||||
|
||||
// Display tooltips
|
||||
tooltips: {
|
||||
controls: false,
|
||||
seek: true,
|
||||
},
|
||||
|
||||
// Captions settings
|
||||
captions: {
|
||||
active: false,
|
||||
language: 'auto',
|
||||
// Listen to new tracks added after Plyr is initialized.
|
||||
// This is needed for streaming captions, but may result in unselectable options
|
||||
update: false,
|
||||
},
|
||||
|
||||
// Fullscreen settings
|
||||
fullscreen: {
|
||||
enabled: true, // Allow fullscreen?
|
||||
fallback: true, // Fallback for vintage browsers
|
||||
iosNative: false, // Use the native fullscreen in iOS (disables custom controls)
|
||||
},
|
||||
|
||||
// Local storage
|
||||
storage: {
|
||||
enabled: true,
|
||||
key: 'plyr',
|
||||
},
|
||||
|
||||
// Default controls
|
||||
controls: [
|
||||
'play-large',
|
||||
// 'restart',
|
||||
// 'rewind',
|
||||
'play',
|
||||
// 'fast-forward',
|
||||
'progress',
|
||||
'current-time',
|
||||
'mute',
|
||||
'volume',
|
||||
'captions',
|
||||
'settings',
|
||||
'pip',
|
||||
'airplay',
|
||||
'fullscreen',
|
||||
],
|
||||
settings: [
|
||||
'captions',
|
||||
'quality',
|
||||
'speed',
|
||||
],
|
||||
|
||||
// Localisation
|
||||
i18n: {
|
||||
restart: 'Restart',
|
||||
rewind: 'Rewind {seektime}s',
|
||||
play: 'Play',
|
||||
pause: 'Pause',
|
||||
fastForward: 'Forward {seektime}s',
|
||||
seek: 'Seek',
|
||||
played: 'Played',
|
||||
buffered: 'Buffered',
|
||||
currentTime: 'Current time',
|
||||
duration: 'Duration',
|
||||
volume: 'Volume',
|
||||
mute: 'Mute',
|
||||
unmute: 'Unmute',
|
||||
enableCaptions: 'Enable captions',
|
||||
disableCaptions: 'Disable captions',
|
||||
enterFullscreen: 'Enter fullscreen',
|
||||
exitFullscreen: 'Exit fullscreen',
|
||||
frameTitle: 'Player for {title}',
|
||||
captions: 'Captions',
|
||||
settings: 'Settings',
|
||||
speed: 'Speed',
|
||||
normal: 'Normal',
|
||||
quality: 'Quality',
|
||||
loop: 'Loop',
|
||||
start: 'Start',
|
||||
end: 'End',
|
||||
all: 'All',
|
||||
reset: 'Reset',
|
||||
disabled: 'Disabled',
|
||||
enabled: 'Enabled',
|
||||
advertisement: 'Ad',
|
||||
qualityBadge: {
|
||||
2160: '4K',
|
||||
1440: 'HD',
|
||||
1080: 'HD',
|
||||
720: 'HD',
|
||||
576: 'SD',
|
||||
480: 'SD',
|
||||
},
|
||||
},
|
||||
|
||||
// URLs
|
||||
urls: {
|
||||
vimeo: {
|
||||
sdk: 'https://player.vimeo.com/api/player.js',
|
||||
iframe: 'https://player.vimeo.com/video/{0}?{1}',
|
||||
api: 'https://vimeo.com/api/v2/video/{0}.json',
|
||||
},
|
||||
youtube: {
|
||||
sdk: 'https://www.youtube.com/iframe_api',
|
||||
api: 'https://www.googleapis.com/youtube/v3/videos?id={0}&key={1}&fields=items(snippet(title))&part=snippet',
|
||||
},
|
||||
googleIMA: {
|
||||
sdk: 'https://imasdk.googleapis.com/js/sdkloader/ima3.js',
|
||||
},
|
||||
},
|
||||
|
||||
// Custom control listeners
|
||||
listeners: {
|
||||
seek: null,
|
||||
play: null,
|
||||
pause: null,
|
||||
restart: null,
|
||||
rewind: null,
|
||||
fastForward: null,
|
||||
mute: null,
|
||||
volume: null,
|
||||
captions: null,
|
||||
fullscreen: null,
|
||||
pip: null,
|
||||
airplay: null,
|
||||
speed: null,
|
||||
quality: null,
|
||||
loop: null,
|
||||
language: null,
|
||||
},
|
||||
|
||||
// Events to watch and bubble
|
||||
events: [
|
||||
// Events to watch on HTML5 media elements and bubble
|
||||
// https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events
|
||||
'ended',
|
||||
'progress',
|
||||
'stalled',
|
||||
'playing',
|
||||
'waiting',
|
||||
'canplay',
|
||||
'canplaythrough',
|
||||
'loadstart',
|
||||
'loadeddata',
|
||||
'loadedmetadata',
|
||||
'timeupdate',
|
||||
'volumechange',
|
||||
'play',
|
||||
'pause',
|
||||
'error',
|
||||
'seeking',
|
||||
'seeked',
|
||||
'emptied',
|
||||
'ratechange',
|
||||
'cuechange',
|
||||
|
||||
// Custom events
|
||||
'enterfullscreen',
|
||||
'exitfullscreen',
|
||||
'captionsenabled',
|
||||
'captionsdisabled',
|
||||
'languagechange',
|
||||
'controlshidden',
|
||||
'controlsshown',
|
||||
'ready',
|
||||
|
||||
// YouTube
|
||||
'statechange',
|
||||
'qualitychange',
|
||||
'qualityrequested',
|
||||
|
||||
// Ads
|
||||
'adsloaded',
|
||||
'adscontentpause',
|
||||
'adscontentresume',
|
||||
'adstarted',
|
||||
'adsmidpoint',
|
||||
'adscomplete',
|
||||
'adsallcomplete',
|
||||
'adsimpression',
|
||||
'adsclick',
|
||||
],
|
||||
|
||||
// Selectors
|
||||
// Change these to match your template if using custom HTML
|
||||
selectors: {
|
||||
editable: 'input, textarea, select, [contenteditable]',
|
||||
container: '.plyr',
|
||||
controls: {
|
||||
container: null,
|
||||
wrapper: '.plyr__controls',
|
||||
},
|
||||
labels: '[data-plyr]',
|
||||
buttons: {
|
||||
play: '[data-plyr="play"]',
|
||||
pause: '[data-plyr="pause"]',
|
||||
restart: '[data-plyr="restart"]',
|
||||
rewind: '[data-plyr="rewind"]',
|
||||
fastForward: '[data-plyr="fast-forward"]',
|
||||
mute: '[data-plyr="mute"]',
|
||||
captions: '[data-plyr="captions"]',
|
||||
fullscreen: '[data-plyr="fullscreen"]',
|
||||
pip: '[data-plyr="pip"]',
|
||||
airplay: '[data-plyr="airplay"]',
|
||||
settings: '[data-plyr="settings"]',
|
||||
loop: '[data-plyr="loop"]',
|
||||
},
|
||||
inputs: {
|
||||
seek: '[data-plyr="seek"]',
|
||||
volume: '[data-plyr="volume"]',
|
||||
speed: '[data-plyr="speed"]',
|
||||
language: '[data-plyr="language"]',
|
||||
quality: '[data-plyr="quality"]',
|
||||
},
|
||||
display: {
|
||||
currentTime: '.plyr__time--current',
|
||||
duration: '.plyr__time--duration',
|
||||
buffer: '.plyr__progress__buffer',
|
||||
loop: '.plyr__progress__loop', // Used later
|
||||
volume: '.plyr__volume--display',
|
||||
},
|
||||
progress: '.plyr__progress',
|
||||
captions: '.plyr__captions',
|
||||
menu: {
|
||||
quality: '.js-plyr__menu__list--quality',
|
||||
},
|
||||
},
|
||||
|
||||
// Class hooks added to the player in different states
|
||||
classNames: {
|
||||
type: 'plyr--{0}',
|
||||
provider: 'plyr--{0}',
|
||||
video: 'plyr__video-wrapper',
|
||||
embed: 'plyr__video-embed',
|
||||
embedContainer: 'plyr__video-embed__container',
|
||||
poster: 'plyr__poster',
|
||||
posterEnabled: 'plyr__poster-enabled',
|
||||
ads: 'plyr__ads',
|
||||
control: 'plyr__control',
|
||||
playing: 'plyr--playing',
|
||||
paused: 'plyr--paused',
|
||||
stopped: 'plyr--stopped',
|
||||
loading: 'plyr--loading',
|
||||
hover: 'plyr--hover',
|
||||
tooltip: 'plyr__tooltip',
|
||||
cues: 'plyr__cues',
|
||||
hidden: 'plyr__sr-only',
|
||||
hideControls: 'plyr--hide-controls',
|
||||
isIos: 'plyr--is-ios',
|
||||
isTouch: 'plyr--is-touch',
|
||||
uiSupported: 'plyr--full-ui',
|
||||
noTransition: 'plyr--no-transition',
|
||||
menu: {
|
||||
value: 'plyr__menu__value',
|
||||
badge: 'plyr__badge',
|
||||
open: 'plyr--menu-open',
|
||||
},
|
||||
captions: {
|
||||
enabled: 'plyr--captions-enabled',
|
||||
active: 'plyr--captions-active',
|
||||
},
|
||||
fullscreen: {
|
||||
enabled: 'plyr--fullscreen-enabled',
|
||||
fallback: 'plyr--fullscreen-fallback',
|
||||
},
|
||||
pip: {
|
||||
supported: 'plyr--pip-supported',
|
||||
active: 'plyr--pip-active',
|
||||
},
|
||||
airplay: {
|
||||
supported: 'plyr--airplay-supported',
|
||||
active: 'plyr--airplay-active',
|
||||
},
|
||||
tabFocus: 'plyr__tab-focus',
|
||||
},
|
||||
|
||||
// Embed attributes
|
||||
attributes: {
|
||||
embed: {
|
||||
provider: 'data-plyr-provider',
|
||||
id: 'data-plyr-embed-id',
|
||||
},
|
||||
},
|
||||
|
||||
// API keys
|
||||
keys: {
|
||||
google: null,
|
||||
},
|
||||
|
||||
// Advertisements plugin
|
||||
// Register for an account here: http://vi.ai/publisher-video-monetization/?aid=plyrio
|
||||
ads: {
|
||||
enabled: false,
|
||||
publisherId: '',
|
||||
},
|
||||
};
|
||||
|
||||
export default defaults;
|
213
src/js/fullscreen.js
Normal file
@ -0,0 +1,213 @@
|
||||
// ==========================================================================
|
||||
// Fullscreen wrapper
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API#prefixing
|
||||
// ==========================================================================
|
||||
|
||||
import utils from './utils';
|
||||
|
||||
const browser = utils.getBrowser();
|
||||
|
||||
function onChange() {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update toggle button
|
||||
const button = this.player.elements.buttons.fullscreen;
|
||||
if (utils.is.element(button)) {
|
||||
utils.toggleState(button, this.active);
|
||||
}
|
||||
|
||||
// Trigger an event
|
||||
utils.dispatchEvent.call(this.player, this.target, this.active ? 'enterfullscreen' : 'exitfullscreen', true);
|
||||
|
||||
// Trap focus in container
|
||||
if (!browser.isIos) {
|
||||
utils.trapFocus.call(this.player, this.target, this.active);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleFallback(toggle = false) {
|
||||
// Store or restore scroll position
|
||||
if (toggle) {
|
||||
this.scrollPosition = {
|
||||
x: window.scrollX || 0,
|
||||
y: window.scrollY || 0,
|
||||
};
|
||||
} else {
|
||||
window.scrollTo(this.scrollPosition.x, this.scrollPosition.y);
|
||||
}
|
||||
|
||||
// Toggle scroll
|
||||
document.body.style.overflow = toggle ? 'hidden' : '';
|
||||
|
||||
// Toggle class hook
|
||||
utils.toggleClass(this.target, this.player.config.classNames.fullscreen.fallback, toggle);
|
||||
|
||||
// Toggle button and fire events
|
||||
onChange.call(this);
|
||||
}
|
||||
|
||||
class Fullscreen {
|
||||
constructor(player) {
|
||||
// Keep reference to parent
|
||||
this.player = player;
|
||||
|
||||
// Get prefix
|
||||
this.prefix = Fullscreen.prefix;
|
||||
this.property = Fullscreen.property;
|
||||
|
||||
// Scroll position
|
||||
this.scrollPosition = { x: 0, y: 0 };
|
||||
|
||||
// Register event listeners
|
||||
// Handle event (incase user presses escape etc)
|
||||
utils.on(document, this.prefix === 'ms' ? 'MSFullscreenChange' : `${this.prefix}fullscreenchange`, () => {
|
||||
// TODO: Filter for target??
|
||||
onChange.call(this);
|
||||
});
|
||||
|
||||
// Fullscreen toggle on double click
|
||||
utils.on(this.player.elements.container, 'dblclick', event => {
|
||||
// Ignore double click in controls
|
||||
if (utils.is.element(this.player.elements.controls) && this.player.elements.controls.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.toggle();
|
||||
});
|
||||
|
||||
// Update the UI
|
||||
this.update();
|
||||
}
|
||||
|
||||
// Determine if native supported
|
||||
static get native() {
|
||||
return !!(document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || document.msFullscreenEnabled);
|
||||
}
|
||||
|
||||
// Get the prefix for handlers
|
||||
static get prefix() {
|
||||
// No prefix
|
||||
if (utils.is.function(document.exitFullscreen)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Check for fullscreen support by vendor prefix
|
||||
let value = '';
|
||||
const prefixes = [
|
||||
'webkit',
|
||||
'moz',
|
||||
'ms',
|
||||
];
|
||||
|
||||
prefixes.some(pre => {
|
||||
if (utils.is.function(document[`${pre}ExitFullscreen`]) || utils.is.function(document[`${pre}CancelFullScreen`])) {
|
||||
value = pre;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static get property() {
|
||||
return this.prefix === 'moz' ? 'FullScreen' : 'Fullscreen';
|
||||
}
|
||||
|
||||
// Determine if fullscreen is enabled
|
||||
get enabled() {
|
||||
return (
|
||||
(Fullscreen.native || this.player.config.fullscreen.fallback) &&
|
||||
this.player.config.fullscreen.enabled &&
|
||||
this.player.supported.ui &&
|
||||
this.player.isVideo
|
||||
);
|
||||
}
|
||||
|
||||
// Get active state
|
||||
get active() {
|
||||
if (!this.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fallback using classname
|
||||
if (!Fullscreen.native) {
|
||||
return utils.hasClass(this.target, this.player.config.classNames.fullscreen.fallback);
|
||||
}
|
||||
|
||||
const element = !this.prefix ? document.fullscreenElement : document[`${this.prefix}${this.property}Element`];
|
||||
|
||||
return element === this.target;
|
||||
}
|
||||
|
||||
// Get target element
|
||||
get target() {
|
||||
return browser.isIos && this.player.config.fullscreen.iosNative ? this.player.media : this.player.elements.container;
|
||||
}
|
||||
|
||||
// Update UI
|
||||
update() {
|
||||
if (this.enabled) {
|
||||
this.player.debug.log(`${Fullscreen.native ? 'Native' : 'Fallback'} fullscreen enabled`);
|
||||
} else {
|
||||
this.player.debug.log('Fullscreen not supported and fallback disabled');
|
||||
}
|
||||
|
||||
// Add styling hook to show button
|
||||
utils.toggleClass(this.player.elements.container, this.player.config.classNames.fullscreen.enabled, this.enabled);
|
||||
}
|
||||
|
||||
// Make an element fullscreen
|
||||
enter() {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// iOS native fullscreen doesn't need the request step
|
||||
if (browser.isIos && this.player.config.fullscreen.iosNative) {
|
||||
if (this.player.playing) {
|
||||
this.target.webkitEnterFullscreen();
|
||||
}
|
||||
} else if (!Fullscreen.native) {
|
||||
toggleFallback.call(this, true);
|
||||
} else if (!this.prefix) {
|
||||
this.target.requestFullscreen();
|
||||
} else if (!utils.is.empty(this.prefix)) {
|
||||
this.target[`${this.prefix}Request${this.property}`]();
|
||||
}
|
||||
}
|
||||
|
||||
// Bail from fullscreen
|
||||
exit() {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// iOS native fullscreen
|
||||
if (browser.isIos && this.player.config.fullscreen.iosNative) {
|
||||
this.target.webkitExitFullscreen();
|
||||
this.player.play();
|
||||
} else if (!Fullscreen.native) {
|
||||
toggleFallback.call(this, false);
|
||||
} else if (!this.prefix) {
|
||||
(document.cancelFullScreen || document.exitFullscreen).call(document);
|
||||
} else if (!utils.is.empty(this.prefix)) {
|
||||
const action = this.prefix === 'moz' ? 'Cancel' : 'Exit';
|
||||
document[`${this.prefix}${action}${this.property}`]();
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle state
|
||||
toggle() {
|
||||
if (!this.active) {
|
||||
this.enter();
|
||||
} else {
|
||||
this.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Fullscreen;
|
150
src/js/html5.js
Normal file
@ -0,0 +1,150 @@
|
||||
// ==========================================================================
|
||||
// Plyr HTML5 helpers
|
||||
// ==========================================================================
|
||||
|
||||
import support from './support';
|
||||
import utils from './utils';
|
||||
|
||||
const html5 = {
|
||||
getSources() {
|
||||
if (!this.isHTML5) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.media.querySelectorAll('source');
|
||||
},
|
||||
|
||||
// Get quality levels
|
||||
getQualityOptions() {
|
||||
if (!this.isHTML5) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get sources
|
||||
const sources = html5.getSources.call(this);
|
||||
|
||||
if (utils.is.empty(sources)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get <source> with size attribute
|
||||
const sizes = Array.from(sources).filter(source => !utils.is.empty(source.getAttribute('size')));
|
||||
|
||||
// If none, bail
|
||||
if (utils.is.empty(sizes)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Reduce to unique list
|
||||
return utils.dedupe(sizes.map(source => Number(source.getAttribute('size'))));
|
||||
},
|
||||
|
||||
extend() {
|
||||
if (!this.isHTML5) {
|
||||
return;
|
||||
}
|
||||
|
||||
const player = this;
|
||||
|
||||
// Quality
|
||||
Object.defineProperty(player.media, 'quality', {
|
||||
get() {
|
||||
// Get sources
|
||||
const sources = html5.getSources.call(player);
|
||||
|
||||
if (utils.is.empty(sources)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const matches = Array.from(sources).filter(source => source.getAttribute('src') === player.source);
|
||||
|
||||
if (utils.is.empty(matches)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Number(matches[0].getAttribute('size'));
|
||||
},
|
||||
set(input) {
|
||||
// Get sources
|
||||
const sources = html5.getSources.call(player);
|
||||
|
||||
if (utils.is.empty(sources)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get matches for requested size
|
||||
const matches = Array.from(sources).filter(source => Number(source.getAttribute('size')) === input);
|
||||
|
||||
// No matches for requested size
|
||||
if (utils.is.empty(matches)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get supported sources
|
||||
const supported = matches.filter(source => support.mime.call(player, source.getAttribute('type')));
|
||||
|
||||
// No supported sources
|
||||
if (utils.is.empty(supported)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Trigger change event
|
||||
utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {
|
||||
quality: input,
|
||||
});
|
||||
|
||||
// Get current state
|
||||
const { currentTime, playing } = player;
|
||||
|
||||
// Set new source
|
||||
player.media.src = supported[0].getAttribute('src');
|
||||
|
||||
// Restore time
|
||||
const onLoadedMetaData = () => {
|
||||
player.currentTime = currentTime;
|
||||
player.off('loadedmetadata', onLoadedMetaData);
|
||||
};
|
||||
player.on('loadedmetadata', onLoadedMetaData);
|
||||
|
||||
// Load new source
|
||||
player.media.load();
|
||||
|
||||
// Resume playing
|
||||
if (playing) {
|
||||
player.play();
|
||||
}
|
||||
|
||||
// Trigger change event
|
||||
utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
|
||||
quality: input,
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// Cancel current network requests
|
||||
// See https://github.com/sampotts/plyr/issues/174
|
||||
cancelRequests() {
|
||||
if (!this.isHTML5) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove child sources
|
||||
utils.removeElement(html5.getSources());
|
||||
|
||||
// Set blank video src attribute
|
||||
// This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
|
||||
// Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
|
||||
this.media.setAttribute('src', this.config.blankVideo);
|
||||
|
||||
// Load the new empty source
|
||||
// This will cancel existing requests
|
||||
// See https://github.com/sampotts/plyr/issues/174
|
||||
this.media.load();
|
||||
|
||||
// Debugging
|
||||
this.debug.log('Cancelled network requests');
|
||||
},
|
||||
};
|
||||
|
||||
export default html5;
|
35
src/js/i18n.js
Normal file
@ -0,0 +1,35 @@
|
||||
// ==========================================================================
|
||||
// Plyr internationalization
|
||||
// ==========================================================================
|
||||
|
||||
import utils from './utils';
|
||||
|
||||
const i18n = {
|
||||
get(key = '', config = {}) {
|
||||
if (utils.is.empty(key) || utils.is.empty(config)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let string = utils.getDeep(config.i18n, key);
|
||||
|
||||
if (utils.is.empty(string)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const replace = {
|
||||
'{seektime}': config.seekTime,
|
||||
'{title}': config.title,
|
||||
};
|
||||
|
||||
Object.entries(replace).forEach(([
|
||||
key,
|
||||
value,
|
||||
]) => {
|
||||
string = utils.replaceAll(string, key, value);
|
||||
});
|
||||
|
||||
return string;
|
||||
},
|
||||
};
|
||||
|
||||
export default i18n;
|
728
src/js/listeners.js
Normal file
@ -0,0 +1,728 @@
|
||||
// ==========================================================================
|
||||
// Plyr Event Listeners
|
||||
// ==========================================================================
|
||||
|
||||
import controls from './controls';
|
||||
import ui from './ui';
|
||||
import utils from './utils';
|
||||
|
||||
// Sniff out the browser
|
||||
const browser = utils.getBrowser();
|
||||
|
||||
class Listeners {
|
||||
constructor(player) {
|
||||
this.player = player;
|
||||
this.lastKey = null;
|
||||
|
||||
this.handleKey = this.handleKey.bind(this);
|
||||
this.toggleMenu = this.toggleMenu.bind(this);
|
||||
this.firstTouch = this.firstTouch.bind(this);
|
||||
}
|
||||
|
||||
// Handle key presses
|
||||
handleKey(event) {
|
||||
const code = event.keyCode ? event.keyCode : event.which;
|
||||
const pressed = event.type === 'keydown';
|
||||
const repeat = pressed && code === this.lastKey;
|
||||
|
||||
// Bail if a modifier key is set
|
||||
if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the event is bubbled from the media element
|
||||
// Firefox doesn't get the keycode for whatever reason
|
||||
if (!utils.is.number(code)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Seek by the number keys
|
||||
const seekByKey = () => {
|
||||
// Divide the max duration into 10th's and times by the number value
|
||||
this.player.currentTime = this.player.duration / 10 * (code - 48);
|
||||
};
|
||||
|
||||
// Handle the key on keydown
|
||||
// Reset on keyup
|
||||
if (pressed) {
|
||||
// Which keycodes should we prevent default
|
||||
const preventDefault = [
|
||||
48,
|
||||
49,
|
||||
50,
|
||||
51,
|
||||
52,
|
||||
53,
|
||||
54,
|
||||
56,
|
||||
57,
|
||||
32,
|
||||
75,
|
||||
38,
|
||||
40,
|
||||
77,
|
||||
39,
|
||||
37,
|
||||
70,
|
||||
67,
|
||||
73,
|
||||
76,
|
||||
79,
|
||||
];
|
||||
|
||||
// Check focused element
|
||||
// and if the focused element is not editable (e.g. text input)
|
||||
// and any that accept key input http://webaim.org/techniques/keyboard/
|
||||
const focused = utils.getFocusElement();
|
||||
if (utils.is.element(focused) && utils.matches(focused, this.player.config.selectors.editable)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the code is found prevent default (e.g. prevent scrolling for arrows)
|
||||
if (preventDefault.includes(code)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case 48:
|
||||
case 49:
|
||||
case 50:
|
||||
case 51:
|
||||
case 52:
|
||||
case 53:
|
||||
case 54:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
// 0-9
|
||||
if (!repeat) {
|
||||
seekByKey();
|
||||
}
|
||||
break;
|
||||
|
||||
case 32:
|
||||
case 75:
|
||||
// Space and K key
|
||||
if (!repeat) {
|
||||
this.player.togglePlay();
|
||||
}
|
||||
break;
|
||||
|
||||
case 38:
|
||||
// Arrow up
|
||||
this.player.increaseVolume(0.1);
|
||||
break;
|
||||
|
||||
case 40:
|
||||
// Arrow down
|
||||
this.player.decreaseVolume(0.1);
|
||||
break;
|
||||
|
||||
case 77:
|
||||
// M key
|
||||
if (!repeat) {
|
||||
this.player.muted = !this.player.muted;
|
||||
}
|
||||
break;
|
||||
|
||||
case 39:
|
||||
// Arrow forward
|
||||
this.player.forward();
|
||||
break;
|
||||
|
||||
case 37:
|
||||
// Arrow back
|
||||
this.player.rewind();
|
||||
break;
|
||||
|
||||
case 70:
|
||||
// F key
|
||||
this.player.fullscreen.toggle();
|
||||
break;
|
||||
|
||||
case 67:
|
||||
// C key
|
||||
if (!repeat) {
|
||||
this.player.toggleCaptions();
|
||||
}
|
||||
break;
|
||||
|
||||
case 76:
|
||||
// L key
|
||||
this.player.loop = !this.player.loop;
|
||||
break;
|
||||
|
||||
/* case 73:
|
||||
this.setLoop('start');
|
||||
break;
|
||||
|
||||
case 76:
|
||||
this.setLoop();
|
||||
break;
|
||||
|
||||
case 79:
|
||||
this.setLoop('end');
|
||||
break; */
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Escape is handle natively when in full screen
|
||||
// So we only need to worry about non native
|
||||
if (!this.player.fullscreen.enabled && this.player.fullscreen.active && code === 27) {
|
||||
this.player.fullscreen.toggle();
|
||||
}
|
||||
|
||||
// Store last code for next cycle
|
||||
this.lastKey = code;
|
||||
} else {
|
||||
this.lastKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle menu
|
||||
toggleMenu(event) {
|
||||
controls.toggleMenu.call(this.player, event);
|
||||
}
|
||||
|
||||
// Device is touch enabled
|
||||
firstTouch() {
|
||||
this.player.touch = true;
|
||||
|
||||
// Add touch class
|
||||
utils.toggleClass(this.player.elements.container, this.player.config.classNames.isTouch, true);
|
||||
|
||||
// Clean up
|
||||
utils.off(document.body, 'touchstart', this.firstTouch);
|
||||
}
|
||||
|
||||
// Global window & document listeners
|
||||
global(toggle = true) {
|
||||
// Keyboard shortcuts
|
||||
if (this.player.config.keyboard.global) {
|
||||
utils.toggleListener(window, 'keydown keyup', this.handleKey, toggle, false);
|
||||
}
|
||||
|
||||
// Click anywhere closes menu
|
||||
utils.toggleListener(document.body, 'click', this.toggleMenu, toggle);
|
||||
|
||||
// Detect touch by events
|
||||
utils.on(document.body, 'touchstart', this.firstTouch);
|
||||
}
|
||||
|
||||
// Container listeners
|
||||
container() {
|
||||
// Keyboard shortcuts
|
||||
if (!this.player.config.keyboard.global && this.player.config.keyboard.focused) {
|
||||
utils.on(this.player.elements.container, 'keydown keyup', this.handleKey, false);
|
||||
}
|
||||
|
||||
// Detect tab focus
|
||||
// Remove class on blur/focusout
|
||||
utils.on(this.player.elements.container, 'focusout', event => {
|
||||
utils.toggleClass(event.target, this.player.config.classNames.tabFocus, false);
|
||||
});
|
||||
|
||||
// Add classname to tabbed elements
|
||||
utils.on(this.player.elements.container, 'keydown', event => {
|
||||
if (event.keyCode !== 9) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delay the adding of classname until the focus has changed
|
||||
// This event fires before the focusin event
|
||||
setTimeout(() => {
|
||||
utils.toggleClass(utils.getFocusElement(), this.player.config.classNames.tabFocus, true);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
// Toggle controls on mouse events and entering fullscreen
|
||||
utils.on(this.player.elements.container, 'mousemove mouseleave touchstart touchmove enterfullscreen exitfullscreen', event => {
|
||||
const { controls } = this.player.elements;
|
||||
|
||||
// Remove button states for fullscreen
|
||||
if (event.type === 'enterfullscreen') {
|
||||
controls.pressed = false;
|
||||
controls.hover = false;
|
||||
}
|
||||
|
||||
// Show, then hide after a timeout unless another control event occurs
|
||||
const show = [
|
||||
'touchstart',
|
||||
'touchmove',
|
||||
'mousemove',
|
||||
].includes(event.type);
|
||||
|
||||
let delay = 0;
|
||||
|
||||
if (show) {
|
||||
ui.toggleControls.call(this.player, true);
|
||||
// Use longer timeout for touch devices
|
||||
delay = this.player.touch ? 3000 : 2000;
|
||||
}
|
||||
|
||||
// Clear timer
|
||||
clearTimeout(this.player.timers.controls);
|
||||
// Timer to prevent flicker when seeking
|
||||
this.player.timers.controls = setTimeout(() => ui.toggleControls.call(this.player, false), delay);
|
||||
});
|
||||
}
|
||||
|
||||
// Listen for media events
|
||||
media() {
|
||||
// Time change on media
|
||||
utils.on(this.player.media, 'timeupdate seeking seeked', event => controls.timeUpdate.call(this.player, event));
|
||||
|
||||
// Display duration
|
||||
utils.on(this.player.media, 'durationchange loadeddata loadedmetadata', event => controls.durationUpdate.call(this.player, event));
|
||||
|
||||
// Check for audio tracks on load
|
||||
// We can't use `loadedmetadata` as it doesn't seem to have audio tracks at that point
|
||||
utils.on(this.player.media, 'loadeddata', () => {
|
||||
utils.toggleHidden(this.player.elements.volume, !this.player.hasAudio);
|
||||
utils.toggleHidden(this.player.elements.buttons.mute, !this.player.hasAudio);
|
||||
});
|
||||
|
||||
// Handle the media finishing
|
||||
utils.on(this.player.media, 'ended', () => {
|
||||
// Show poster on end
|
||||
if (this.player.isHTML5 && this.player.isVideo && this.player.config.resetOnEnd) {
|
||||
// Restart
|
||||
this.player.restart();
|
||||
}
|
||||
});
|
||||
|
||||
// Check for buffer progress
|
||||
utils.on(this.player.media, 'progress playing seeking seeked', event => controls.updateProgress.call(this.player, event));
|
||||
|
||||
// Handle volume changes
|
||||
utils.on(this.player.media, 'volumechange', event => controls.updateVolume.call(this.player, event));
|
||||
|
||||
// Handle play/pause
|
||||
utils.on(this.player.media, 'playing play pause ended emptied timeupdate', event => ui.checkPlaying.call(this.player, event));
|
||||
|
||||
// Loading state
|
||||
utils.on(this.player.media, 'waiting canplay seeked playing', event => ui.checkLoading.call(this.player, event));
|
||||
|
||||
// If autoplay, then load advertisement if required
|
||||
// TODO: Show some sort of loading state while the ad manager loads else there's a delay before ad shows
|
||||
utils.on(this.player.media, 'playing', () => {
|
||||
if (!this.player.ads) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If ads are enabled, wait for them first
|
||||
if (this.player.ads.enabled && !this.player.ads.initialized) {
|
||||
// Wait for manager response
|
||||
this.player.ads.managerPromise.then(() => this.player.ads.play()).catch(() => this.player.play());
|
||||
}
|
||||
});
|
||||
|
||||
// Click video
|
||||
if (this.player.supported.ui && this.player.config.clickToPlay && !this.player.isAudio) {
|
||||
// Re-fetch the wrapper
|
||||
const wrapper = utils.getElement.call(this.player, `.${this.player.config.classNames.video}`);
|
||||
|
||||
// Bail if there's no wrapper (this should never happen)
|
||||
if (!utils.is.element(wrapper)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// On click play, pause ore restart
|
||||
utils.on(wrapper, 'click', () => {
|
||||
// Touch devices will just show controls (if we're hiding controls)
|
||||
if (this.player.config.hideControls && this.player.touch && !this.player.paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.player.paused) {
|
||||
this.player.play();
|
||||
} else if (this.player.ended) {
|
||||
this.player.restart();
|
||||
this.player.play();
|
||||
} else {
|
||||
this.player.pause();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Disable right click
|
||||
if (this.player.supported.ui && this.player.config.disableContextMenu) {
|
||||
utils.on(
|
||||
this.player.elements.wrapper,
|
||||
'contextmenu',
|
||||
event => {
|
||||
event.preventDefault();
|
||||
},
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
// Volume change
|
||||
utils.on(this.player.media, 'volumechange', () => {
|
||||
// Save to storage
|
||||
this.player.storage.set({ volume: this.player.volume, muted: this.player.muted });
|
||||
});
|
||||
|
||||
// Speed change
|
||||
utils.on(this.player.media, 'ratechange', () => {
|
||||
// Update UI
|
||||
controls.updateSetting.call(this.player, 'speed');
|
||||
|
||||
// Save to storage
|
||||
this.player.storage.set({ speed: this.player.speed });
|
||||
});
|
||||
|
||||
// Quality request
|
||||
utils.on(this.player.media, 'qualityrequested', event => {
|
||||
// Save to storage
|
||||
this.player.storage.set({ quality: event.detail.quality });
|
||||
});
|
||||
|
||||
// Quality change
|
||||
utils.on(this.player.media, 'qualitychange', event => {
|
||||
// Update UI
|
||||
controls.updateSetting.call(this.player, 'quality', null, event.detail.quality);
|
||||
});
|
||||
|
||||
// Caption language change
|
||||
utils.on(this.player.media, 'languagechange', () => {
|
||||
// Update UI
|
||||
controls.updateSetting.call(this.player, 'captions');
|
||||
|
||||
// Save to storage
|
||||
this.player.storage.set({ language: this.player.language });
|
||||
});
|
||||
|
||||
// Captions toggle
|
||||
utils.on(this.player.media, 'captionsenabled captionsdisabled', () => {
|
||||
// Update UI
|
||||
controls.updateSetting.call(this.player, 'captions');
|
||||
|
||||
// Save to storage
|
||||
this.player.storage.set({ captions: this.player.captions.active });
|
||||
});
|
||||
|
||||
// Proxy events to container
|
||||
// Bubble up key events for Edge
|
||||
utils.on(this.player.media, this.player.config.events.concat([
|
||||
'keyup',
|
||||
'keydown',
|
||||
]).join(' '), event => {
|
||||
let detail = {};
|
||||
|
||||
// Get error details from media
|
||||
if (event.type === 'error') {
|
||||
detail = this.player.media.error;
|
||||
}
|
||||
|
||||
utils.dispatchEvent.call(this.player, this.player.elements.container, event.type, true, detail);
|
||||
});
|
||||
}
|
||||
|
||||
// Listen for control events
|
||||
controls() {
|
||||
// IE doesn't support input event, so we fallback to change
|
||||
const inputEvent = browser.isIE ? 'change' : 'input';
|
||||
|
||||
// Run default and custom handlers
|
||||
const proxy = (event, defaultHandler, customHandlerKey) => {
|
||||
const customHandler = this.player.config.listeners[customHandlerKey];
|
||||
const hasCustomHandler = utils.is.function(customHandler);
|
||||
let returned = true;
|
||||
|
||||
// Execute custom handler
|
||||
if (hasCustomHandler) {
|
||||
returned = customHandler.call(this.player, event);
|
||||
}
|
||||
|
||||
// Only call default handler if not prevented in custom handler
|
||||
if (returned && utils.is.function(defaultHandler)) {
|
||||
defaultHandler.call(this.player, event);
|
||||
}
|
||||
};
|
||||
|
||||
// Trigger custom and default handlers
|
||||
const on = (element, type, defaultHandler, customHandlerKey, passive = true) => {
|
||||
const customHandler = this.player.config.listeners[customHandlerKey];
|
||||
const hasCustomHandler = utils.is.function(customHandler);
|
||||
|
||||
utils.on(element, type, event => proxy(event, defaultHandler, customHandlerKey), passive && !hasCustomHandler);
|
||||
};
|
||||
|
||||
// Play/pause toggle
|
||||
on(this.player.elements.buttons.play, 'click', this.player.togglePlay, 'play');
|
||||
|
||||
// Pause
|
||||
on(this.player.elements.buttons.restart, 'click', this.player.restart, 'restart');
|
||||
|
||||
// Rewind
|
||||
on(this.player.elements.buttons.rewind, 'click', this.player.rewind, 'rewind');
|
||||
|
||||
// Rewind
|
||||
on(this.player.elements.buttons.fastForward, 'click', this.player.forward, 'fastForward');
|
||||
|
||||
// Mute toggle
|
||||
on(
|
||||
this.player.elements.buttons.mute,
|
||||
'click',
|
||||
() => {
|
||||
this.player.muted = !this.player.muted;
|
||||
},
|
||||
'mute',
|
||||
);
|
||||
|
||||
// Captions toggle
|
||||
on(this.player.elements.buttons.captions, 'click', this.player.toggleCaptions);
|
||||
|
||||
// Fullscreen toggle
|
||||
on(
|
||||
this.player.elements.buttons.fullscreen,
|
||||
'click',
|
||||
() => {
|
||||
this.player.fullscreen.toggle();
|
||||
},
|
||||
'fullscreen',
|
||||
);
|
||||
|
||||
// Picture-in-Picture
|
||||
on(
|
||||
this.player.elements.buttons.pip,
|
||||
'click',
|
||||
() => {
|
||||
this.player.pip = 'toggle';
|
||||
},
|
||||
'pip',
|
||||
);
|
||||
|
||||
// Airplay
|
||||
on(this.player.elements.buttons.airplay, 'click', this.player.airplay, 'airplay');
|
||||
|
||||
// Settings menu
|
||||
on(this.player.elements.buttons.settings, 'click', event => {
|
||||
controls.toggleMenu.call(this.player, event);
|
||||
});
|
||||
|
||||
// Settings menu
|
||||
on(this.player.elements.settings.form, 'click', event => {
|
||||
event.stopPropagation();
|
||||
|
||||
// Go back to home tab on click
|
||||
const showHomeTab = () => {
|
||||
const id = `plyr-settings-${this.player.id}-home`;
|
||||
controls.showTab.call(this.player, id);
|
||||
};
|
||||
|
||||
// Settings menu items - use event delegation as items are added/removed
|
||||
if (utils.matches(event.target, this.player.config.selectors.inputs.language)) {
|
||||
proxy(
|
||||
event,
|
||||
() => {
|
||||
this.player.language = event.target.value;
|
||||
showHomeTab();
|
||||
},
|
||||
'language',
|
||||
);
|
||||
} else if (utils.matches(event.target, this.player.config.selectors.inputs.quality)) {
|
||||
proxy(
|
||||
event,
|
||||
() => {
|
||||
this.player.quality = event.target.value;
|
||||
showHomeTab();
|
||||
},
|
||||
'quality',
|
||||
);
|
||||
} else if (utils.matches(event.target, this.player.config.selectors.inputs.speed)) {
|
||||
proxy(
|
||||
event,
|
||||
() => {
|
||||
this.player.speed = parseFloat(event.target.value);
|
||||
showHomeTab();
|
||||
},
|
||||
'speed',
|
||||
);
|
||||
} else {
|
||||
const tab = event.target;
|
||||
controls.showTab.call(this.player, tab.getAttribute('aria-controls'));
|
||||
}
|
||||
});
|
||||
|
||||
// Set range input alternative "value", which matches the tooltip time (#954)
|
||||
on(this.player.elements.inputs.seek, 'mousedown mousemove', event => {
|
||||
const clientRect = this.player.elements.progress.getBoundingClientRect();
|
||||
const percent = 100 / clientRect.width * (event.pageX - clientRect.left);
|
||||
event.currentTarget.setAttribute('seek-value', percent);
|
||||
});
|
||||
|
||||
// Pause while seeking
|
||||
on(this.player.elements.inputs.seek, 'mousedown mouseup keydown keyup touchstart touchend', event => {
|
||||
const seek = event.currentTarget;
|
||||
|
||||
// Was playing before?
|
||||
const play = seek.hasAttribute('play-on-seeked');
|
||||
|
||||
// Done seeking
|
||||
const done = [
|
||||
'mouseup',
|
||||
'touchend',
|
||||
'keyup',
|
||||
].includes(event.type);
|
||||
|
||||
// If we're done seeking and it was playing, resume playback
|
||||
if (play && done) {
|
||||
seek.removeAttribute('play-on-seeked');
|
||||
this.player.play();
|
||||
} else if (!done && this.player.playing) {
|
||||
seek.setAttribute('play-on-seeked', '');
|
||||
this.player.pause();
|
||||
}
|
||||
});
|
||||
|
||||
// Seek
|
||||
on(
|
||||
this.player.elements.inputs.seek,
|
||||
inputEvent,
|
||||
event => {
|
||||
const seek = event.currentTarget;
|
||||
|
||||
// If it exists, use seek-value instead of "value" for consistency with tooltip time (#954)
|
||||
let seekTo = seek.getAttribute('seek-value');
|
||||
|
||||
if (utils.is.empty(seekTo)) {
|
||||
seekTo = seek.value;
|
||||
}
|
||||
|
||||
seek.removeAttribute('seek-value');
|
||||
|
||||
this.player.currentTime = seekTo / seek.max * this.player.duration;
|
||||
},
|
||||
'seek',
|
||||
);
|
||||
|
||||
// Current time invert
|
||||
// Only if one time element is used for both currentTime and duration
|
||||
if (this.player.config.toggleInvert && !utils.is.element(this.player.elements.display.duration)) {
|
||||
on(this.player.elements.display.currentTime, 'click', () => {
|
||||
// Do nothing if we're at the start
|
||||
if (this.player.currentTime === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.player.config.invertTime = !this.player.config.invertTime;
|
||||
|
||||
controls.timeUpdate.call(this.player);
|
||||
});
|
||||
}
|
||||
|
||||
// Volume
|
||||
on(
|
||||
this.player.elements.inputs.volume,
|
||||
inputEvent,
|
||||
event => {
|
||||
this.player.volume = event.target.value;
|
||||
},
|
||||
'volume',
|
||||
);
|
||||
|
||||
// Polyfill for lower fill in <input type="range"> for webkit
|
||||
if (browser.isWebkit) {
|
||||
on(utils.getElements.call(this.player, 'input[type="range"]'), 'input', event => {
|
||||
controls.updateRangeFill.call(this.player, event.target);
|
||||
});
|
||||
}
|
||||
|
||||
// Seek tooltip
|
||||
on(this.player.elements.progress, 'mouseenter mouseleave mousemove', event => controls.updateSeekTooltip.call(this.player, event));
|
||||
|
||||
// Update controls.hover state (used for ui.toggleControls to avoid hiding when interacting)
|
||||
on(this.player.elements.controls, 'mouseenter mouseleave', event => {
|
||||
this.player.elements.controls.hover = !this.player.touch && event.type === 'mouseenter';
|
||||
});
|
||||
|
||||
// Update controls.pressed state (used for ui.toggleControls to avoid hiding when interacting)
|
||||
on(this.player.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {
|
||||
this.player.elements.controls.pressed = [
|
||||
'mousedown',
|
||||
'touchstart',
|
||||
].includes(event.type);
|
||||
});
|
||||
|
||||
// Focus in/out on controls
|
||||
on(this.player.elements.controls, 'focusin focusout', event => {
|
||||
const { config, elements, timers } = this.player;
|
||||
|
||||
// Skip transition to prevent focus from scrolling the parent element
|
||||
utils.toggleClass(elements.controls, config.classNames.noTransition, event.type === 'focusin');
|
||||
|
||||
// Toggle
|
||||
ui.toggleControls.call(this.player, event.type === 'focusin');
|
||||
|
||||
// If focusin, hide again after delay
|
||||
if (event.type === 'focusin') {
|
||||
// Restore transition
|
||||
setTimeout(() => {
|
||||
utils.toggleClass(elements.controls, config.classNames.noTransition, false);
|
||||
}, 0);
|
||||
|
||||
// Delay a little more for keyboard users
|
||||
const delay = this.touch ? 3000 : 4000;
|
||||
|
||||
// Clear timer
|
||||
clearTimeout(timers.controls);
|
||||
// Hide
|
||||
timers.controls = setTimeout(() => ui.toggleControls.call(this.player, false), delay);
|
||||
}
|
||||
});
|
||||
|
||||
// Mouse wheel for volume
|
||||
on(
|
||||
this.player.elements.inputs.volume,
|
||||
'wheel',
|
||||
event => {
|
||||
// Detect "natural" scroll - suppored on OS X Safari only
|
||||
// Other browsers on OS X will be inverted until support improves
|
||||
const inverted = event.webkitDirectionInvertedFromDevice;
|
||||
const step = 1 / 50;
|
||||
let direction = 0;
|
||||
|
||||
// Scroll down (or up on natural) to decrease
|
||||
if (event.deltaY < 0 || event.deltaX > 0) {
|
||||
if (inverted) {
|
||||
this.player.decreaseVolume(step);
|
||||
direction = -1;
|
||||
} else {
|
||||
this.player.increaseVolume(step);
|
||||
direction = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll up (or down on natural) to increase
|
||||
if (event.deltaY > 0 || event.deltaX < 0) {
|
||||
if (inverted) {
|
||||
this.player.increaseVolume(step);
|
||||
direction = 1;
|
||||
} else {
|
||||
this.player.decreaseVolume(step);
|
||||
direction = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't break page scrolling at max and min
|
||||
if ((direction === 1 && this.player.media.volume < 1) || (direction === -1 && this.player.media.volume > 0)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
'volume',
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
// Reset on destroy
|
||||
clear() {
|
||||
this.global(false);
|
||||
}
|
||||
}
|
||||
|
||||
export default Listeners;
|