Compare commits

...

599 Commits
v2 ... v3.3.11

Author SHA1 Message Date
efe70ab48e v3.3.11 2018-06-11 16:39:35 +10:00
1e1874d86b Merge pull request #1009 from friday/contributing
Contributing document and codepen demo updates
2018-06-08 10:52:37 +10:00
16624b90d3 Clarifications due to recent non-constructive comments in #1001 2018-06-07 14:30:05 +02:00
ed14b656a8 Add contributing document 2018-06-07 11:47:51 +02:00
1d0cf16254 Readme: Replace streaming section with codepen templates for all supported formats and libraries (and updated code) 2018-06-07 11:47:34 +02:00
05b85da3f4 Update controls.md (fixes #996) 2018-06-02 19:48:48 +10:00
a4caba120c Merge branch 'master' of github.com:sampotts/plyr
# Conflicts:
#	demo/dist/demo.css
#	dist/plyr.css
#	dist/plyr.js.map
#	dist/plyr.min.js
#	dist/plyr.min.js.map
#	dist/plyr.polyfilled.js.map
#	dist/plyr.polyfilled.min.js
#	dist/plyr.polyfilled.min.js.map
2018-05-31 23:43:40 +10:00
969a877a34 v3.3.10 2018-05-31 23:41:48 +10:00
fb22a90d33 Merge pull request #993 from sampotts/develop
v3.3.10
2018-05-31 23:39:51 +10:00
108bd3dfa0 Fixed incorrect BEM formatting, fixed buffer alignment 2018-05-31 23:33:59 +10:00
5a445ae647 Merge pull request #988 from kim-company/translate-qualities
Translate quality badges and quality names
2018-05-31 22:43:31 +10:00
56668f58b6 Rename qualityName to label 2018-05-31 14:40:56 +02:00
eec96e5879 Merge pull request #990 from friday/travis
Travis integration
2018-05-31 18:33:00 +10:00
c6c9d877e4 Merge pull request #992 from philipgiuliani/quality-resume-time
Wait for the metadata to be loaded before setting the currentTime
2018-05-31 18:32:10 +10:00
61f4b998e1 Wait for the metadata to be loaded before setting the currentTime 2018-05-31 10:17:41 +02:00
25a319d884 Merge pull request #989 from friday/pr-template
Proposed changes to PR template
2018-05-31 08:34:02 +10:00
4bf678fe6c Proposed changes to PR template (develop as base branch, exclude build and typo fix) 2018-05-30 19:52:15 +02:00
359acd6bb9 Lint and build in travis 2018-05-30 19:40:17 +02:00
2fce385691 Add npm scripts for linting and building 2018-05-30 19:40:17 +02:00
a82c61c539 Gulp: Add option to build only 2018-05-30 19:39:57 +02:00
a8fa125a96 Refactor getDeep method 2018-05-30 17:30:10 +02:00
6435ced707 Return undefined when the key is not present. 2018-05-30 17:10:38 +02:00
94dc0d176c Rebuild 2018-05-30 17:03:41 +02:00
23c21252e8 Rebuild 2018-05-30 17:02:07 +02:00
41c7dff0e8 Add getDeep method to utils 2018-05-30 17:02:07 +02:00
e3bae562fc Rebuild 2018-05-30 17:02:07 +02:00
1c1668bfc3 Implement translation support for qualityName and qualityBadge 2018-05-30 17:02:07 +02:00
e0c09c51f2 Allow nested translations 2018-05-30 17:02:07 +02:00
8de06fb862 Accept quality 0 2018-05-30 17:02:07 +02:00
64412868d8 ESLint tweak 2018-05-30 17:02:07 +02:00
450958c290 Merge pull request #981 from friday/hls-captions
Improve captions handling for streaming
2018-05-30 21:44:42 +10:00
963fe11ad6 Update readme.md 2018-05-30 00:22:01 +10:00
ce199e4b6b Merge pull request #986 from friday/701
Call duration update method manually if user config has duration
2018-05-30 00:20:15 +10:00
9d798893b5 Call duration update method manually if user config has duration 2018-05-29 16:06:07 +02:00
64399e0717 Defer initial captions update to next tick, to avoid event being triggered to early 2018-05-28 17:54:25 +02:00
f58e23b325 Change to using addtrack and removetrack listeners since 'change' didn't trigger in firefox for embedded captions (may also be a hls.js issue) 2018-05-28 16:19:44 +02:00
812e07b734 Replace browser language detection in defaults.js with explicit 'auto' option 2018-05-28 07:43:37 +02:00
c9298fde76 Fix typo 2018-05-28 07:08:38 +02:00
0109454a34 Ensure language is set in case the track is added after initialization, and trigger languagechange event when language is initially set 2018-05-28 06:08:03 +02:00
813f703211 Add option to watch caption track changes and update language options 2018-05-28 06:08:03 +02:00
7aad747c25 Optimize captions code reused and ensure captionsenabled/captionsdisabled
will be sent on initial setup
2018-05-28 05:44:54 +02:00
d70a787af1 Merge branch 'develop' 2018-05-28 10:42:11 +10:00
69bb0917ad v3.3.9 2018-05-28 10:41:51 +10:00
6f256d09b2 ESLint tweak 2018-05-28 10:18:04 +10:00
e9684c2021 Merge pull request #979 from friday/respect-storage
Respect storage being disabled for storage getter
2018-05-28 10:09:02 +10:00
bf91a0e73f Merge pull request #977 from friday/utils.is.icue-ie11
Restore utils.is.cue()
2018-05-28 10:08:42 +10:00
14b6309aef Merge pull request #978 from friday/ie-issues
Fix InvalidStateError and IE11 issues
2018-05-28 10:08:24 +10:00
6391ced99f If storage is disabled, disable get as well, not just set 2018-05-28 01:58:06 +02:00
fac8a185ba Simplify currentTime setter and bail when media hasn't loaded 2018-05-28 00:57:07 +02:00
c69aa8a42b Avoid duration getter returning NaN before element has loaded 2018-05-28 00:57:01 +02:00
f34bf22125 Restore utils.is.cue() 2018-05-27 20:28:48 +02:00
f0be913dc3 Merge pull request #975 from sampotts/develop
v3.3.8
2018-05-26 13:55:22 +10:00
cd51788b98 v3.3.8 2018-05-26 13:53:15 +10:00
edd67b0da3 Typo 2018-05-20 23:44:40 +10:00
d733454d7f Pause while seeking 2018-05-20 23:40:28 +10:00
41f9a87e0e Add URL polyfill 2018-05-20 23:40:00 +10:00
f4858f0c62 Merge pull request #959 from friday/876
Youtube and vimeo fixes
2018-05-19 16:49:31 +10:00
121093ae71 Prevent durationchange events from showing time when invertTime is false 2018-05-19 04:27:45 +02:00
aa8fc313a9 Fix #966: Add 'seeked' event listener to update progress (seeking doesn't have the correct time) 2018-05-19 04:23:22 +02:00
723298a07b Fix #921: Trigger seeked event in youtube plugin if either playing or paused 2018-05-19 04:18:27 +02:00
f8c89e3e95 Fix #876: YouTube and Vimeo autoplays on seek 2018-05-19 04:18:27 +02:00
333435a9c2 Fix playback state (paused) and events (play/pause) 2018-05-19 04:18:27 +02:00
3ab2295fe7 Merge branch 'master' into develop 2018-05-19 11:29:47 +10:00
c41bb657ac Merge pull request #958 from friday/954
Fix the seek tooltip time difference from seek time
2018-05-19 11:28:38 +10:00
55bbf64f2b Merge pull request #963 from friday/verify-poster
Make sure poster element isn't shown if the image isn't loaded
2018-05-19 11:27:52 +10:00
3bba65f2c2 Merge pull request #967 from friday/883
toggleControls rewrite
2018-05-19 11:27:19 +10:00
1bab0d07b5 Merge branch 'master' into develop 2018-05-19 11:26:05 +10:00
602353f4d9 Merge branch 'master' of github.com:sampotts/plyr 2018-05-19 11:25:02 +10:00
51814249af Reduce circular dependencies 2018-05-19 11:24:56 +10:00
37c5fbfe16 toggleControls() rewrite 2018-05-18 16:19:38 +02:00
d7356726a1 Remove ui.checkFailed() and error class 2018-05-16 23:21:06 +02:00
4db6bf7a2e Make utils.toggleClass() compatible with Element.classList.toggle (rename toggle argument to 'force' and make it optional) 2018-05-16 23:21:06 +02:00
28826f6402 Add 'video only' caveat to toggleControls() doc (current behavior) 2018-05-16 23:21:06 +02:00
c845558d96 Youtube poster: Set css backgroundSize to 'cover' for padded youtube thumbnails 2018-05-15 16:41:51 +02:00
16c3a7d9e5 Rewrite ui.setPoster to check that images arent broken or youtube fallback images. Only show poster element when valid 2018-05-15 16:21:36 +02:00
90d5b48845 Add async method to utils for loading/checking images 2018-05-15 13:27:55 +02:00
d1acc4abb3 Add event before seeking via mouse interaction to set alternative 'value' for the input matching the tooltip time 2018-05-14 19:50:08 +02:00
797b70998f Merge pull request #960 from friday/935
Support importing Plyr in Node.js without errors
2018-05-14 23:38:48 +10:00
4a01027da0 Merge pull request #961 from friday/expose-defaults
Enable overriding defaults
2018-05-14 23:38:25 +10:00
7ca2169790 Expose defaults (enable overriding) 2018-05-14 06:49:04 +02:00
054f522aa9 Enable importing Plyr in node.js without errors (resulting in an empty object) 2018-05-14 05:35:13 +02:00
f2fc3f5ea5 Fix the seek tooltip time difference from seek time 2018-05-12 00:10:39 +02:00
765c01e83d Remove references to window.Plyr 2018-05-10 09:34:15 +10:00
33a11fb53a v3.3.7 2018-05-09 09:50:22 +10:00
d1d41ca49a Merge branch 'master' of github.com:sampotts/plyr 2018-05-09 09:48:52 +10:00
c06e0ee5e9 Grid tweak 2018-05-09 09:48:46 +10:00
83f80ccc40 Merge pull request #950 from friday/poster-fixes
Poster fixes
2018-05-09 09:44:36 +10:00
069065ea3a Fix #946 - poster getting click events 2018-05-08 16:50:40 +02:00
1672e78041 Fix poster being stretched 2018-05-08 16:49:32 +02:00
34401de3d0 Merge branch 'master' into develop 2018-05-08 22:22:43 +10:00
f687b81b70 v3.3.6 2018-05-08 13:18:30 +10:00
bbb11e611e Vimeo options, docs for multiple players 2018-05-08 13:12:39 +10:00
90919411e9 Use div for poster, Vimeo fixes, Tooltip fixes 2018-05-08 12:57:24 +10:00
1491b017a0 Setup multiple players 2018-05-06 16:18:10 +10:00
1655150092 v3.3.5 2018-05-06 01:32:51 +10:00
ceb6c9a100 v3.3.3 2018-05-06 01:16:41 +10:00
00bbce08fb Reverted menu change 2018-05-06 01:14:41 +10:00
91a4b86860 Small bug fixes 2018-05-06 01:03:38 +10:00
5aece6fa06 Merge 2018-05-06 00:50:02 +10:00
a70b94afe2 Merge branch 'master' of github.com:sampotts/plyr 2018-05-06 00:49:22 +10:00
9ebc2719d3 v3.3.0 2018-05-06 00:49:12 +10:00
b46aae1833 Merge pull request #939 from Billybobbonnet/patch-1
Added 480p to SD labels
2018-05-03 20:28:03 +10:00
30e6a40865 Added 480p to SD labels 2018-05-03 11:42:09 +02:00
403df36af6 Merge branch 'master' into develop 2018-04-27 21:42:29 +10:00
5ca769807e Merge pull request #923 from friday/922
Only add hideControls class if config.hideControls is truthy
2018-04-27 20:07:18 +10:00
72a71a605b Fix for default timestamp 2018-04-27 20:06:14 +10:00
24d833a5d1 Merge branch 'master' into develop 2018-04-27 18:35:06 +10:00
44b30380f7 Merge branch 'beta' of github.com:Selz/plyr 2018-04-27 18:34:06 +10:00
261cd086c7 Update readme.md 2018-04-27 12:44:58 +10:00
9e19b526b9 Only add hideControls class if config.hideControls is truthy 2018-04-26 17:51:14 +02:00
6c617a0ef1 Readme fix 2018-04-27 01:12:04 +10:00
a812650fea v3.2.4 2018-04-27 00:47:51 +10:00
fec7a77d6f v3.2.3 2018-04-25 20:02:36 +10:00
971e261067 Fix for iOS 9 throwing error for name property in fullscreen API (fixes #908) 2018-04-25 19:59:22 +10:00
27407ba021 v3.2.2 2018-04-25 19:46:39 +10:00
ef8e58ede4 Fix for hidden buffer and incorrect use of aria-hidden 2018-04-25 19:40:23 +10:00
f13260c10a Merge pull request #919 from sampotts/master
Merge back
2018-04-25 07:38:17 +10:00
e1183d6049 Merge pull request #918 from sampotts/master
Merge back
2018-04-25 07:37:18 +10:00
f1b275aedc v3.2.1 2018-04-23 00:53:54 +10:00
b647af256c More a11y stuff and context menu fix 2018-04-23 00:01:19 +10:00
d2e9ed3467 Merge 2018-04-18 18:34:59 +10:00
5b39986835 Merge branch 'master' of github.com:sampotts/plyr 2018-04-18 18:29:50 +10:00
a97b08e8ea ARIA and Vimeo fixes 2018-04-18 18:29:43 +10:00
56d1be9447 Merge pull request #903 from friday/901
Show captions even if toggle button is omitted from controls
2018-04-18 08:49:05 +10:00
a241cb5215 Merge pull request #904 from friday/881
Fullscreen aria-pressed event listened fix for Chrome
2018-04-18 08:48:08 +10:00
042b1a8294 Fullscreen aria-pressed event listened fix for Chrome 2018-04-17 20:28:47 +02:00
6d79b8cd4c Don't require captions toggle button to be enabled in order to show captions 2018-04-17 18:59:19 +02:00
88d766aeae v3.2.0 2018-04-17 23:54:38 +10:00
119b471b84 More bug fixes 2018-04-17 23:51:23 +10:00
7f079e0ec3 Fix for playing false positive (fixes #898) 2018-04-17 22:52:46 +10:00
46fe3eecff Fixed bug for captions with no srclang and labels and improved logic (fixes #875) 2018-04-17 22:49:28 +10:00
3061a701d5 PR merge 2018-04-14 14:58:09 +10:00
e45109e1d7 Merge branch 'master' of github.com:sampotts/plyr 2018-04-14 14:48:20 +10:00
e138e6d51e Merge pull request #895 from nicolasthy/patch-1
Fix IE10 split error
2018-04-14 14:47:57 +10:00
aef1363b04 Fix IE10 with default captions.language 2018-04-13 14:44:05 +02:00
766dd03d81 Fix IE10 split error
On IE10, Plyr throws the error `Unable to get property 'split' of undefined or null reference`. This fixes the case when `window.navigator.language` is null and can't use the `split()` function.
2018-04-12 22:12:12 +02:00
ab393651ec Merge branch 'master' of github.com:sampotts/plyr 2018-04-11 23:44:44 +10:00
ffd265d0ae Merge pull request #888 from Antonio-Laguna/master
Safer check for active caption
2018-04-11 23:42:40 +10:00
72155472dd Safer check for active caption 2018-04-11 15:39:12 +02:00
9b7170834e Merge pull request #887 from danielsarin/use-i18n-for-normal-speed
Add i18n support for "Normal" value in speed options
2018-04-11 22:43:47 +10:00
3e57a87bf7 Add i18n support for "Normal" value in speed options 2018-04-11 15:39:23 +03:00
a15d1c9f1c Merge pull request #886 from danielsarin/increate-menu-z-index
Increase menu container z-index to be higher than controls
2018-04-11 22:23:46 +10:00
a095a64f90 Increase menu container z-index to be higher than controls 2018-04-11 15:13:34 +03:00
2374d6b1c4 Merge branch 'master' of github.com:sampotts/plyr 2018-04-11 21:52:36 +10:00
5ed3ff9084 Restore paused state after seek 2018-04-11 21:52:31 +10:00
385be55510 Merge pull request #874 from friday/873
Fixes issue leaving fullscreen in Chrome using button
2018-04-10 17:21:15 +10:00
3082d0d128 Fixes #873 Can't leave fullscreen in Chrome (using button) 2018-04-05 20:29:01 +02:00
f7e242f054 Merge pull request #871 from friday/867
Fix #867: Add custom property fallback
2018-04-05 09:19:46 +10:00
2874505004 Merge pull request #868 from friday/null-no-controls
Fix string "null" being appended after the video if controls argument is empty.
2018-04-05 09:19:05 +10:00
ed9e0c13d7 Fix #867: Add custom property fallback 2018-04-05 00:33:09 +02:00
10be94fa99 Fix 'null' being appended after the video if controls is empty array 2018-04-04 21:33:14 +02:00
ee79c46145 Merge branch 'master' of github.com:sampotts/plyr 2018-04-04 16:50:06 +10:00
384010a2c0 Style fixes 2018-04-04 16:50:00 +10:00
1e47019122 Merge pull request #863 from friday/data-plyr-config-no-options
Fix loading data-plyr-config when initiating Plyr without any options
2018-04-04 11:33:30 +10:00
536c65e82c Fix loading data-plyr-config when initiating Plyr without any options 2018-04-04 03:16:25 +02:00
cdf14932ec Changelog 2018-04-03 23:03:16 +10:00
3b20dbd9fd v3.1.0 2018-04-03 22:57:34 +10:00
e4d975af00 Styling fixes 2018-04-03 22:56:19 +10:00
2782a00e7c v3.1.0-beta.2 2018-04-03 22:31:55 +10:00
91d192dd7c YouTube speed menu fix 2018-04-03 22:30:29 +10:00
b1e3abc795 v3.1.0-beta.1 2018-04-02 22:52:02 +10:00
3395e8df90 HTML5 quality selection 2018-04-02 22:40:03 +10:00
cce143a7da v3.0.11 2018-03-30 23:14:07 +11:00
d593005b32 Muted and autoplay fixes, small bug fixes 2018-03-30 23:09:17 +11:00
7be9d5d4d3 v3.0.10 2018-03-30 00:16:42 +11:00
d7141d5ed7 Controls docs, package upgrades 2018-03-30 00:11:48 +11:00
0d0ece94d3 Fix regression 2018-03-29 20:20:37 +11:00
1c06f6d06d Vimeo hotfix 2018-03-29 19:35:02 +11:00
dda8e30b92 Merge branch 'master' of github.com:sampotts/plyr 2018-03-28 22:45:18 +11:00
c4e2e24643 Bug fixes 2018-03-28 22:45:11 +11:00
e020a105a3 Update readme.md 2018-03-28 00:55:55 +11:00
2b7fe9a4f9 v3.0.6 2018-03-28 00:17:15 +11:00
951df64b7f v3.0.5 2018-03-27 23:52:26 +11:00
0976afe282 v3.0.4 2018-03-27 23:47:58 +11:00
7b1e4abda7 Controls fixes 2018-03-27 23:43:38 +11:00
0cf75eed3f Revert API method change 2018-03-27 21:15:11 +11:00
d96957d086 Allow fullscreen in iframe 2018-03-27 21:13:22 +11:00
1a032ea498 Fix for seeking issue 2018-03-27 21:10:06 +11:00
5d079da1b8 Use object.entries 2018-03-27 10:41:06 +11:00
9c1bc6ab08 Fixes for fast forward and issues with event.preventDefault() 2018-03-27 10:36:08 +11:00
3d2ba8c009 Update readme.md 2018-03-22 09:11:42 +11:00
e872ce3f77 Update readme.md 2018-03-22 09:10:50 +11:00
b77756da04 Typo 2018-03-22 01:15:10 +11:00
9b23e13ce8 v3.0.3 2018-03-22 01:13:37 +11:00
5eafe9baff Vimeo offset tweak (fixes #826) 2018-03-22 01:08:08 +11:00
c251c94131 Fix for .stop() method (fixes #819) 2018-03-22 01:02:38 +11:00
17041efc71 Check for array for speed options (fixes #252) 2018-03-22 00:33:14 +11:00
05b8e8a6e0 Restore as float (fixes #828) 2018-03-22 00:28:42 +11:00
f998b996fa Fix for Firefox fullscreen oddness (Fixes #821) 2018-03-22 00:26:01 +11:00
958b47c435 Merge branch 'master' of github.com:sampotts/plyr 2018-03-22 00:06:26 +11:00
a27248d3b6 Merge pull request #820 from saadshahd/patch-1
Fix fast-forward control
2018-03-22 00:05:24 +11:00
1b1f7be7ff Merge branch 'master' of github.com:sampotts/plyr 2018-03-22 00:04:34 +11:00
59d4a27240 Improve Sprite checking (fixes #827) 2018-03-22 00:04:28 +11:00
75e9f3c2e3 Fix fast-forward control
fast-forward control doesn't work.
2018-03-21 12:15:57 +02:00
7132eccf50 Merge pull request #822 from DanielRuf/patch/fix-options-link
fix the options link in the readme
2018-03-21 09:12:06 +11:00
e953c6398c fix the options link in the readme 2018-03-20 15:05:51 +01:00
bb7eea27e5 v3.0.2 2018-03-18 22:46:36 +11:00
595c5e95bc Fix for Safari with adblockers 2018-03-18 22:37:06 +11:00
43e6dcd41d Fix for local storage issue 2018-03-18 01:37:24 +11:00
b06c8ae43f Changelog updated 2018-03-18 01:14:18 +11:00
c7ea13c0c7 Sentry in live only 2018-03-18 01:08:05 +11:00
0f8c6e147b Added Sentry 2018-03-18 00:21:23 +11:00
e566365288 Typo 2018-03-17 23:44:40 +11:00
a06e0f5890 Updated screenshot 2018-03-17 23:40:28 +11:00
3bccc0da01 v3.0.0 2018-03-17 23:33:25 +11:00
a0173d991e Removed beta message 2018-03-17 23:31:34 +11:00
600f0eb8a3 Merge branch 'beta'
# Conflicts:
#	readme.md
2018-03-17 23:30:16 +11:00
5db73b1327 Added buffered getter 2018-03-17 23:27:40 +11:00
5cb1628cd8 Vimeo fix 2018-03-15 10:29:05 +11:00
c74b75e8e1 3.0.0-beta.20 2018-03-13 23:35:17 +11:00
0538476d6f 3.0.0-beta.19 2018-03-13 22:15:28 +11:00
5ebe18d081 Typography fix 2018-03-13 22:00:40 +11:00
207adde36d 3.0.0-beta.18 2018-03-13 21:44:18 +11:00
1b13ddaa54 Update ads 2018-03-13 21:42:01 +11:00
9981c349be Fix for null manager race condition 2018-03-11 18:23:47 +11:00
b3365a7373 Normalised event names and removed unused 2018-03-11 12:54:51 +11:00
9a0c1c830d Merge pull request #804 from friday/ads-trigger-arguments
[v3] Add optional arguments to Ads.trigger
2018-03-11 10:55:29 +11:00
ef27ba16f4 Add optional argument to Ads.trigger (currently only used for adblocker error) 2018-03-10 16:20:33 +01:00
e206edc1f6 Event listener fixes, loadScript promise, ads tweaks 2018-03-11 02:03:35 +11:00
c734bc4957 Merge branch 'beta' of github.com:sampotts/plyr into beta 2018-03-10 23:32:55 +11:00
572b8a7aca Manually merged PRs 2018-03-10 23:32:48 +11:00
eebae4a227 Merge pull request #802 from gehaktmolen/ad-hotfixes
Advertisement couldnt be loaded when creative dimensions do not align after resizing
2018-03-10 23:32:15 +11:00
6a2ca534d2 Removed redundant wrappers within the adsmanager promises. 2018-03-09 14:29:37 +01:00
7adc2bc6c8 Unneeded else has been removed within the play() method. 2018-03-09 13:21:19 +01:00
ba8d7831a7 Made sure play() returns a promise. 2018-03-09 12:50:57 +01:00
69ffcbad27 Ad block detection would not work when calling play() right after creating the player instance, so the adsManager now also rejects on such a case. Also made sure that calling play() will wait for the adsManager promise to resolve or otherwise return the media.play() method. 2018-03-09 11:17:24 +01:00
819f7d1080 Resizing the ad container while having it on display none will return offset width and height of 0, which will cause ads not to play when ad sizes are set within the clients DSP. Also making sure that the inner containers of the ad container are full size. The container is now hidden/ displayed using z-index. 2018-03-07 15:43:48 +01:00
409b588458 Made sure that cue points for midrolls are not displayed when the ad rule for a midroll doesn't exceed the total play time of a video. 2018-03-07 15:17:30 +01:00
e90a603d57 Removed a double this.enabled variable and updated a comment in ads.js. Also made sure the adsmanager promise also can fail, so we can use it to wait for getting the advertisement ready when someone clicks the play button. Otherwise there it can look glitchy when the actual video starts playing and the video ad plays a few seconds later because the vast tag was slow to retrieve. Also fixed a typo. 2018-03-06 17:27:59 +01:00
6f061621ad v3.0.0-beta.17 2018-03-03 23:16:15 +11:00
0300610108 Typo 2018-03-03 23:14:57 +11:00
2fba5f152c 3.0.0-beta.16 2018-03-03 23:06:54 +11:00
317b08c703 Ready event fix, YouTube play event fix, docs update 2018-03-03 23:06:12 +11:00
bfb550b8d0 Package updates 2018-02-22 23:46:52 +11:00
174234c166 v3.0.0-beta.15 2018-02-19 09:55:16 +11:00
24b4220de5 Fix IE CORS captions 2018-02-19 09:52:46 +11:00
f1895a4cce Pause button fix, polyfilled build, unminified builds 2018-02-17 19:34:15 +11:00
c2a6306d46 Merge pull request #781 from friday/gulp-unminified-js-output
Build both minified and non-minified js-bundles
2018-02-17 09:22:34 +11:00
7ac732f45b Merge branch 'beta' into gulp-unminified-js-output 2018-02-17 09:22:19 +11:00
c90f1bdf08 v3.0.0-beta.13 2018-02-13 00:02:13 +11:00
6a9be8d16b Fix for custom controls 2018-02-13 00:01:19 +11:00
58c2c52c95 Merge branch 'beta' of github.com:sampotts/plyr into beta 2018-02-11 15:09:40 +11:00
73a39769d4 Fullscreen API changes, color settings tweaks 2018-02-11 15:09:34 +11:00
7221e26eca Merge pull request #780 from friday/captions-ie11-indexsizeerror
Fix harmless but annoying IE error 'IndexSizeError'
2018-02-06 12:51:45 +11:00
98adb8e784 Fix harmless but annoying IE error 'IndexSizeError' 2018-02-06 02:39:01 +01:00
a59dcb2f53 Gulp js build: create both minified and non-minified outputs 2018-02-06 01:57:27 +01:00
d21b58e1c9 Copy 2018-02-06 11:26:13 +11:00
d6e84cbabb Nicer checks 2018-02-06 11:12:03 +11:00
fcccf1d479 Copy 2018-02-06 11:08:26 +11:00
211db12a3d Readme merge 2018-02-06 11:06:46 +11:00
ce1d5a60d6 Remove eslint-rule 'no-shadow' (common variable names should be able to exist in different scopes) 2018-02-05 23:22:20 +01:00
f67315e20c 3.0.0-beta.12 2018-02-06 00:25:50 +11:00
2150c44036 Added backwards compatibility for <div> embeds 2018-02-06 00:24:48 +11:00
70c9fbdde3 Removed fetch dependency 2018-02-05 21:43:32 +11:00
f3ea31c515 Merge branch 'beta' of github.com:sampotts/plyr into beta
# Conflicts:
#	dist/plyr.js
#	dist/plyr.js.map
2018-02-05 21:28:16 +11:00
1ee88cba16 Testing fetch 2018-02-05 21:26:18 +11:00
af3ae75229 Update readme.md 2018-02-03 23:16:52 +11:00
d76ef3ff91 Small UI tweaks and fix for instanceof issue 2018-01-31 19:33:00 +11:00
2691c7c9d6 Version bump + icon fix 2018-01-30 13:01:05 +11:00
26b1d8ce8f Fix UMD stuff 2018-01-30 12:57:19 +11:00
6fae148fc1 Deploy 2018-01-30 09:26:09 +11:00
bb51647fe2 Merge pull request #772 from sampotts/fix/ads-blocked
Fix: ads blocked and media playing before ad plays
2018-01-30 09:22:54 +11:00
71efbe7a92 Merge branch 'beta' into fix/ads-blocked
# Conflicts:
#	dist/plyr.js
#	dist/plyr.js.map
#	src/js/plugins/ads.js
#	src/js/plyr.js
2018-01-30 09:22:14 +11:00
afd695cb39 Fix typo's 2018-01-29 22:45:46 +01:00
c4eb4c97ac fix(ads): Fixes media from playing when ads are blocked 2018-01-29 22:40:08 +01:00
8f7a8940f3 Version bump 2018-01-25 22:42:52 +11:00
5e68f8c8dd Attempt to fix YouTube message error, added ads references, changes to bool 2018-01-25 22:41:30 +11:00
b4e22e2e7b Restored “Ad” in label 2018-01-24 09:06:20 +11:00
d4234da9aa Docs tweak 2018-01-23 19:13:35 +11:00
1f53b27d4e Version bump 2018-01-23 18:00:08 +11:00
cc128e6088 Renamed property, UI tweak 2018-01-23 10:31:21 +11:00
3c8acb4e9e Fix bug where ad would play on every play action 2018-01-22 21:07:08 +01:00
ebf53d14b1 Small tweaks 2018-01-22 23:39:09 +11:00
b298587c0b Bug fix 2018-01-22 23:20:03 +11:00
26e9aaceb8 Version bump 2018-01-22 23:17:40 +11:00
384f3d6eda Gulp 2018-01-22 23:16:50 +11:00
3aa5747c90 Merge pull request #760 from sampotts/beta-with-ads
Beta with ads
2018-01-22 23:15:52 +11:00
5671235fd9 Formatting, events and ad countdown added 2018-01-22 23:15:10 +11:00
1dd5c9efd9 Converted demo to iife 2018-01-20 15:23:36 +11:00
5fad152cbf Formatting and “ad” badge 2018-01-19 20:24:15 +11:00
f33ca846f2 Build 2018-01-19 14:30:28 +11:00
986c802acd Merge branch 'beta-with-ads' of github.com:sampotts/plyr into beta-with-ads
# Conflicts:
#	src/js/plugins/ads.js
2018-01-19 14:30:11 +11:00
98dd818bf6 Merge branch 'beta' into beta-with-ads
# Conflicts:
#	demo/dist/demo.js
#	demo/dist/demo.js.map
#	dist/plyr.js
#	dist/plyr.js.map
2018-01-19 14:28:39 +11:00
021f6c8460 Comments and formatting 2018-01-19 14:26:25 +11:00
392f837398 Merge pull request #763 from gehaktmolen/beta-with-ads-adjustments
Beta with ads - Reloading ads on new video
2018-01-19 14:26:08 +11:00
6831c30534 Transition event fix 2018-01-19 14:22:26 +11:00
ed6048034b Noticed that Plyr stopped working when ads are blocked. 2018-01-18 14:04:47 +01:00
8af312fe3c Updated pause and resume content methods within Ads class. 2018-01-18 12:31:10 +01:00
d87ada4f58 Reformatted ads codebase and added/ changed comments. Also removed un-used events. 2018-01-18 12:26:53 +01:00
31c8166562 Fixed string literal and position issue of the midroll cue inside the time line. Added a check for the progress element existence. 2018-01-17 15:57:10 +01:00
0cb2f95888 Removed an un-used variable. 2018-01-17 15:43:08 +01:00
896ea7c689 Added cue markings within the time line for when midrolls will be displayed. Removed unusued callback parameter. 2018-01-17 15:38:26 +01:00
1d1eb02bd7 Added the logging of our main promises to their resolving callback. Otherwise they come up as null. 2018-01-17 14:44:44 +01:00
3583165b30 Removed logic related to starting the ad by clicking/ tapping the advertisement container. Ad is started by plyr play method. 2018-01-17 14:09:11 +01:00
d822f0c6bf Adsmanager is now re/pre-loaded with new ads when the video is done or an ad error appears. Will make it possible to request ads when a new video is loaded. Added comments and missing events within the adsmanagerloader method. 2018-01-17 13:58:39 +01:00
9e52296dc6 Moved the ads container to be outside of the video wrapper. This way we can easily move the ad in front or behind the video controls based on content resume or pause IMA events. 2018-01-17 12:19:32 +01:00
12a7a4142c Moved the logic for pausing and playing the video to content pause/ resume IMA events to avoid flickering. Also used events for resolving the adsmanager and adsloader promises. 2018-01-17 11:32:13 +01:00
8348f79742 Fix loading/playing of the ads when there is no valid ads.tagUrl 2018-01-17 08:31:36 +01:00
ec73d34bd3 Some tweaks 2018-01-16 23:06:40 +01:00
1cef48d4f8 fix blocking play() if ads are set 2018-01-15 23:30:54 +01:00
c24c05226d Merge pull request #761 from gehaktmolen/beta-with-ads-promises
Beta with ads - Added promises, missing events, new ad tag and additional logging.
2018-01-15 20:13:51 +01:00
4b0005c28e Added promises, missing events, new ad tag and additional logging. 2018-01-15 14:47:34 +01:00
8064405dbc Tweaks 2018-01-14 23:33:18 +11:00
22e8892993 Code tweaks 2018-01-14 23:15:33 +11:00
cfc86bcb7c Merge branch 'beta' into beta-with-ads
# Conflicts:
#	demo/dist/demo.js
#	demo/dist/demo.js.map
#	dist/plyr.js
#	dist/plyr.js.map
2018-01-14 22:55:44 +11:00
5f96ec6ac2 Minor logic tweak 2018-01-14 22:54:03 +11:00
bbdf225d7b Fix loading google ima sdk 2018-01-14 08:21:35 +01:00
025fc1090b Implementing ads plugin 2018-01-13 23:02:59 +01:00
d9ec1d1b8e Progressively enhance <iframe> embeds 2018-01-12 19:35:46 +11:00
2e5d06ad85 Publish script tweaks 2018-01-09 20:43:58 +11:00
bacd049eb0 Package 2018-01-09 20:26:56 +11:00
6fd7b26bb2 Beta version up on https://plyr.io/beta and CDN 2018-01-09 20:25:46 +11:00
1df79cf7f8 Publishing to /beta 2018-01-09 19:35:17 +11:00
e6badacf0d Recommended extensions for VS Code 2018-01-09 18:52:36 +11:00
a0d9d5eca8 Styling tweaks 2018-01-09 09:14:59 +11:00
8786377a75 Use CSS custom property for webkit range fill 2018-01-08 20:53:18 +11:00
f0322e8d94 Merge branch 'develop' of github.com:sampotts/plyr into develop 2018-01-08 19:42:29 +11:00
3f2ac3fca0 Package tweaks 2018-01-08 19:42:21 +11:00
9872207e87 Merge pull request #752 from friday/gulp-fix
Enable gulp builds when aws.json isn't present.
2018-01-08 12:12:11 +11:00
58d942e737 Fix gulp build for user who doesn't have aws.json 2018-01-08 02:01:39 +01:00
dd190155c4 Empty storage fix 2018-01-07 23:16:55 +11:00
ebb3b83b27 Merge branch 'master' into develop
# Conflicts:
#	src/js/plyr.js
2018-01-07 22:46:28 +11:00
2b36ab7ef5 Merge branch 'master' into develop
# Conflicts:
#	.vscode/settings.json
#	demo/dist/demo.css
#	demo/dist/demo.js
#	demo/error.html
#	demo/index.html
#	demo/src/js/main.js
#	demo/src/less/lib/fontface.less
#	dist/plyr.css
#	dist/plyr.js
#	gulpfile.js
#	package-lock.json
#	package.json
#	readme.md
#	src/js/plyr.js
#	src/less/plyr.less
#	src/scss/plyr.scss
2018-01-07 22:39:28 +11:00
eb38e0394d Slider styling 2018-01-07 22:35:52 +11:00
e14e2cfaff Merge branch 'develop' of https://github.com/Selz/plyr into develop 2018-01-05 10:37:38 +11:00
04119b27e6 Tweaks 2018-01-05 10:37:34 +11:00
Sam
92cb9e22e2 Started on error handling 2018-01-04 13:43:56 +11:00
Sam
6b9106ddb1 Fix for promise issue on Chrome, loading fix 2017-12-27 21:40:35 +00:00
965fc0b2f5 Docs, restored loadSprite and supported static methods 2017-12-23 18:42:52 +00:00
98ac98b4c2 Vimeo fix 2017-12-21 00:20:56 +00:00
178b0d8020 Badge tweak 2017-12-21 00:06:59 +00:00
3bd1c1ff56 Fix for scrubber 2017-12-20 22:06:26 +00:00
7d4bf91a35 Small fixes 2017-12-20 21:45:06 +00:00
ac3d1d1242 Docs 2017-12-20 21:10:43 +00:00
742018a716 Fix SASS bundle 2017-12-20 21:08:44 +00:00
a2ef691b4b Comment update 2017-12-20 20:49:41 +00:00
9e0c406a4a Remove chaning ability and return promise for play() 2017-12-20 20:47:02 +00:00
f3df7aba15 Split up settings file 2017-12-20 18:00:05 +00:00
6bc3592381 Fix for rounding 2017-12-20 15:32:16 +00:00
6864149989 Converted to SASS/SCSS 2017-12-20 15:14:05 +00:00
aab53fa91f Minor tweaks 2017-12-18 16:57:23 +00:00
423f67b4f4 Copy 2017-12-08 15:55:12 +00:00
82f81f4f73 More Edge fixes and small UI bugs 2017-12-08 15:54:08 +00:00
c8990bd379 IE & Edge fixes, Storage & Console classes 2017-12-08 10:05:38 +00:00
de54929bb7 Safari CSS fixes and variables setup 2017-11-25 22:54:04 +11:00
fd77831303 Fix display for current language on change 2017-11-25 01:19:16 +11:00
cda574e627 Map 2017-11-24 08:47:17 +11:00
fda1977119 Fix for keyboard increase/decrease volume 2017-11-24 08:47:11 +11:00
f7bf0961cf Fix overflow issue on small players with menu open 2017-11-23 22:32:07 +11:00
61325bbad1 Vimeo captions fix 2017-11-23 20:50:07 +11:00
921cefd212 Moved to provider + type to make it cleaner in future, fix for multiple players 2017-11-23 17:35:35 +11:00
de6f0f1b77 Updated data attributes to data-plyr namespace. Speed menu fixes 2017-11-23 12:57:43 +11:00
7382553a78 Work on touch controls 2017-11-22 00:04:11 +11:00
4b82e89845 Fix for playing getter as currentTime check is flaky 2017-11-21 21:14:44 +11:00
d3b31e595a Handle no audio, more docs in code, fix for playing getter 2017-11-21 20:14:57 +11:00
f33bc5a5c6 Minor tweaks 2017-11-21 14:05:55 +11:00
f518ec108b Vimeo autopause option 2017-11-21 13:33:51 +11:00
edfc6cd475 Play button as toggle button, tooltip changes, docs updated, fullscreen fix 2017-11-21 13:12:36 +11:00
92cd67effb Docs to build custom CSS for plyr 2017-11-20 23:53:54 +11:00
da1e987444 WIP on docs example 2017-11-20 21:23:49 +11:00
2d4a166218 Merge branch 'develop' of https://github.com/Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
#	dist/plyr.js.map
2017-11-20 10:48:53 +11:00
feae00224e Added ended and playing getters 2017-11-20 10:48:28 +11:00
000afdd300 Merge branch 'develop' of github.com:Selz/plyr into develop 2017-11-19 23:35:23 +11:00
0dc9681ae8 YouTube title 2017-11-19 23:35:07 +11:00
dc391c98c6 UI tweaks 2017-11-19 21:15:24 +11:00
4b62a5c74d Captions fix 2017-11-19 17:54:38 +11:00
3f744ef63a Formatting 2017-11-18 19:36:36 +11:00
5a244b7fed Merge branch 'develop' of https://github.com/Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
#	dist/plyr.js.map
#	src/js/controls.js
2017-11-18 19:33:01 +11:00
4dca4bf93c Minor fixes 2017-11-18 19:31:45 +11:00
6984d6fb16 Controls cleanup, work on captions bug, click to invert time 2017-11-18 19:30:26 +11:00
d7a1c44281 Using fetch instead of xhr, grabbing title for YouTube 2017-11-16 11:38:06 +01:00
c64b8f6940 Started on error handling, Safari icon fix 2017-11-14 17:27:40 +01:00
022b436c3f YouTube fix 2017-11-14 13:22:23 +01:00
6058bb0245 Docs 2017-11-12 08:16:47 +00:00
3ade86537d Docs, keyboard shortcut fixes 2017-11-12 08:14:14 +00:00
d80be3b903 More docs, event renamed 2017-11-12 07:45:52 +00:00
1a26681d87 Added Sparkk TV to the list of users 2017-11-10 00:19:44 +11:00
9171297764 More docs 2017-11-10 00:06:46 +11:00
ebd1a52e5d Config docs 2017-11-09 21:18:09 +11:00
743c84188e Fix for destroy 2017-11-09 20:54:14 +11:00
4879bea4a0 Moved console methods out of the root of the object 2017-11-09 20:01:13 +11:00
66917fd39b Use callback for loading Vimeo API 2017-11-09 19:44:07 +11:00
fd97607e55 Merge branch 'develop' of https://github.com/Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
#	dist/plyr.js.map
2017-11-09 19:41:12 +11:00
f878581c8f UI bugs 2017-11-09 19:40:45 +11:00
f9602acf61 Callback for loadScript 2017-11-09 16:06:49 +11:00
86a5724bdb Missing code highlight 2017-11-09 00:22:40 +11:00
63c963d726 More docs 2017-11-09 00:21:44 +11:00
88bfa35b99 Test 2017-11-09 00:06:34 +11:00
bb66be98da Volume fixes and other tidy up work 2017-11-08 23:46:20 +11:00
c948e95ade Looping, increase/decrease volume fix 2017-11-08 00:37:14 +11:00
1a5f4b1b9e Merge branch 'develop' of github.com:Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
#	dist/plyr.js.map
#	src/js/defaults.js
2017-11-07 23:23:17 +11:00
3f41a0cf54 Merge branch 'develop' of github.com:Selz/plyr into develop
# Conflicts:
#	readme.md
2017-11-07 23:21:35 +11:00
966ca1acc3 Trap focus fix 2017-11-07 18:01:24 +11:00
e2c7491ccd Using the “href” attribute on SVG if supported, using hasAttribute 2017-11-07 09:58:37 +11:00
fae4ca12e0 Started on docs 2017-11-06 23:06:14 +11:00
84505da84b Automatic Vimeo aspect ratio 2017-11-06 22:00:00 +11:00
2497e25b3c Global listeners to prevent repeat binding 2017-11-06 21:19:00 +11:00
9c4b7e7094 Keyboard logic 2017-11-06 20:34:11 +11:00
3a9beaed59 Vimeo captions fix 2017-11-06 20:27:19 +11:00
1578525ee3 Finished aspect ratio setting 2017-11-06 20:24:07 +11:00
62c1b368cf Cleanup 2017-11-06 19:53:27 +11:00
f8ecea8fb7 Added Vimeo playback speed 2017-11-06 19:47:14 +11:00
0068710740 Started on documentation and aspect ratio option 2017-11-06 19:38:31 +11:00
5fe477340b Tab focus classname change 2017-11-05 23:20:26 +11:00
45df319823 Keyboard shortcut tweaks 2017-11-05 23:09:33 +11:00
6bebbe4153 Key listeners fix 2017-11-05 20:49:37 +11:00
374de800a4 Captions fix 2017-11-05 18:57:22 +11:00
60084a17f8 YouTube volume fix 2017-11-05 18:40:41 +11:00
4d417d0396 Vimeo fix 2017-11-05 12:04:31 +11:00
e2d8bd2b73 Captions language fix 2017-11-05 11:59:15 +11:00
1c693df00b src getter fix, local storage fix 2017-11-05 11:45:02 +11:00
8aaa932050 Cleanup 2017-11-05 01:13:00 +11:00
3cd6c2acf6 Merge branch 'develop' of https://github.com/Selz/plyr into develop 2017-11-05 01:02:17 +11:00
3930ebb339 Menu design tweaks, moved logic into plugins 2017-11-05 01:02:10 +11:00
b102714067 Merge pull request #705 from friday/editorconfig
Add .editorconfig file
2017-11-05 00:49:45 +11:00
13d3037a53 Meta data and icons updated 2017-11-05 00:29:21 +11:00
1e7a60ee5c Add .editorconfig file 2017-11-04 14:16:00 +01:00
8d80f6b05d Removed log 2017-11-04 23:53:03 +11:00
597b3fe0db Retrofit PRs 2017-11-04 22:41:18 +11:00
d920de2a25 Small tweaks 2017-11-04 21:19:02 +11:00
069c8093ae Small bug fixes 2017-11-04 14:45:06 +11:00
1cc2930dc0 ES6-ified 2017-11-04 14:25:28 +11:00
3d50936b47 Split LESS into more granular files, Vimeo fixes 2017-10-28 20:14:33 +11:00
dd9d5c8898 Linting and minor changes 2017-10-27 15:06:16 +11:00
71db66d802 Error pages 2017-10-26 20:59:40 +11:00
959b5a20e3 Inlined SVGs, fixed build 2017-10-26 00:10:56 +11:00
9de5c0cf39 Built JS 2017-10-26 00:00:15 +11:00
1a3868a6c6 Merge branch 'develop' of https://github.com/Selz/plyr into develop 2017-10-25 23:59:59 +11:00
378aa159b8 Docs/demo refresh 2017-10-25 23:59:53 +11:00
6876a9163d Merge pull request #694 from friday/fix/volume-steps
Restore volume stepping via key up/down
2017-10-25 23:59:15 +11:00
34d28a69ad Merge pull request #693 from friday/fix/instanceof-undefined
v3: Add instanceof wrapper to avoid TypeErrors
2017-10-25 23:54:10 +11:00
0715d3ae67 Restore up/down arrow behavior from v2 (10 steps between min and max instead of one) 2017-10-25 14:25:10 +02:00
542095f5eb Add instanceof wrapper that avoids TypeError when second argument is undefined 2017-10-25 14:10:38 +02:00
57517a9dcc Fullscreen improvements 2017-10-18 23:55:53 +11:00
751708ff23 Fix 2017-10-18 19:47:03 +11:00
fcf944788a Cleanup 2017-10-18 12:47:54 +11:00
36a84c5c2d Removed extra <progress> for populating lower fill on range inputs 2017-10-18 12:43:10 +11:00
4392abfc49 Merge branch 'develop' of https://github.com/Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
2017-10-08 19:12:55 +11:00
3238b6a36a Fullscreen fix 2017-10-08 19:12:25 +11:00
18a5edef0e Linting 2017-10-08 19:10:04 +11:00
02cb093f7b Small tweaks to focus 2017-10-03 00:00:45 +11:00
d6977473b1 Formatting 2017-10-02 21:03:51 +11:00
15cffad89e CDN URLs 2017-10-02 14:54:35 +11:00
0d96601d1a CDN URLs 2017-10-02 14:48:15 +11:00
7959297a98 Merge branch 'develop' of https://github.com/Selz/plyr into develop 2017-10-02 13:55:08 +11:00
6dd010ea34 Comments, small tweaks 2017-10-02 13:55:03 +11:00
f89ddb2f1b Merge pull request #669 from friday/fix/prevent-buttons-from-submitting-form
Prevent buttons from submitting form (v3)
2017-09-27 23:33:28 +10:00
2e5cc272e3 Merge pull request #670 from friday/fix/errors-without-settings-pane
Avoid errors when initiating plyr without settings (v3)
2017-09-27 23:32:25 +10:00
ebd13c63e8 Avoid multiple errors when initiating plyr without 'settings' in controls 2017-09-27 05:09:56 +02:00
ec091266aa Prevent buttons from submitting form 2017-09-27 02:34:23 +02:00
ad105877ed Merge pull request #667 from friday/fix/caption-feature-detection
Fix 'TypeError: Cannot read property 'kind' of null' in captions feat…
2017-09-27 10:03:25 +10:00
c84f666b55 Fix 'TypeError: Cannot read property 'kind' of null' in captions feature detection if video lacks captions 2017-09-27 00:24:54 +02:00
2bba1f30e2 Fixing Vimeo captions, WIP on settings menu, prettier and VS code settings 2017-09-03 14:36:55 +10:00
2196665495 Cleanup 2017-08-16 13:30:27 +10:00
0148c76c30 ESLint, comments, quality and speed menus 2017-08-16 00:36:23 +10:00
18b2cbb2e9 Small tweak 2017-08-13 13:54:16 +10:00
f6a7555a1d Work on quality control 2017-08-06 21:00:31 +10:00
f7144dc0cb Fix bug when switching sources 2017-08-06 13:42:37 +10:00
a9957211f4 Work on playback rate changes 2017-07-31 09:58:30 +10:00
7b60e473fa Small tweaks 2017-07-23 21:13:11 +10:00
dfc516baf6 Merge branch 'develop' of https://github.com/Selz/plyr into develop 2017-07-09 17:17:26 +10:00
b0d3bcd15a Notes 2017-07-09 17:17:21 +10:00
03c3960e93 Tweaks 2017-07-09 17:14:42 +10:00
21f444ed61 Tweaks 2017-06-12 09:26:01 +07:00
40b4f8e840 Tweaks 2017-06-04 22:39:21 +10:00
bc61dac4c5 Tidy up, fixing destroy 2017-06-04 18:30:37 +10:00
3605989226 Warning 2017-06-04 15:51:37 +10:00
a49d77afab Source change fix 2017-06-04 15:50:47 +10:00
7daa08c32f Change to proper constructor + prototypes 2017-06-04 15:27:37 +10:00
aaab9ad082 Seperated reduce motion check 2017-05-22 09:07:14 +10:00
86c9004183 More work on the menu 2017-05-22 08:55:45 +10:00
857dfe838c Menu toggle 2017-05-21 17:50:07 +10:00
e1a19faf26 URL updates 2017-05-16 10:20:58 +10:00
f3bda17fa0 Merge branch 'master' into develop
# Conflicts:
#	demo/dist/demo.js
#	demo/src/js/main.js
#	dist/plyr.js
#	notes.md
#	src/js/plyr.js
2017-05-16 10:17:04 +10:00
966c3d875d Single instance only 2017-05-16 09:58:53 +10:00
fe9383bed5 Cleanup 2017-05-09 21:30:09 +10:00
2c31770030 Update notes 2017-05-09 00:20:22 +10:00
8d3e160166 Adding support for playsinline 2017-05-09 00:18:19 +10:00
408cfe5b97 Added support for passive event listeners 2017-05-08 23:07:19 +10:00
279fee3595 Bug fixes 2017-05-07 20:17:36 +10:00
28dddfcff2 Vimeo captions working 2017-05-07 20:07:08 +10:00
9e2580ec6a Merge branch 'develop' of https://github.com/Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
2017-05-07 19:04:05 +10:00
aba5a9dc0e Utils object, work on Vimeo captions 2017-05-07 19:03:48 +10:00
9999828505 Merge pull request #574 from mapmelabs/youtube-loop
Implement loop in YouTube
2017-04-28 13:12:31 +10:00
b04301c211 Implement loop in YouTube 2017-04-27 11:53:53 -03:00
97157efcfa More work on Vimeo captions 2017-04-26 00:24:42 +10:00
3756476809 Merge branch 'develop' of github.com:Selz/plyr into develop 2017-04-25 22:39:21 +10:00
b3d798eeee Gulp tweak 2017-04-25 22:39:14 +10:00
b499622eb8 Started on Vimeo captions 2017-04-25 20:45:25 +10:00
04b8d0bac8 Tweaks 2017-04-25 19:31:34 +10:00
8ea4cbd942 Tidy up 2017-04-25 18:43:09 +10:00
7889ae1126 Built JS 2017-04-25 18:37:56 +10:00
897d49ad87 Merge branch 'develop' of https://github.com/Selz/plyr into develop 2017-04-25 18:37:36 +10:00
1960d35d8b More work on menus and tidy up 2017-04-25 18:37:31 +10:00
0b7d0dedf6 Merge pull request #545 from silverwind/blank-mp4
Add blank.mp4 to dist files
2017-04-25 12:40:20 +10:00
948e2cc66c Merge branch 'develop' into blank-mp4 2017-04-25 12:40:13 +10:00
396b816a1f Merge pull request #563 from stormrockwell/master
removed vimeo id parsing because it is not necessary
2017-04-25 12:37:43 +10:00
0a58cbfd59 Merge branch 'develop' into master 2017-04-25 12:37:35 +10:00
bbe4b7e565 Notes 2017-04-22 14:55:03 +10:00
2ecca2cbe3 removed vimeo id parsing because it is not necessary 2017-04-19 15:16:03 -04:00
f5d80fa888 Notes 2017-04-19 22:40:32 +10:00
f2bbe4eb12 Looping menu (WIP) 2017-04-19 22:34:52 +10:00
60e51b7077 Added notes 2017-04-19 21:33:23 +10:00
01d1ac9ab9 Toggle menu 2017-04-17 21:05:35 +10:00
9b2396f5ff Airplay and PiP 2017-04-17 01:28:52 +10:00
da15980b8a ID fix and styling fix 2017-04-17 00:32:41 +10:00
452678867f More work on menus 2017-04-16 20:38:45 +10:00
ff2d27f8e5 Cleanup events and references 2017-04-16 13:00:57 +10:00
546cdaad92 Merge branch 'develop' of https://github.com/Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
2017-04-15 23:22:35 +10:00
5d38497f07 Formatting 2017-04-15 23:22:14 +10:00
808a3af3cf Formatting 2017-04-15 23:21:18 +10:00
889712761a Merge branch 'develop' of github.com:Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
#	src/js/plyr.js
2017-03-29 09:05:25 +11:00
46fab972a0 Namespacing 2017-03-29 09:03:33 +11:00
535c046b62 Merge branch 'develop' of https://github.com/Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
#	src/js/plyr.js
2017-03-28 09:30:37 +11:00
55dfab8394 Tweaks 2017-03-28 09:19:58 +11:00
18bf4d84b9 Menu creation (WIP) 2017-03-28 00:12:33 +11:00
ef1d73df15 Controls rewrite 2017-03-27 00:25:41 +11:00
684107da5c WIP on new controls creation 2017-03-26 21:32:41 +11:00
2a97a9a9c5 Add blank.mp4 to dist files
For a complete "offline" experience, it's necessary to self-host the
file, so include it in the dist files for that purpose.
2017-03-25 10:58:36 +01:00
ca12343b16 Merge branch 'develop' of https://github.com/Selz/plyr into develop 2017-03-25 18:44:17 +11:00
a974fbf31c Notes 2017-03-25 18:44:10 +11:00
6eaf33ec6c Merge pull request #520 from platformpurple/feature/subtitles
Feature/subtitles
2017-03-25 18:43:45 +11:00
33fef7faee Merge branch 'develop' into feature/subtitles 2017-03-25 18:43:36 +11:00
b083bf4297 Merge branch 'master' into develop
# Conflicts:
#	dist/plyr.css
#	dist/plyr.js
#	src/js/plyr.js
#	src/less/plyr.less
#	src/scss/plyr.scss
2017-03-25 11:24:38 +11:00
ebc7ed538a Manual merge of #509 2017-03-25 10:49:04 +11:00
a60868bfe8 Clean up 2017-03-25 10:47:37 +11:00
4a2866d05f Merge branch 'develop' of https://github.com/Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
2017-03-25 10:37:21 +11:00
1a05f352c7 Code formatting 2017-03-25 10:37:00 +11:00
ba27de0669 Merge pull request #510 from platformpurple/feature/loop-events
Added key bindings for loop
2017-03-25 10:35:15 +11:00
e21e7054ce Merge branch 'develop' into feature/loop-events 2017-03-25 10:35:08 +11:00
bc323e905c Manual merge of #543 PR 2017-03-25 10:27:03 +11:00
afa1fe9d5f Merge pull request #514 from platformpurple/improvement/loop-color-area
Improvement/loop color area
2017-03-25 10:22:10 +11:00
2444efc834 Merge branch 'develop' into improvement/loop-color-area 2017-03-25 10:22:02 +11:00
7b6257ff20 Merge branch 'develop' of https://github.com/Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
2017-03-25 10:09:14 +11:00
13973125fb Loop variable naming 2017-03-25 10:08:39 +11:00
ddf9104349 Merge pull request #511 from platformpurple/develop
Fix on typo
2017-03-25 10:07:07 +11:00
47b53fffb4 remove commented out code 2017-03-24 17:29:48 +02:00
9ba3753f80 toggle quality options 2017-03-24 17:25:09 +02:00
a353194fe1 make config.captions.selectedIndex number 2017-03-22 15:50:56 +02:00
c205c47509 set captionExists to true if selectedIndex is bigger than capt source 2017-03-22 13:38:08 +02:00
9c867edfbc fix data typo in language button 2017-03-18 01:59:20 +02:00
9919d80782 check if captions exists 2017-03-15 17:18:34 +02:00
8464ffe6ad Conflicts and tracks array on config 2017-02-24 16:38:00 +02:00
6537225c61 Subtitles tracks 2017-02-24 16:32:17 +02:00
dcbf59bd89 Colored strip indicating looped area 2017-02-15 17:41:04 +02:00
21d478d396 Add looping key bindings to allowed array 2017-02-14 17:15:27 +02:00
054c243416 Fix on typo and gulp 2017-02-14 16:44:29 +02:00
d57e453541 Fix on typo 2017-02-14 16:42:40 +02:00
3f45ef4908 Removed console 2017-02-14 16:29:05 +02:00
1fd742464d Added key bindings for loop 2017-02-14 16:04:58 +02:00
9c599884a8 Merge branch 'develop' of https://github.com/Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
#	src/js/plyr.js
2017-02-05 11:36:53 +11:00
cbef45841c Menu work 2017-02-05 11:34:33 +11:00
96d9f302c2 Merge pull request #490 from platformpurple/develop
Playback speed and looping controls
2017-02-05 11:31:58 +11:00
afcdf17a72 Removed not needed functions + reverted demo.js to previous 2017-02-03 14:52:38 +02:00
1bcdbe4c00 Refactored loop event buttons + on 'No Loop' cleared displayed timing 2017-02-02 11:38:08 +02:00
45c0ded88c Loop functionality 2017-02-01 19:16:39 +02:00
ea30ad9494 Playback speed control settings 2017-01-31 17:21:33 +02:00
7608615702 Merge branch 'develop' of https://github.com/Selz/plyr into develop 2017-01-11 20:14:48 +11:00
cc5f37392f ToDo notes, code tidy up 2017-01-11 20:14:41 +11:00
413fcbcb8c Merge branch 'develop' of github.com:Selz/plyr into develop
# Conflicts:
#	dist/plyr.js
#	src/js/plyr.js
2017-01-10 21:47:49 +11:00
c49d0a99e4 JsBeautifier 2017-01-10 21:43:28 +11:00
5a0cb9289c JsBeautifier in use, syntax tweaks 2017-01-10 20:22:18 +11:00
bce1d983cb Merge pull request #457 from amowu/patch-3
fix: Firefox can not display captions
2017-01-04 08:45:40 +11:00
047fc43f8f Merge pull request #458 from amowu/patch-4
fix: parse webVTT time NaN
2017-01-04 08:45:06 +11:00
0cbfc9252c fix: parse webVTT time NaN 2016-12-16 14:32:04 +08:00
d02e57bdb3 fix: Firefox can not display captions 2016-12-15 16:38:46 +08:00
663c1fb627 Merge pull request #427 from amowu/patch-2
Fix cannot scroll after destroyed
2016-11-27 20:09:49 +11:00
a7969b8e9e Fix cannot scroll after destroyed
In single page application, switch router when plyr is fullscreen mode, page cannot scroll, because `document.body.style.overflow` is `hidden`
2016-11-24 11:21:43 +08:00
4ca3f030cc Merge pull request #419 from amowu/patch-1
refactor: miss prefix
2016-11-18 09:48:40 +11:00
02bc8c8445 refactor: miss prefix
fix _fullscreen.prefix can't work
2016-11-10 16:27:10 +08:00
7965b82cca Quality WIP 2016-11-06 21:47:44 +11:00
bae04a492a Merge branch 'master' into develop
# Conflicts:
#	demo/index.html
#	dist/plyr.js
2016-11-06 15:55:55 +11:00
72404e77e5 PiP 2016-11-01 12:00:16 +11:00
Sam
c7310c21fb Fullscreen fix, styling 2016-10-24 00:11:47 +11:00
Sam
ed9e27b64f Merge branch 'develop' of https://github.com/Selz/plyr into develop 2016-10-23 21:42:18 +11:00
801ed63be5 Work on PiP 2016-10-23 21:21:42 +11:00
Sam
2aa9b267ab Merge branch 'develop' of https://github.com/Selz/plyr into develop
# Conflicts:
#	src/js/plyr.js
2016-10-23 21:16:49 +11:00
Sam
90338d9600 Tweaks 2016-10-23 21:15:19 +11:00
5cecf16d4f Merge branch 'master' into develop
# Conflicts:
#	demo/dist/demo.js
#	dist/plyr.css
#	dist/plyr.js
2016-10-23 15:27:28 +11:00
21a30f1b6f Fixed for array passed to _on and _off 2016-10-03 17:16:05 +11:00
Sam
613c45ede9 Merge branch 'master' into develop 2016-10-01 22:18:40 +10:00
Sam
8743c6a08d Code style 2016-10-01 22:18:01 +10:00
Sam
eba0831538 Manually merged #385 2016-10-01 22:07:01 +10:00
Sam
1ad103c29f Menu animation 2016-09-26 23:21:57 +10:00
Sam
ca37b4c9ac Menu 2016-09-25 23:54:49 +10:00
d3bbf09d12 More menu work 2016-09-25 20:01:58 +10:00
f608317eec Merge branch 'develop' of https://github.com/Selz/plyr into develop
# Conflicts:
#	dist/plyr.css
#	dist/plyr.js
2016-09-14 15:22:41 +10:00
c8b9c9bcaa Expanded 2016-09-13 23:52:25 +10:00
Sam
d638cdcdd3 Started on PIP support 2016-09-13 00:16:27 +10:00
46f82a4af3 Added quality in menu 2016-09-07 22:18:05 +10:00
Sam
42a2642d40 Icon fix 2016-09-06 23:50:59 +10:00
Sam
37840c3844 Working on settings menu 2016-09-06 23:48:09 +10:00
28335ef3d8 Merge pull request #356 from amowu/feature/add-playback-speed
Add playback speed
2016-09-06 20:46:00 +10:00
78ec5b3322 refactor: sorting speed 2016-09-05 22:56:19 +08:00
ac7e1ab299 test: add speed-up button 2016-09-05 18:00:11 +08:00
ea60fd0f45 docs: update readme 2016-08-31 17:18:44 +08:00
c291e8c5d9 refactor: check config.speeds format 2016-08-31 15:42:01 +08:00
f0ac542a7f refactor: add localStorage supporting 2016-08-31 15:34:44 +08:00
a412085785 feat: add playback speed button 2016-08-31 15:11:29 +08:00
156 changed files with 45395 additions and 13339 deletions

10
.editorconfig Normal file
View 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
View 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"
}
}

View File

@ -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
-

View File

@ -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
View File

@ -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/

View File

@ -1,11 +0,0 @@
{
"html": {
"allowed_file_extensions": []
},
"css": {
"allowed_file_extensions": []
},
"js": {
"allowed_file_extensions": []
}
}

View File

@ -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
View File

@ -0,0 +1,4 @@
demo
.github
.vscode
*.code-workspace

7
.prettierrc Normal file
View File

@ -0,0 +1,7 @@
{
"useTabs": false,
"tabWidth": 4,
"printWidth": 160,
"singleQuote": true,
"trailingComma": "all"
}

25
.stylelintrc.json Normal file
View 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
View 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
View 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
View 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}"
}
]
}

View File

@ -1,2 +1 @@
{
}
{}

52
CONTRIBUTING.md Normal file
View 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.

View File

@ -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"
}
}

View File

@ -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"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because one or more lines are too long

4373
demo/dist/demo.js vendored

File diff suppressed because it is too large Load Diff

1
demo/dist/demo.js.map vendored Normal file

File diff suppressed because one or more lines are too long

2
demo/dist/demo.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
demo/dist/demo.min.js.map vendored Normal file

File diff suppressed because one or more lines are too long

1
demo/dist/demo.svg vendored
View File

@ -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

File diff suppressed because one or more lines are too long

View 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>

View File

@ -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> &copy; Brainfarm</small></li>
<li class="plyr__cite plyr__cite--audio"><small><a href="http://www.kishibashi.com/" target="_blank">Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;</a> &copy; Kishi Bashi</small></li>
<li class="plyr__cite plyr__cite--youtube"><small><a href="https://www.youtube.com/watch?v=bTqVqk7FSmY" target="_blank">View From A Blue Moon</a> on <span class="color--youtube"><svg class="icon"><use xlink:href="#icon-youtube"/></svg>YouTube</span></small></li>
<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> &copy; 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 &ndash; &ldquo;It All Began With A Burst&rdquo;</a> &copy; 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&nbsp;
<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&nbsp;
<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.&amp;url=http%3A%2F%2Fplyr.io&amp;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>

View 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

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

327
demo/src/js/demo.js Normal file
View 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 &ndash; &ldquo;It All Began With A Burst&rdquo;',
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 */
})();

View File

@ -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;
}());
}
}

View File

@ -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 &ndash; &ldquo;It All Began With A Burst&rdquo;",
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");
}

View File

@ -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);
}
}

View File

@ -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%);
}
}

View File

@ -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;
}

View File

@ -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";

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View 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';

View 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';

View 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;
}
}

View 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;
}
}

View File

@ -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);
}

View 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;
}
}

View File

@ -0,0 +1,11 @@
// ==========================================================================
// Lists
// ==========================================================================
// Lists
ul,
li {
list-style: none;
margin: 0;
padding: 0;
}

View File

@ -0,0 +1,10 @@
// ==========================================================================
// Basic media
// ==========================================================================
img,
video,
audio {
max-width: 100%;
vertical-align: middle;
}

View File

@ -0,0 +1,9 @@
// ==========================================================================
// Navigation
// ==========================================================================
nav {
display: flex;
justify-content: center;
margin-bottom: $spacing-base;
}

View File

@ -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);
}
}

View 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);
}
}
}

View File

@ -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);
}
}

View 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;
}
}
}

View File

@ -3,7 +3,11 @@
// ==========================================================================
// Fade
@keyframes fade-in {
0% { opacity: 0 }
100% { opacity: 1 }
}
@keyframes fadein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}

View 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');
}

View 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
View 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;
}

View 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;
}

View File

@ -0,0 +1,6 @@
// ==========================================================================
// Breakpoints
// ==========================================================================
$screen-sm: 480px;
$screen-md: 768px;

View 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;

View 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%));

View File

@ -0,0 +1,5 @@
// ==========================================================================
// Icons
// ==========================================================================
$icon-size: 16px;

View File

@ -0,0 +1,5 @@
// ==========================================================================
// Layout
// ==========================================================================
$container-max-width: 1260px;

View 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;

View File

@ -0,0 +1,5 @@
// ==========================================================================
// Colors
// ==========================================================================
$spacing-base: 20px;

View 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;

View 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;
}

View 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;
}

View File

@ -0,0 +1,7 @@
// ==========================================================================
// Misc cosmetic
// ==========================================================================
.no-border {
border: 0;
}

View 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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

Binary file not shown.

2
dist/plyr.css vendored

File diff suppressed because one or more lines are too long

8158
dist/plyr.js vendored

File diff suppressed because one or more lines are too long

1
dist/plyr.js.map vendored Normal file

File diff suppressed because one or more lines are too long

2
dist/plyr.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/plyr.min.js.map vendored Normal file

File diff suppressed because one or more lines are too long

13542
dist/plyr.polyfilled.js vendored Normal file

File diff suppressed because it is too large Load Diff

1
dist/plyr.polyfilled.js.map vendored Normal file

File diff suppressed because one or more lines are too long

2
dist/plyr.polyfilled.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/plyr.polyfilled.min.js.map vendored Normal file

File diff suppressed because one or more lines are too long

2
dist/plyr.svg vendored
View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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
}
}

1407
readme.md

File diff suppressed because it is too large Load Diff

250
src/js/captions.js Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

405
src/js/defaults.js Normal file
View 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
View 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
View 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
View 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
View 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;

Some files were not shown because too many files have changed in this diff Show More