aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/pull_request_template.md8
-rw-r--r--bower.json4
-rw-r--r--changelog.md16
-rw-r--r--controls.md1
-rw-r--r--demo/dist/demo.css2
-rw-r--r--demo/error.html37
-rw-r--r--demo/index.html167
-rw-r--r--demo/src/js/main.js178
-rw-r--r--demo/src/less/lib/fontface.less20
-rw-r--r--dist/plyr.css2
-rw-r--r--gulpfile.js14
-rw-r--r--license.md2
-rw-r--r--package.json90
-rw-r--r--readme.md50
-rw-r--r--src/js/plyr.js1823
-rw-r--r--src/less/plyr.less88
-rw-r--r--src/scss/plyr.scss110
17 files changed, 1448 insertions, 1164 deletions
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index f1ad850d..c4779d3c 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,8 +1,8 @@
-### Link to related issue (if applicable)
+### Link to related issue (if applicable)
-### Sumary of proposed changes
+### Sumary of proposed changes
### Task list
-- [ ] Tested on [supported browsers](https://github.com/Selz/plyr#browser-support)
-- [ ] Gulp build completed \ No newline at end of file
+- [ ] Tested on [supported browsers](https://github.com/sampotts/plyr#browser-support)
+- [ ] Gulp build completed \ No newline at end of file
diff --git a/bower.json b/bower.json
index 5903f44a..74b2e9fc 100644
--- a/bower.json
+++ b/bower.json
@@ -9,7 +9,7 @@
"HTml5 Video"
],
"authors": [
- "Sam Potts <me@sampotts.me>"
+ "Sam Potts <sam@potts.es>"
],
"dependencies": {},
"main": [
@@ -27,7 +27,7 @@
],
"repository": {
"type": "git",
- "url": "git://github.com/selz/plyr.git"
+ "url": "git://github.com/sampotts/plyr.git"
},
"license": "MIT"
}
diff --git a/changelog.md b/changelog.md
index 1fc85a42..000423d0 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,8 +1,20 @@
# Changelog
+## v2.0.16
+- Fullscreen bug fix (fixes #664)
+
+## v2.0.15
+- Demo fix
+
+## v2.0.14
+- CDN URL updates. Sorry, still working on V3 as hard as I can...
+
+## v2.0.13
+- Repo moved and Vimeo demo fix
+
## v2.0.12
-- Ability to set custom `blankUrl` for source changes (https://github.com/Selz/plyr/pull/504)
-- Ability to set caption button listener (https://github.com/Selz/plyr/pull/468)
+- Ability to set custom `blankUrl` for source changes (https://github.com/sampotts/plyr/pull/504)
+- Ability to set caption button listener (https://github.com/sampotts/plyr/pull/468)
## v2.0.11
- Fix for `cleanUp` being called twice (thanks to @sebastiancarlsson)
diff --git a/controls.md b/controls.md
index 36267156..15f52e47 100644
--- a/controls.md
+++ b/controls.md
@@ -37,6 +37,7 @@ You need to add several placeholders to your html template that are replaced whe
- `{id}` - the dynamically generated ID for the player (for form controls)
- `{seektime}` - the seek time specified in options for fast forward and rewind
+- `{title}` - the title of your media, if specified
You can include only the controls you need when specifying custom html.
diff --git a/demo/dist/demo.css b/demo/dist/demo.css
index a9b2f5bc..b1595f07 100644
--- a/demo/dist/demo.css
+++ b/demo/dist/demo.css
@@ -1 +1 @@
-/*! normalize.css v2.1.3 | MIT License | git.io/normalize */a.logo,img,legend{border:0}a,h1,h2{color:#3498db}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,small,summary{display:block}body,figure,li,ul{margin:0}[hidden],template{display:none}li,nav ul,ul{list-style:none;padding:0}legend,li,nav ul,ul{padding:0}.btn__bar,sub,sup{position:relative}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}a{background:0 0;text-decoration:none;border-bottom:1px dotted currentColor;transition:background .3s ease,color .3s ease,border .3s ease}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}hr{box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}.btn__bar,nav li{white-space:nowrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}sub,sup{font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}svg:not(:root){overflow:hidden}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@keyframes fade-in{0%{opacity:0}100%{opacity:1}}@font-face{font-family:Avenir;src:url(//cdn.plyr.io/fonts/avenir-medium.woff2) format("woff2"),url(//cdn.plyr.io/fonts/avenir-medium.woff) format("woff");font-style:normal;font-weight:500}@font-face{font-family:Avenir;src:url(//cdn.plyr.io/fonts/avenir-bold.woff2) format("woff2"),url(//cdn.plyr.io/fonts/avenir-bold.woff) format("woff");font-style:normal;font-weight:700}html{font-size:100%;height:100%;background:fixed #f2f5f7}body{font-family:Avenir,"Helvetica Neue",Helvetica,Arial,sans-serif;line-height:1.5;text-align:center;color:#55646b;font-weight:500;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;padding:10px}h1,h2{letter-spacing:-.025em;margin:0 0 10px;line-height:1.2;font-weight:700}h1{font-size:64px;font-size:4rem}p,small{margin:0 0 20px}small{padding:0 10px;font-size:14px;font-size:.875rem}a:focus,a:hover{color:#343f4a;border-bottom-color:transparent}a:focus{outline:#343f4a dotted thin;outline-offset:1px}.color--vimeo{color:#19b7ed}.color--youtube{color:#cc181e}*,::after,::before{box-sizing:border-box}.btn__bar ul,nav li{display:inline-block}header{padding:20px;margin-bottom:20px}header p{font-size:18px;font-size:1.125rem}section{max-width:1200px;margin:0 auto 20px}@media (min-width:480px){header{padding-top:60px;padding-bottom:60px}section{margin-bottom:40px}}.icon{fill:currentColor;width:18px;height:18px;vertical-align:-3px}.btn,.btn__count,.error main,video{vertical-align:middle}a svg,button svg,label svg{pointer-events:none}.btn .icon,a .icon{margin-right:10px}.btn:not(.btn-large) .icon{width:16px;height:16px}nav ul{margin:0;font-size:0}nav li{margin-top:10px;font-size:16px;font-size:1rem}nav li+li{margin-left:20px}.btn__bar{margin:0 auto 20px;max-width:1200px}.btn__bar::before{content:"";position:absolute;top:50%;left:0;right:0;height:1px;background:#dbe3e8}.btn__bar ul{position:relative;z-index:1;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn__bar li{margin:0}.btn__bar li:first-child .btn{border-radius:4px 0 0 4px}.btn__bar li:last-child .btn{border-radius:0 4px 4px 0}.btn__bar li+li .btn{margin-left:-1px}.btn__bar li.active .btn{position:relative;z-index:1}.btn__bar li.active .btn .icon{color:inherit}.btn__bar li.active+li .btn:hover{z-index:0}.btn__bar .btn{position:relative;display:block;border-radius:0}.btn__bar .btn:focus,.btn__bar .btn:hover{z-index:1}@media (min-width:560px){.btn__bar{margin-bottom:40px}}.btn,.btn__count{display:inline-block;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-weight:700}.btn{padding:10px 12px;background:linear-gradient(#f8fafb,#e9eef1);border:1px solid #cbd0d3;box-shadow:0 1px 1px rgba(0,0,0,.05);text-shadow:0 1px 1px #fff;color:#55646b;transition:background .1s ease,color .1s ease;font-size:14px;font-size:.875rem}.btn:focus,.btn:hover{border-color:#b5bcc0;color:#55646b;outline:0}.btn--large{padding:10px 20px;font-size:16px;font-size:1rem}.btn--primary,.btn__bar li.active .btn{background-image:linear-gradient(#3498db,#258cd1);background-color:#3498db;border-color:#217dbb;box-shadow:0 1px 1px rgba(0,0,0,.15);text-shadow:0 1px 1px rgba(0,0,0,.1);color:#fff}.btn--primary:focus,.btn--primary:hover{color:#fff;border-color:#196090}.btn--youtube .icon{color:#cc181e}.btn--vimeo .icon{color:#19b7ed}.btn--twitter .icon{color:#4BAAF4}.btn__count{position:relative;margin-left:10px;padding:10px 15px;background:#fff;border:1px solid #cbd0d3}.btn__count::before,.plyr__video-wrapper::after{content:"";position:absolute}.btn__count::before{display:block;width:8px;height:8px;left:1px;top:50%;margin-top:-4px;background:inherit;border:inherit;border-width:1px 0 0 1px;transform:rotate(-45deg) translate(-50%,-50%)}.error body,html.error{height:100%}.error body{width:100%;display:table;table-layout:fixed}.error main{display:table-cell;width:100%}video{max-width:100%}.plyr{margin:0 auto;border-radius:6px}.plyr--audio{max-width:520px}.plyr__video-wrapper::after{pointer-events:none;top:0;bottom:0;left:0;right:0;border:1px solid rgba(0,0,0,.15);border-radius:inherit}.plyr__cite{display:none;margin-top:20px}.plyr__cite .icon{margin-right:5px}.plyr--audio~ul .plyr__cite--audio,.plyr--video:not(.plyr--youtube):not(.plyr--vimeo)~ul .plyr__cite--video,.plyr--vimeo~ul .plyr__cite--vimeo,.plyr--youtube~ul .plyr__cite--youtube{display:block} \ No newline at end of file
+/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}a{background:0 0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=search]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@-webkit-keyframes fade-in{0%{opacity:0}100%{opacity:1}}@keyframes fade-in{0%{opacity:0}100%{opacity:1}}@font-face{font-family:Avenir;src:url(//cdn.plyr.io/fonts/avenir-medium.woff2) format("woff2"),url(//cdn.plyr.io/fonts/avenir-medium.woff) format("woff");font-style:normal;font-weight:500}@font-face{font-family:Avenir;src:url(//cdn.plyr.io/fonts/avenir-bold.woff2) format("woff2"),url(//cdn.plyr.io/fonts/avenir-bold.woff) format("woff");font-style:normal;font-weight:700}html{font-size:100%}body{font-family:Avenir,"Helvetica Neue",Helvetica,Arial,sans-serif;line-height:1.5;text-align:center;color:#55646b;font-weight:500;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}h1,h2{letter-spacing:-.025em;color:#3498db;margin:0 0 10px;line-height:1.2;font-weight:700}h1{font-size:64px;font-size:4rem}p,small{margin:0 0 20px}small{display:block;padding:0 10px;font-size:14px;font-size:.875rem}li,ul{list-style:none;margin:0;padding:0}a{text-decoration:none;color:#3498db;border-bottom:1px dotted currentColor;-webkit-transition:background .3s ease,color .3s ease,border .3s ease;transition:background .3s ease,color .3s ease,border .3s ease}a:focus,a:hover{color:#343f4a;border-bottom-color:transparent}a:focus{outline:thin dotted #343f4a;outline-offset:1px}a.logo{border:0}.color--vimeo{color:#19b7ed}.color--youtube{color:#cc181e}*,::after,::before{-webkit-box-sizing:border-box;box-sizing:border-box}[hidden]{display:none}html{height:100%;background:#f2f5f7 fixed}body{margin:0;padding:10px}header{padding:20px;margin-bottom:20px}header p{font-size:18px;font-size:1.125rem}@media (min-width:480px){header{padding-top:60px;padding-bottom:60px}}section{max-width:1200px;margin:0 auto 20px}@media (min-width:480px){section{margin-bottom:40px}}.icon{fill:currentColor;width:18px;height:18px;vertical-align:-3px}a svg,button svg,label svg{pointer-events:none}.btn .icon,a .icon{margin-right:10px}.btn:not(.btn-large) .icon{width:16px;height:16px}nav ul{list-style:none;margin:0;padding:0;font-size:0}nav li{display:inline-block;margin-top:10px;font-size:16px;font-size:1rem;white-space:nowrap}nav li+li{margin-left:20px}.btn__bar{position:relative;margin:0 auto 20px;max-width:1200px;white-space:nowrap}.btn__bar::before{content:"";position:absolute;top:50%;left:0;right:0;height:1px;background:#dbe3e8}.btn__bar ul{position:relative;z-index:1;display:inline-block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn__bar li{margin:0}.btn__bar li:first-child .btn{border-radius:4px 0 0 4px}.btn__bar li:last-child .btn{border-radius:0 4px 4px 0}.btn__bar li+li .btn{margin-left:-1px}.btn__bar li.active .btn{-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.2);box-shadow:inset 0 1px 1px rgba(0,0,0,.2);position:relative;z-index:1}.btn__bar li.active .btn .icon{color:inherit}.btn__bar li.active+li .btn:hover{z-index:0}.btn__bar .btn{position:relative;display:block;border-radius:0}.btn__bar .btn:focus,.btn__bar .btn:hover{z-index:1}@media (min-width:560px){.btn__bar{margin-bottom:40px}}.btn,.btn__count{display:inline-block;vertical-align:middle;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-weight:700}.btn{padding:10px 12px;background:-webkit-gradient(linear,left top,left bottom,from(#f8fafb),to(#e9eef1));background:linear-gradient(#f8fafb,#e9eef1);border:1px solid #cbd0d3;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05);text-shadow:0 1px 1px #fff;color:#55646b;-webkit-transition:background .1s ease,color .1s ease;transition:background .1s ease,color .1s ease;font-size:14px;font-size:.875rem}.btn:focus,.btn:hover{border-color:#b5bcc0;color:#55646b;outline:0}.btn--large{padding:10px 20px;font-size:16px;font-size:1rem}.btn--primary,.btn__bar li.active .btn{background-image:-webkit-gradient(linear,left top,left bottom,from(#3498db),to(#258cd1));background-image:linear-gradient(#3498db,#258cd1);background-color:#3498db;border-color:#217dbb;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.15);box-shadow:0 1px 1px rgba(0,0,0,.15);text-shadow:0 1px 1px rgba(0,0,0,.1);color:#fff}.btn--primary:focus,.btn--primary:hover{color:#fff;border-color:#196090}.btn--youtube .icon{color:#cc181e}.btn--vimeo .icon{color:#19b7ed}.btn--twitter .icon{color:#4baaf4}.btn__count{position:relative;margin-left:10px;padding:10px 15px;background:#fff;border:1px solid #cbd0d3}.btn__count::before{content:"";position:absolute;display:block;width:8px;height:8px;left:1px;top:50%;margin-top:-4px;background:inherit;border:inherit;border-width:1px 0 0 1px;-webkit-transform:rotate(-45deg) translate(-50%,-50%);transform:rotate(-45deg) translate(-50%,-50%)}.error body,html.error{height:100%}.error body{width:100%;display:table;table-layout:fixed}.error main{display:table-cell;width:100%;vertical-align:middle}video{max-width:100%;vertical-align:middle}.plyr{margin:0 auto;border-radius:6px}.plyr--audio{max-width:520px}.plyr__video-wrapper::after{content:"";pointer-events:none;position:absolute;top:0;bottom:0;left:0;right:0;border:1px solid rgba(0,0,0,.15);border-radius:inherit}.plyr__cite{display:none;margin-top:20px}.plyr__cite .icon{margin-right:5px}.plyr--audio~ul .plyr__cite--audio,.plyr--video:not(.plyr--youtube):not(.plyr--vimeo)~ul .plyr__cite--video,.plyr--vimeo~ul .plyr__cite--vimeo,.plyr--youtube~ul .plyr__cite--youtube{display:block} \ No newline at end of file
diff --git a/demo/error.html b/demo/error.html
index c9ba8c36..6dc22cb1 100644
--- a/demo/error.html
+++ b/demo/error.html
@@ -1,18 +1,25 @@
<!doctype html>
<html lang="en" class="error">
- <head>
- <meta charset="utf-8" />
- <title>Doh. Looks like something went wrong.</title>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <!-- Docs styles -->
- <link rel="stylesheet" href="dist/demo.css">
- </head>
- <body>
- <main>
- <h1>Doh.</h1>
- <p>Looks like something went wrong.</p>
- <a href="http://plyr.io" class="btn btn--primary">Back to plyr.io</a>
- </main>
- </body>
-</html>
+<head>
+ <meta charset="utf-8" />
+ <title>Doh. Looks like something went wrong.</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+
+ <!-- Docs styles -->
+ <link rel="stylesheet" href="dist/demo.css">
+
+ <!-- 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">
+</head>
+
+<body>
+ <main>
+ <h1>Doh.</h1>
+ <p>Looks like something went wrong.</p>
+ <a href="http://plyr.io" class="btn btn--primary">Back to plyr.io</a>
+ </main>
+</body>
+
+</html> \ No newline at end of file
diff --git a/demo/index.html b/demo/index.html
index 4482ed7d..b6941537 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -1,88 +1,103 @@
<!doctype html>
<html lang="en">
- <head>
- <meta charset="utf-8" />
- <title>Plyr - A simple HTML5 media player</title>
- <meta name="description" content="A simple HTML5 media player with custom controls and WebVTT captions.">
- <meta name="author" content="Sam Potts">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <!-- Styles -->
- <link rel="stylesheet" href="../dist/plyr.css">
+<head>
+ <meta charset="utf-8" />
+ <title>Plyr - A simple HTML5 media player</title>
+ <meta name="description" content="A simple HTML5 media player with custom controls and WebVTT captions.">
+ <meta name="author" content="Sam Potts">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
- <!-- Docs styles -->
- <link rel="stylesheet" href="dist/demo.css">
- </head>
- <body>
- <header>
- <h1>Plyr</h1>
- <p>A simple, accessible HTML5 media player by <a href="https://twitter.com/sam_potts" target="_blank">@sam_potts</a> from <a href="https://twitter.com/selz" target="_blank">@selz</a></p>
- <nav>
- <ul>
- <li>
- <a href="https://github.com/selz/plyr" target="_blank" class="btn btn--large btn--primary" data-shr-network="github">
- <svg class="icon"><use xlink:href="#icon-github"/></svg>Download on GitHub
- </a>
- </li>
- <li>
- <a href="https://twitter.com/intent/tweet?text=A+simple+HTML5+media+player+with+custom+controls+and+WebVTT+captions.&url=http%3A%2F%2Fplyr.io&via=Sam_Potts" target="_blank" class="btn btn--large btn--twitter" data-shr-network="twitter">
- <svg class="icon"><use xlink:href="#icon-twitter"/></svg>Tweet
- </a>
- </li>
- </ul>
- </nav>
- </header>
+ <!-- Styles -->
+ <link rel="stylesheet" href="../dist/plyr.css">
- <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.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg?v1" controls crossorigin>
- <!-- Video files -->
- <source src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4" type="video/mp4">
- <source src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.webm" type="video/webm">
+ <!-- Docs styles -->
+ <link rel="stylesheet" href="dist/demo.css">
- <!-- Text track file -->
- <track kind="captions" label="English" srclang="en" src="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt" default>
+ <!-- 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">
+</head>
- <!-- Fallback for browsers that don't support the <video> element -->
- <a href="https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4" download>Download</a>
- </video>
+<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>
- <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>
- </ul>
- </section>
- </main>
+ <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>
+ <!-- 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">
- <!-- Plyr core script -->
- <script src="../dist/plyr.js"></script>
+ <!-- Text track file -->
+ <track kind="captions" label="English" srclang="en" src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt"
+ default>
- <!-- Docs script -->
- <script src="dist/demo.js"></script>
+ <!-- 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>
+ </video>
- <!-- Rangetouch to fix <input type="range"> on touch devices (see https://rangetouch.com) -->
- <script src="https://cdn.rangetouch.com/0.0.9/rangetouch.js" async></script>
+ <ul>
+ <li class="plyr__cite plyr__cite--video"><small><a href="http://viewfromabluemoon.com/" target="_blank">View From A Blue Moon</a> &copy; Brainfarm</small></li>
+ <li class="plyr__cite plyr__cite--audio"><small><a href="http://www.kishibashi.com/" target="_blank">Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;</a> &copy; Kishi Bashi</small></li>
+ <li class="plyr__cite plyr__cite--youtube"><small><a href="https://www.youtube.com/watch?v=bTqVqk7FSmY" target="_blank">View From A Blue Moon</a> on <span class="color--youtube"><svg class="icon"><use xlink:href="#icon-youtube"/></svg>YouTube</span></small></li>
+ <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>
+ </ul>
+ </section>
+ </main>
- <!-- Sharing libary (https://shr.one) -->
- <script src="https://cdn.shr.one/0.1.9/shr.js"></script>
- <script>if(window.shr) { window.shr.setup({ count: { classname: 'btn__count' } }); }</script>
- </body>
-</html>
+ <!-- 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>
+
+ <!-- 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>
+</body>
+
+</html> \ No newline at end of file
diff --git a/demo/src/js/main.js b/demo/src/js/main.js
index df0418e3..7d732dcd 100644
--- a/demo/src/js/main.js
+++ b/demo/src/js/main.js
@@ -7,73 +7,73 @@
/*global plyr*/
// General functions
-;(function() {
+(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',
+ debug: true,
+ title: "Video demo",
+ iconUrl: "../dist/plyr.svg",
tooltips: {
- controls: true
+ controls: true
},
captions: {
- defaultActive: true
+ defaultActive: true
}
});
- plyr.loadSprite('dist/demo.svg');
+ plyr.loadSprite("dist/demo.svg");
// Plyr returns an array regardless
var player = instances[0];
// Setup type toggle
- var buttons = document.querySelectorAll('[data-source]'),
+ var buttons = document.querySelectorAll("[data-source]"),
types = {
- video: 'video',
- audio: 'audio',
- youtube: 'youtube',
- vimeo: 'vimeo'
+ video: "video",
+ audio: "audio",
+ youtube: "youtube",
+ vimeo: "vimeo"
},
- currentType = window.location.hash.replace('#', ''),
- historySupport = (window.history && window.history.pushState);
+ 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');
+ buttons[i].addEventListener("click", function() {
+ var type = this.getAttribute("data-source");
newSource(type);
if (historySupport) {
- history.pushState({ 'type': type }, '', '#' + type);
+ history.pushState({ type: type }, "", "#" + type);
}
});
}
// List for backwards/forwards
- window.addEventListener('popstate', function(event) {
- if(event.state && 'type' in event.state) {
+ window.addEventListener("popstate", function(event) {
+ if (event.state && "type" in event.state) {
newSource(event.state.type);
}
});
// On load
- if(historySupport) {
+ if (historySupport) {
var video = !currentType.length;
// If there's no current type set, assume video
- if(video) {
+ if (video) {
currentType = types.video;
}
// Replace current history state
- if(currentType in types) {
- history.replaceState({ 'type': currentType }, '', (video ? '' : '#' + currentType));
+ if (currentType in types) {
+ history.replaceState({ type: currentType }, "", video ? "" : "#" + currentType);
}
// If it's not video, load the source
- if(currentType !== types.video) {
+ if (currentType !== types.video) {
newSource(currentType, true);
}
}
@@ -82,11 +82,10 @@
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 : '');
+ element.classList[state ? "add" : "remove"](className);
+ } else {
+ var name = (" " + element.className + " ").replace(/\s+/g, " ").replace(" " + className + " ", "");
+ element.className = name + (state ? " " + className : "");
}
}
}
@@ -94,68 +93,78 @@
// 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)) {
+ if (!(type in types) || (!init && type === currentType) || (!currentType.length && type === types.video)) {
return;
}
- switch(type) {
+ switch (type) {
case types.video:
player.source({
- type: 'video',
- title: 'View From A Blue Moon',
- sources: [{
- src: 'https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4',
- type: 'video/mp4'
- },
- {
- src: 'https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.webm',
- type: 'video/webm'
- }],
- poster: 'https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg',
- tracks: [{
- kind: 'captions',
- label: 'English',
- srclang:'en',
- src: 'https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt',
- default: true
- }]
+ 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.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3',
- type: 'audio/mp3'
- },
- {
- src: 'https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg',
- type: 'audio/ogg'
- }]
+ 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'
- }]
+ type: "video",
+ title: "View From A Blue Moon",
+ sources: [
+ {
+ src: "bTqVqk7FSmY",
+ type: "youtube"
+ }
+ ]
});
break;
case types.vimeo:
player.source({
- type: 'video',
- title: 'View From A Blue Moon',
- sources: [{
- src: '143418951',
- type: 'vimeo'
- }]
+ type: "video",
+ title: "View From A Blue Moon",
+ sources: [
+ {
+ src: "147865858",
+ type: "vimeo"
+ }
+ ]
});
break;
}
@@ -165,21 +174,30 @@
// Remove active classes
for (var x = buttons.length - 1; x >= 0; x--) {
- toggleClass(buttons[x].parentElement, 'active', false);
+ toggleClass(buttons[x].parentElement, "active", false);
}
// Set active on parent
- toggleClass(document.querySelector('[data-source="'+ type +'"]').parentElement, 'active', true);
+ 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');
+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");
}
diff --git a/demo/src/less/lib/fontface.less b/demo/src/less/lib/fontface.less
index a7da5ad9..cdecc256 100644
--- a/demo/src/less/lib/fontface.less
+++ b/demo/src/less/lib/fontface.less
@@ -4,15 +4,17 @@
@font-face {
font-family: "Avenir";
- src: url("//cdn.plyr.io/fonts/avenir-medium.woff2") format("woff2"),
- url("//cdn.plyr.io/fonts/avenir-medium.woff") format("woff");
- font-style: normal;
- font-weight: @font-weight-base;
+ src: url("//cdn.plyr.io/static/fonts/avenir-medium.woff2") format("woff2"),
+ url("//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("//cdn.plyr.io/fonts/avenir-bold.woff2") format("woff2"),
- url("//cdn.plyr.io/fonts/avenir-bold.woff") format("woff");
- font-style: normal;
- font-weight: @font-weight-bold;
-} \ No newline at end of file
+ src: url("//cdn.plyr.io/static/fonts/avenir-bold.woff2") format("woff2"),
+ url("//cdn.plyr.io/static/fonts/avenir-bold.woff") format("woff");
+ font-style: normal;
+ font-weight: @font-weight-bold;
+ font-display: swap;
+}
diff --git a/dist/plyr.css b/dist/plyr.css
index e92820ce..1ca2a7fd 100644
--- a/dist/plyr.css
+++ b/dist/plyr.css
@@ -1 +1 @@
-.plyr input[type=range]:focus,.plyr:focus{outline:0}.plyr .plyr__video-embed iframe,.plyr__tooltip{pointer-events:none}@keyframes plyr-progress{to{background-position:25px 0}}.plyr{position:relative;max-width:100%;min-width:200px;font-family:Avenir,'Avenir Next','Helvetica Neue','Segoe UI',Helvetica,Arial,sans-serif;direction:ltr}.plyr,.plyr *,.plyr ::after,.plyr ::before{box-sizing:border-box}.plyr a,.plyr button,.plyr input,.plyr label{-ms-touch-action:manipulation;touch-action:manipulation}.plyr audio,.plyr video{width:100%;height:auto;vertical-align:middle;border-radius:inherit}.plyr input[type=range]{display:block;height:20px;width:100%;margin:0;padding:0;vertical-align:middle;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer;border:none;background:0 0}.plyr input[type=range]::-webkit-slider-runnable-track{height:8px;background:0 0;border:0;border-radius:4px;-webkit-user-select:none;user-select:none}.plyr input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;margin-top:-4px;position:relative;height:16px;width:16px;background:#fff;border:2px solid transparent;border-radius:100%;transition:background .2s ease,border .2s ease,transform .2s ease;box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(0,0,0,.15);box-sizing:border-box}.plyr input[type=range]::-moz-range-track{height:8px;background:0 0;border:0;border-radius:4px;-moz-user-select:none;user-select:none}.plyr input[type=range]::-moz-range-thumb{position:relative;height:16px;width:16px;background:#fff;border:2px solid transparent;border-radius:100%;transition:background .2s ease,border .2s ease,transform .2s ease;box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(0,0,0,.15);box-sizing:border-box}.plyr input[type=range]::-ms-track{height:8px;background:0 0;border:0;color:transparent}.plyr input[type=range]::-ms-fill-upper{height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none}.plyr input[type=range]::-ms-fill-lower{height:8px;border:0;border-radius:4px;-ms-user-select:none;user-select:none;background:#3498db}.plyr input[type=range]::-ms-thumb{position:relative;height:16px;width:16px;background:#fff;border:2px solid transparent;border-radius:100%;transition:background .2s ease,border .2s ease,transform .2s ease;box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(0,0,0,.15);box-sizing:border-box;margin-top:0}.plyr input[type=range]::-ms-tooltip{display:none}.plyr input[type=range]::-moz-focus-outer{border:0}.plyr input[type=range].tab-focus:focus{outline-offset:3px}.plyr input[type=range]:active::-webkit-slider-thumb{background:#3498db;border-color:#fff;transform:scale(1.25)}.plyr input[type=range]:active::-moz-range-thumb{background:#3498db;border-color:#fff;transform:scale(1.25)}.plyr input[type=range]:active::-ms-thumb{background:#3498db;border-color:#fff;transform:scale(1.25)}.plyr--video input[type=range].tab-focus:focus{outline:rgba(255,255,255,.5) dotted 1px}.plyr--audio input[type=range].tab-focus:focus{outline:rgba(86,93,100,.5) dotted 1px}.plyr__sr-only{clip:rect(1px,1px,1px,1px);overflow:hidden;position:absolute!important;padding:0!important;border:0!important;height:1px!important;width:1px!important}.plyr__video-wrapper{position:relative;background:#000;border-radius:inherit}.plyr__video-embed{padding-bottom:56.25%;height:0;border-radius:inherit;overflow:hidden;z-index:0}.plyr__video-embed iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.plyr__video-embed>div{position:relative;padding-bottom:200%;transform:translateY(-35.95%)}.plyr video::-webkit-media-text-track-container{display:none}.plyr__captions{display:none;position:absolute;bottom:0;left:0;width:100%;padding:20px;transform:translateY(-40px);transition:transform .3s ease;color:#fff;font-size:16px;text-align:center;font-weight:400}.plyr__captions span{border-radius:2px;padding:3px 10px;background:rgba(0,0,0,.7);-webkit-box-decoration-break:clone;box-decoration-break:clone;line-height:150%}.plyr__captions span:empty{display:none}@media (min-width:768px){.plyr__captions{font-size:24px}}.plyr--captions-active .plyr__captions{display:block}.plyr--hide-controls .plyr__captions{transform:translateY(-15px)}@media (min-width:1024px){.plyr--fullscreen-active .plyr__captions{font-size:32px}}.plyr ::-webkit-media-controls{display:none}.plyr__controls{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;line-height:1;text-align:center}.plyr__controls .plyr__progress,.plyr__controls .plyr__time,.plyr__controls>button{margin-left:5px}.plyr__controls .plyr__progress:first-child,.plyr__controls .plyr__time:first-child,.plyr__controls>button:first-child{margin-left:0}.plyr__controls .plyr__volume{margin-left:5px}.plyr__controls [data-plyr=pause]{margin-left:0}.plyr__controls button{position:relative;display:inline-block;-ms-flex-negative:0;flex-shrink:0;overflow:visible;vertical-align:middle;padding:7px;border:0;background:0 0;border-radius:3px;cursor:pointer;transition:background .3s ease,color .3s ease,opacity .3s ease;color:inherit}.plyr__controls button svg{width:18px;height:18px;display:block;fill:currentColor}.plyr__controls button:focus{outline:0}.plyr__controls .icon--captions-on,.plyr__controls .icon--exit-fullscreen,.plyr__controls .icon--muted{display:none}@media (min-width:480px){.plyr__controls .plyr__progress,.plyr__controls .plyr__time,.plyr__controls>button{margin-left:10px}}.plyr--hide-controls .plyr__controls{opacity:0;pointer-events:none}.plyr--video .plyr__controls{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:50px 10px 10px;background:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.5));border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;color:#fff;transition:opacity .3s ease}.plyr--video .plyr__controls button.tab-focus:focus,.plyr--video .plyr__controls button:hover{background:#3498db;color:#fff}.plyr--audio .plyr__controls{padding:10px;border-radius:inherit;background:#fff;border:1px solid #dbe3e8;color:#565D64}.plyr--audio .plyr__controls button.tab-focus:focus,.plyr--audio .plyr__controls button:hover,.plyr__play-large{background:#3498db;color:#fff}.plyr__play-large{display:none;position:absolute;z-index:1;top:50%;left:50%;transform:translate(-50%,-50%);padding:10px;border:4px solid currentColor;border-radius:100%;box-shadow:0 1px 1px rgba(0,0,0,.15);transition:all .3s ease}.plyr__play-large svg{position:relative;left:2px;width:20px;height:20px;display:block;fill:currentColor}.plyr__play-large:focus{outline:rgba(255,255,255,.5) dotted 1px}.plyr .plyr__play-large{display:inline-block}.plyr--audio .plyr__play-large,.plyr--playing .plyr__controls [data-plyr=play],.plyr__controls [data-plyr=pause]{display:none}.plyr--playing .plyr__play-large{opacity:0;visibility:hidden}.plyr--playing .plyr__controls [data-plyr=pause]{display:inline-block}.plyr--captions-active .plyr__controls .icon--captions-on,.plyr--fullscreen-active .icon--exit-fullscreen,.plyr--muted .plyr__controls .icon--muted{display:block}.plyr [data-plyr=captions],.plyr [data-plyr=fullscreen],.plyr--captions-active .plyr__controls .icon--captions-on+svg,.plyr--fullscreen-active .icon--exit-fullscreen+svg,.plyr--muted .plyr__controls .icon--muted+svg{display:none}.plyr--captions-enabled [data-plyr=captions],.plyr--fullscreen-enabled [data-plyr=fullscreen]{display:inline-block}.plyr__tooltip{position:absolute;z-index:2;bottom:100%;margin-bottom:10px;padding:5px 7.5px;opacity:0;background:rgba(0,0,0,.7);border-radius:3px;color:#fff;font-size:14px;line-height:1.3;transform:translate(-50%,10px) scale(.8);transform-origin:50% 100%;transition:transform .2s .1s ease,opacity .2s .1s ease}.plyr__tooltip::before{content:'';position:absolute;width:0;height:0;left:50%;transform:translateX(-50%);bottom:-4px;border-right:4px solid transparent;border-top:4px solid rgba(0,0,0,.7);border-left:4px solid transparent;z-index:2}.plyr button.tab-focus:focus .plyr__tooltip,.plyr button:hover .plyr__tooltip,.plyr__tooltip--visible{opacity:1;transform:translate(-50%,0) scale(1)}.plyr button:hover .plyr__tooltip{z-index:3}.plyr__controls button:first-child .plyr__tooltip{left:0;transform:translate(0,10px) scale(.8);transform-origin:0 100%}.plyr__controls button:first-child .plyr__tooltip::before{left:16px}.plyr__controls button:last-child .plyr__tooltip{right:0;transform:translate(0,10px) scale(.8);transform-origin:100% 100%}.plyr__controls button:last-child .plyr__tooltip::before{left:auto;right:16px;transform:translateX(50%)}.plyr__controls button:first-child .plyr__tooltip--visible,.plyr__controls button:first-child.tab-focus:focus .plyr__tooltip,.plyr__controls button:first-child:hover .plyr__tooltip,.plyr__controls button:last-child .plyr__tooltip--visible,.plyr__controls button:last-child.tab-focus:focus .plyr__tooltip,.plyr__controls button:last-child:hover .plyr__tooltip{transform:translate(0,0) scale(1)}.plyr__progress{position:relative;display:none;-ms-flex:1;flex:1}.plyr__progress input[type=range]{position:relative;z-index:2}.plyr__progress input[type=range]::-webkit-slider-runnable-track{background:0 0}.plyr__progress input[type=range]::-moz-range-track{background:0 0}.plyr__progress input[type=range]::-ms-fill-upper{background:0 0}.plyr__progress .plyr__tooltip{left:0}.plyr .plyr__progress{display:inline-block}.plyr__progress--buffer,.plyr__progress--played,.plyr__volume--display{position:absolute;left:0;top:50%;width:100%;height:8px;margin:-4px 0 0;padding:0;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;border-radius:100px}.plyr__progress--buffer::-webkit-progress-bar,.plyr__progress--played::-webkit-progress-bar,.plyr__volume--display::-webkit-progress-bar{background:0 0}.plyr__progress--buffer::-webkit-progress-value,.plyr__progress--played::-webkit-progress-value,.plyr__volume--display::-webkit-progress-value{background:currentColor;border-radius:100px;min-width:8px}.plyr__progress--buffer::-moz-progress-bar,.plyr__progress--played::-moz-progress-bar,.plyr__volume--display::-moz-progress-bar{background:currentColor;border-radius:100px;min-width:8px}.plyr__progress--buffer::-ms-fill,.plyr__progress--played::-ms-fill,.plyr__volume--display::-ms-fill{border-radius:100px}.plyr__progress--played,.plyr__volume--display{z-index:1;color:#3498db;background:0 0;transition:none}.plyr__progress--played::-webkit-progress-value,.plyr__volume--display::-webkit-progress-value{min-width:8px;max-width:99%;border-top-right-radius:0;border-bottom-right-radius:0;transition:none}.plyr__progress--played::-moz-progress-bar,.plyr__volume--display::-moz-progress-bar{min-width:8px;max-width:99%;border-top-right-radius:0;border-bottom-right-radius:0;transition:none}.plyr__progress--played::-ms-fill,.plyr__volume--display::-ms-fill{display:none}.plyr__progress--buffer::-webkit-progress-value{transition:width .2s ease}.plyr__progress--buffer::-moz-progress-bar{transition:width .2s ease}.plyr__progress--buffer::-ms-fill{transition:width .2s ease}.plyr--video .plyr__progress--buffer,.plyr--video .plyr__volume--display{background:rgba(255,255,255,.25)}.plyr--video .plyr__progress--buffer{color:rgba(255,255,255,.25)}.plyr--audio .plyr__progress--buffer,.plyr--audio .plyr__volume--display{background:rgba(198,214,219,.66)}.plyr--audio .plyr__progress--buffer{color:rgba(198,214,219,.66)}.plyr--loading .plyr__progress--buffer{animation:plyr-progress 1s linear infinite;background-size:25px 25px;background-repeat:repeat-x;background-image:linear-gradient(-45deg,rgba(0,0,0,.15) 25%,transparent 25%,transparent 50%,rgba(0,0,0,.15) 50%,rgba(0,0,0,.15) 75%,transparent 75%,transparent);color:transparent}.plyr--video.plyr--loading .plyr__progress--buffer{background-color:rgba(255,255,255,.25)}.plyr--audio.plyr--loading .plyr__progress--buffer{background-color:rgba(198,214,219,.66)}.plyr__time{display:inline-block;vertical-align:middle;font-size:14px}.plyr__time+.plyr__time{display:none}@media (min-width:768px){.plyr__time+.plyr__time{display:inline-block}}.plyr__time+.plyr__time::before{content:'\2044';margin-right:10px}.plyr__volume{display:none}.plyr .plyr__volume{-ms-flex:1;flex:1;position:relative}.plyr .plyr__volume input[type=range]{position:relative;z-index:2}@media (min-width:480px){.plyr .plyr__volume{display:block;max-width:60px}}@media (min-width:768px){.plyr .plyr__volume{max-width:100px}}.plyr--is-ios .plyr__volume,.plyr--is-ios [data-plyr=mute]{display:none!important}.plyr--fullscreen-active{position:fixed;top:0;left:0;right:0;bottom:0;height:100%;width:100%;z-index:10000000;background:#000;border-radius:0!important}.plyr--fullscreen-active video{height:100%}.plyr--fullscreen-active .plyr__video-wrapper{height:100%;width:100%}.plyr--fullscreen-active .plyr__video-embed{overflow:visible}.plyr--fullscreen-active .plyr__controls{position:absolute;bottom:0;left:0;right:0}.plyr--fullscreen-active.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)} \ No newline at end of file
+@-webkit-keyframes plyr-progress{to{background-position:25px 0}}@keyframes plyr-progress{to{background-position:25px 0}}.plyr{position:relative;max-width:100%;min-width:200px;font-family:Avenir,'Avenir Next','Helvetica Neue','Segoe UI',Helvetica,Arial,sans-serif;direction:ltr}.plyr,.plyr *,.plyr ::after,.plyr ::before{-webkit-box-sizing:border-box;box-sizing:border-box}.plyr a,.plyr button,.plyr input,.plyr label{-ms-touch-action:manipulation;touch-action:manipulation}.plyr:focus{outline:0}.plyr audio,.plyr video{width:100%;height:auto;vertical-align:middle;border-radius:inherit}.plyr input[type=range]{display:block;height:20px;width:100%;margin:0;padding:0;vertical-align:middle;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer;border:none;background:0 0}.plyr input[type=range]::-webkit-slider-runnable-track{height:8px;background:0 0;border:0;border-radius:4px;-webkit-user-select:none;user-select:none}.plyr input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;margin-top:-4px;position:relative;height:16px;width:16px;background:#fff;border:2px solid transparent;border-radius:100%;-webkit-transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease,-webkit-transform .2s ease;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(0,0,0,.15);box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(0,0,0,.15);-webkit-box-sizing:border-box;box-sizing:border-box}.plyr input[type=range]::-moz-range-track{height:8px;background:0 0;border:0;border-radius:4px;-moz-user-select:none;user-select:none}.plyr input[type=range]::-moz-range-thumb{position:relative;height:16px;width:16px;background:#fff;border:2px solid transparent;border-radius:100%;-webkit-transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease,-webkit-transform .2s ease;box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(0,0,0,.15);box-sizing:border-box}.plyr input[type=range]::-ms-track{height:8px;background:0 0;border:0;color:transparent}.plyr input[type=range]::-ms-fill-upper{height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none}.plyr input[type=range]::-ms-fill-lower{height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none;background:#3498db}.plyr input[type=range]::-ms-thumb{position:relative;height:16px;width:16px;background:#fff;border:2px solid transparent;border-radius:100%;-webkit-transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,-webkit-transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease;transition:background .2s ease,border .2s ease,transform .2s ease,-webkit-transform .2s ease;box-shadow:0 1px 1px rgba(0,0,0,.15),0 0 0 1px rgba(0,0,0,.15);box-sizing:border-box;margin-top:0}.plyr input[type=range]::-ms-tooltip{display:none}.plyr input[type=range]:focus{outline:0}.plyr input[type=range]::-moz-focus-outer{border:0}.plyr input[type=range].tab-focus:focus{outline-offset:3px}.plyr input[type=range]:active::-webkit-slider-thumb{background:#3498db;border-color:#fff;-webkit-transform:scale(1.25);transform:scale(1.25)}.plyr input[type=range]:active::-moz-range-thumb{background:#3498db;border-color:#fff;transform:scale(1.25)}.plyr input[type=range]:active::-ms-thumb{background:#3498db;border-color:#fff;transform:scale(1.25)}.plyr--video input[type=range].tab-focus:focus{outline:1px dotted rgba(255,255,255,.5)}.plyr--audio input[type=range].tab-focus:focus{outline:1px dotted rgba(86,93,100,.5)}.plyr__sr-only{clip:rect(1px,1px,1px,1px);overflow:hidden;position:absolute!important;padding:0!important;border:0!important;height:1px!important;width:1px!important}.plyr__video-wrapper{position:relative;background:#000;border-radius:inherit}.plyr__video-embed{padding-bottom:56.25%;height:0;border-radius:inherit;overflow:hidden;z-index:0}.plyr__video-embed iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.plyr__video-embed>div{position:relative;padding-bottom:200%;-webkit-transform:translateY(-35.95%);transform:translateY(-35.95%)}.plyr .plyr__video-embed iframe{pointer-events:none}.plyr video::-webkit-media-text-track-container{display:none}.plyr__captions{display:none;position:absolute;bottom:0;left:0;width:100%;padding:20px;-webkit-transform:translateY(-40px);transform:translateY(-40px);-webkit-transition:-webkit-transform .3s ease;transition:-webkit-transform .3s ease;transition:transform .3s ease;transition:transform .3s ease,-webkit-transform .3s ease;color:#fff;font-size:16px;text-align:center;font-weight:400}.plyr__captions span{border-radius:2px;padding:3px 10px;background:rgba(0,0,0,.7);-webkit-box-decoration-break:clone;box-decoration-break:clone;line-height:150%}.plyr__captions span:empty{display:none}@media (min-width:768px){.plyr__captions{font-size:24px}}.plyr--captions-active .plyr__captions{display:block}.plyr--hide-controls .plyr__captions{-webkit-transform:translateY(-15px);transform:translateY(-15px)}@media (min-width:1024px){.plyr--fullscreen-active .plyr__captions{font-size:32px}}.plyr ::-webkit-media-controls{display:none}.plyr__controls{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;line-height:1;text-align:center}.plyr__controls .plyr__progress,.plyr__controls .plyr__time,.plyr__controls>button{margin-left:5px}.plyr__controls .plyr__progress:first-child,.plyr__controls .plyr__time:first-child,.plyr__controls>button:first-child{margin-left:0}.plyr__controls .plyr__volume{margin-left:5px}.plyr__controls [data-plyr=pause]{margin-left:0}.plyr__controls button{position:relative;display:inline-block;-ms-flex-negative:0;flex-shrink:0;overflow:visible;vertical-align:middle;padding:7px;border:0;background:0 0;border-radius:3px;cursor:pointer;-webkit-transition:background .3s ease,color .3s ease,opacity .3s ease;transition:background .3s ease,color .3s ease,opacity .3s ease;color:inherit}.plyr__controls button svg{width:18px;height:18px;display:block;fill:currentColor}.plyr__controls button:focus{outline:0}.plyr__controls .icon--captions-on,.plyr__controls .icon--exit-fullscreen,.plyr__controls .icon--muted{display:none}@media (min-width:480px){.plyr__controls .plyr__progress,.plyr__controls .plyr__time,.plyr__controls>button{margin-left:10px}}.plyr--hide-controls .plyr__controls{opacity:0;pointer-events:none}.plyr--video .plyr__controls{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:50px 10px 10px;background:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0)),to(rgba(0,0,0,.5)));background:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.5));border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;color:#fff;-webkit-transition:opacity .3s ease;transition:opacity .3s ease}.plyr--video .plyr__controls button.tab-focus:focus,.plyr--video .plyr__controls button:hover{background:#3498db;color:#fff}.plyr--audio .plyr__controls{padding:10px;border-radius:inherit;background:#fff;border:1px solid #dbe3e8;color:#565d64}.plyr--audio .plyr__controls button.tab-focus:focus,.plyr--audio .plyr__controls button:hover{background:#3498db;color:#fff}.plyr__play-large{display:none;position:absolute;z-index:1;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);padding:10px;background:#3498db;border:4px solid currentColor;border-radius:100%;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.15);box-shadow:0 1px 1px rgba(0,0,0,.15);color:#fff;-webkit-transition:all .3s ease;transition:all .3s ease}.plyr__play-large svg{position:relative;left:2px;width:20px;height:20px;display:block;fill:currentColor}.plyr__play-large:focus{outline:1px dotted rgba(255,255,255,.5)}.plyr .plyr__play-large{display:inline-block}.plyr--audio .plyr__play-large{display:none}.plyr--playing .plyr__play-large{opacity:0;visibility:hidden}.plyr--playing .plyr__controls [data-plyr=play],.plyr__controls [data-plyr=pause]{display:none}.plyr--playing .plyr__controls [data-plyr=pause]{display:inline-block}.plyr--captions-active .plyr__controls .icon--captions-on,.plyr--fullscreen-active .icon--exit-fullscreen,.plyr--muted .plyr__controls .icon--muted{display:block}.plyr--captions-active .plyr__controls .icon--captions-on+svg,.plyr--fullscreen-active .icon--exit-fullscreen+svg,.plyr--muted .plyr__controls .icon--muted+svg{display:none}.plyr [data-plyr=captions],.plyr [data-plyr=fullscreen]{display:none}.plyr--captions-enabled [data-plyr=captions],.plyr--fullscreen-enabled [data-plyr=fullscreen]{display:inline-block}.plyr__tooltip{position:absolute;z-index:2;bottom:100%;margin-bottom:10px;padding:5px 7.5px;pointer-events:none;opacity:0;background:rgba(0,0,0,.7);border-radius:3px;color:#fff;font-size:14px;line-height:1.3;-webkit-transform:translate(-50%,10px) scale(.8);transform:translate(-50%,10px) scale(.8);-webkit-transform-origin:50% 100%;transform-origin:50% 100%;-webkit-transition:opacity .2s .1s ease,-webkit-transform .2s .1s ease;transition:opacity .2s .1s ease,-webkit-transform .2s .1s ease;transition:transform .2s .1s ease,opacity .2s .1s ease;transition:transform .2s .1s ease,opacity .2s .1s ease,-webkit-transform .2s .1s ease}.plyr__tooltip::before{content:'';position:absolute;width:0;height:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);bottom:-4px;border-right:4px solid transparent;border-top:4px solid rgba(0,0,0,.7);border-left:4px solid transparent;z-index:2}.plyr button.tab-focus:focus .plyr__tooltip,.plyr button:hover .plyr__tooltip,.plyr__tooltip--visible{opacity:1;-webkit-transform:translate(-50%,0) scale(1);transform:translate(-50%,0) scale(1)}.plyr button:hover .plyr__tooltip{z-index:3}.plyr__controls button:first-child .plyr__tooltip{left:0;-webkit-transform:translate(0,10px) scale(.8);transform:translate(0,10px) scale(.8);-webkit-transform-origin:0 100%;transform-origin:0 100%}.plyr__controls button:first-child .plyr__tooltip::before{left:16px}.plyr__controls button:last-child .plyr__tooltip{right:0;-webkit-transform:translate(0,10px) scale(.8);transform:translate(0,10px) scale(.8);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.plyr__controls button:last-child .plyr__tooltip::before{left:auto;right:16px;-webkit-transform:translateX(50%);transform:translateX(50%)}.plyr__controls button:first-child .plyr__tooltip--visible,.plyr__controls button:first-child.tab-focus:focus .plyr__tooltip,.plyr__controls button:first-child:hover .plyr__tooltip,.plyr__controls button:last-child .plyr__tooltip--visible,.plyr__controls button:last-child.tab-focus:focus .plyr__tooltip,.plyr__controls button:last-child:hover .plyr__tooltip{-webkit-transform:translate(0,0) scale(1);transform:translate(0,0) scale(1)}.plyr__progress{position:relative;display:none;-webkit-box-flex:1;-ms-flex:1;flex:1}.plyr__progress input[type=range]{position:relative;z-index:2}.plyr__progress input[type=range]::-webkit-slider-runnable-track{background:0 0}.plyr__progress input[type=range]::-moz-range-track{background:0 0}.plyr__progress input[type=range]::-ms-fill-upper{background:0 0}.plyr__progress .plyr__tooltip{left:0}.plyr .plyr__progress{display:inline-block}.plyr__progress--buffer,.plyr__progress--played,.plyr__volume--display{position:absolute;left:0;top:50%;width:100%;height:8px;margin:-4px 0 0;padding:0;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;border-radius:100px}.plyr__progress--buffer::-webkit-progress-bar,.plyr__progress--played::-webkit-progress-bar,.plyr__volume--display::-webkit-progress-bar{background:0 0}.plyr__progress--buffer::-webkit-progress-value,.plyr__progress--played::-webkit-progress-value,.plyr__volume--display::-webkit-progress-value{background:currentColor;border-radius:100px;min-width:8px}.plyr__progress--buffer::-moz-progress-bar,.plyr__progress--played::-moz-progress-bar,.plyr__volume--display::-moz-progress-bar{background:currentColor;border-radius:100px;min-width:8px}.plyr__progress--buffer::-ms-fill,.plyr__progress--played::-ms-fill,.plyr__volume--display::-ms-fill{border-radius:100px}.plyr__progress--played,.plyr__volume--display{z-index:1;color:#3498db;background:0 0;-webkit-transition:none;transition:none}.plyr__progress--played::-webkit-progress-value,.plyr__volume--display::-webkit-progress-value{min-width:8px;max-width:99%;border-top-right-radius:0;border-bottom-right-radius:0;-webkit-transition:none;transition:none}.plyr__progress--played::-moz-progress-bar,.plyr__volume--display::-moz-progress-bar{min-width:8px;max-width:99%;border-top-right-radius:0;border-bottom-right-radius:0;-webkit-transition:none;transition:none}.plyr__progress--played::-ms-fill,.plyr__volume--display::-ms-fill{display:none}.plyr__progress--buffer::-webkit-progress-value{-webkit-transition:width .2s ease;transition:width .2s ease}.plyr__progress--buffer::-moz-progress-bar{-webkit-transition:width .2s ease;transition:width .2s ease}.plyr__progress--buffer::-ms-fill{-webkit-transition:width .2s ease;transition:width .2s ease}.plyr--video .plyr__progress--buffer,.plyr--video .plyr__volume--display{background:rgba(255,255,255,.25)}.plyr--video .plyr__progress--buffer{color:rgba(255,255,255,.25)}.plyr--audio .plyr__progress--buffer,.plyr--audio .plyr__volume--display{background:rgba(198,214,219,.66)}.plyr--audio .plyr__progress--buffer{color:rgba(198,214,219,.66)}.plyr--loading .plyr__progress--buffer{-webkit-animation:plyr-progress 1s linear infinite;animation:plyr-progress 1s linear infinite;background-size:25px 25px;background-repeat:repeat-x;background-image:linear-gradient(-45deg,rgba(0,0,0,.15) 25%,transparent 25%,transparent 50%,rgba(0,0,0,.15) 50%,rgba(0,0,0,.15) 75%,transparent 75%,transparent);color:transparent}.plyr--video.plyr--loading .plyr__progress--buffer{background-color:rgba(255,255,255,.25)}.plyr--audio.plyr--loading .plyr__progress--buffer{background-color:rgba(198,214,219,.66)}.plyr__time{display:inline-block;vertical-align:middle;font-size:14px}.plyr__time+.plyr__time{display:none}@media (min-width:768px){.plyr__time+.plyr__time{display:inline-block}}.plyr__time+.plyr__time::before{content:'\2044';margin-right:10px}.plyr__volume{display:none}.plyr .plyr__volume{-webkit-box-flex:1;-ms-flex:1;flex:1;position:relative}.plyr .plyr__volume input[type=range]{position:relative;z-index:2}@media (min-width:480px){.plyr .plyr__volume{display:block;max-width:60px}}@media (min-width:768px){.plyr .plyr__volume{max-width:100px}}.plyr--is-ios .plyr__volume,.plyr--is-ios [data-plyr=mute]{display:none!important}.plyr--fullscreen-active{position:fixed;top:0;left:0;right:0;bottom:0;height:100%;width:100%;z-index:10000000;background:#000;border-radius:0!important}.plyr--fullscreen-active video{height:100%}.plyr--fullscreen-active .plyr__video-wrapper{height:100%;width:100%}.plyr--fullscreen-active .plyr__video-embed{overflow:visible}.plyr--fullscreen-active .plyr__controls{position:absolute;bottom:0;left:0;right:0}.plyr--fullscreen-active.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)} \ No newline at end of file
diff --git a/gulpfile.js b/gulpfile.js
index 923483e5..26b97238 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -77,20 +77,20 @@ function loadJSON(path) {
// 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
+ var src = require('stream').Readable({
+ objectMode: true
});
src._read = function () {
- this.push(new gutil.File({
- cwd: "",
- base: "",
- path: filename,
+ 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);
}
diff --git a/license.md b/license.md
index 8531b2bb..2c19ae73 100644
--- a/license.md
+++ b/license.md
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2015 Selz.com
+Copyright (c) 2017 Sam Potts
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/package.json b/package.json
index 3fe071de..8a4d95d9 100644
--- a/package.json
+++ b/package.json
@@ -1,51 +1,43 @@
{
- "name": "plyr",
- "version": "2.0.12",
- "description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
- "homepage": "http://plyr.io",
- "main": "src/js/plyr.js",
- "dependencies": {},
- "devDependencies": {
- "gulp": "^3.9.1",
- "gulp-autoprefixer": "^3.1.0",
- "gulp-clean-css": "^2.0.6",
- "gulp-concat": "^2.3.3",
- "gulp-less": "^3.0.5",
- "gulp-open": "^2.0.0",
- "gulp-rename": "^1.2.0",
- "gulp-replace": "^0.5.3",
- "gulp-s3": "^0.3.0",
- "gulp-sass": "^2.3.1",
- "gulp-size": "^2.1.0",
- "gulp-svgmin": "^1.2.2",
- "gulp-svgstore": "^5.0.5",
- "gulp-uglify": "^1.5.3",
- "gulp-util": "^3.0.7",
- "run-sequence": "^1.1.5",
- "through2": "^2.0.1"
- },
- "keywords": [
- "HTML5 Video",
- "HTML5 Audio",
- "Media Player",
- "DASH",
- "Shaka",
- "WordPress",
- "HLS"
- ],
- "repository": {
- "type": "git",
- "url": "git://github.com/selz/plyr.git"
- },
- "license": "MIT",
- "bugs": {
- "url": "https://github.com/selz/plyr/issues"
- },
- "directories": {
- "doc": "readme.md"
- },
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "author": "Sam Potts <sam@selz.com>"
+ "name": "plyr",
+ "version": "2.0.16",
+ "description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
+ "homepage": "http://plyr.io",
+ "main": "src/js/plyr.js",
+ "dependencies": {},
+ "devDependencies": {
+ "gulp": "^3.9.1",
+ "gulp-autoprefixer": "^3.1.0",
+ "gulp-clean-css": "^2.0.6",
+ "gulp-concat": "^2.3.3",
+ "gulp-less": "^3.0.5",
+ "gulp-open": "^2.0.0",
+ "gulp-rename": "^1.2.0",
+ "gulp-replace": "^0.5.3",
+ "gulp-s3": "^0.3.0",
+ "gulp-sass": "^2.3.1",
+ "gulp-size": "^2.1.0",
+ "gulp-svgmin": "^1.2.2",
+ "gulp-svgstore": "^5.0.5",
+ "gulp-uglify": "^1.5.3",
+ "gulp-util": "^3.0.7",
+ "run-sequence": "^1.1.5",
+ "through2": "^2.0.1"
+ },
+ "keywords": ["HTML5 Video", "HTML5 Audio", "Media Player", "DASH", "Shaka", "WordPress", "HLS"],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/sampotts/plyr.git"
+ },
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/sampotts/plyr/issues"
+ },
+ "directories": {
+ "doc": "readme.md"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "Sam Potts <sam@potts.es>"
}
diff --git a/readme.md b/readme.md
index 6110b57a..6acf8c3f 100644
--- a/readme.md
+++ b/readme.md
@@ -5,7 +5,7 @@ A simple, accessible and customizable HTML5, YouTube and Vimeo media player.
[Checkout the demo](https://plyr.io)
-[![Image of Plyr](https://cdn.selz.com/plyr/plyr_v1.8.9.png)](https://plyr.io)
+[![Image of Plyr](https://cdn.plyr.io/static/demo/screenshot.png)](https://plyr.io)
## Why?
We wanted a lightweight, accessible and customizable media player that supports [*modern*](#browser-support) browsers. Sure, there are many other players out there but we wanted to keep things simple, using the right elements for the job.
@@ -34,12 +34,12 @@ Check out the [changelog](changelog.md) to see what's new with Plyr.
## Features currently being developed
- Playback speed selection
-- Quality selection
+- Quality selection
- Caption language selection
- AirPlay
- Picture in Picture (MacOS Sierra + Safari)
-[more info](https://github.com/Selz/plyr/issues?q=is%3Aissue+is%3Aopen+label%3A%22In+Development%22)
+[more info](https://github.com/sampotts/plyr/issues?q=is%3Aissue+is%3Aopen+label%3A%22In+Development%22)
## Planned features
- Playlists
@@ -48,9 +48,9 @@ Check out the [changelog](changelog.md) to see what's new with Plyr.
- Wistia video support
- YouTube and Vimeo audio support
- Audio captions
-...and whatever else has been raised in [issues](https://github.com/Selz/plyr/issues)
+...and whatever else has been raised in [issues](https://github.com/sampotts/plyr/issues)
-If you have any cool ideas or features, please let me know by [creating an issue](https://github.com/Selz/plyr/issues/new) or, of course, forking and sending a pull request.
+If you have any cool ideas or features, please let me know by [creating an issue](https://github.com/sampotts/plyr/issues/new) or, of course, forking and sending a pull request.
## CMS plugins
@@ -126,7 +126,7 @@ Note: `data-video-id` value can now be the ID or URL for the video. This attribu
```
Note: `data-video-id` value can now be the ID or URL for the video. This attribute name will change in a future release to reflect this change.
-### JavaScript
+### JavaScript
Include the `plyr.js` script before the closing `</body>` tag and then call `plyr.setup()`. More info on `setup()` can be found under [initialising](#initialising).
```html
@@ -137,7 +137,7 @@ Include the `plyr.js` script before the closing `</body>` tag and then call `ply
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript, you can use the following:
```html
-<script src="https://cdn.plyr.io/2.0.12/plyr.js"></script>
+<script src="https://cdn.plyr.io/2.0.16/plyr.js"></script>
```
### CSS
@@ -150,16 +150,16 @@ Include the `plyr.css` stylsheet into your `<head>`
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
```html
-<link rel="stylesheet" href="https://cdn.plyr.io/2.0.12/plyr.css">
+<link rel="stylesheet" href="https://cdn.plyr.io/2.0.16/plyr.css">
```
### SVG Sprite
-The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/2.0.12/plyr.svg`.
+The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/2.0.16/plyr.svg`.
## Advanced
### LESS & SASS/SCSS
-You can use `plyr.less` or `plyr.scss` file included in `/src` as part of your build and change variables to suit your design. The LESS and SASS require you to use the [autoprefixer](https://www.npmjs.com/package/gulp-autoprefixer) plugin (you should already) as all declerations use the W3C definitions - e.g. `appearance: none;` will be prefixed to `-webkit-appearance: none;` by autoprefixer.
+You can use `plyr.less` or `plyr.scss` file included in `/src` as part of your build and change variables to suit your design. The LESS and SASS require you to use the [autoprefixer](https://www.npmjs.com/package/gulp-autoprefixer) plugin (you should already) as all declerations use the W3C definitions - e.g. `appearance: none;` will be prefixed to `-webkit-appearance: none;` by autoprefixer.
The HTML markup uses the BEM methodology with `plyr` as the block, e.g. `.plyr__controls`. You can change the class hooks in the options to match any custom CSS you write. Check out the JavaScript source for more on this.
@@ -167,7 +167,7 @@ The HTML markup uses the BEM methodology with `plyr` as the block, e.g. `.plyr__
The icons used in the Plyr controls are loaded in an SVG sprite. The sprite is automatically loaded from our CDN by default. If you already have an icon build system in place, you can include the source plyr icons (see `/src/sprite` for source icons).
#### Using the `iconUrl` option
-You can however specify your own `iconUrl` option and Plyr will determine if the url is absolute and requires loading by AJAX/CORS due to current browser limitations or if it's a relative path, just use the path directly.
+You can however specify your own `iconUrl` option and Plyr will determine if the url is absolute and requires loading by AJAX/CORS due to current browser limitations or if it's a relative path, just use the path directly.
If you're using the `<base>` tag on your site, you may need to use something like this:
[svgfixer.js](https://gist.github.com/leonderijke/c5cf7c5b2e424c0061d2)
@@ -213,7 +213,7 @@ Passing a [string selector](https://developer.mozilla.org/en-US/docs/Web/API/Doc
plyr.setup('.js-player', options);
```
-The NodeList, HTMLElement or string selector can be the target `<video>`, `<audio>` or `[data-type]` (for embeds) element itself or a container element.
+The NodeList, HTMLElement or string selector can be the target `<video>`, `<audio>` or `[data-type]` (for embeds) element itself or a container element.
Passing just the options object:
```javascript
@@ -223,7 +223,7 @@ plyr.setup(options);
`setup()` will return an array of *instances* that can be used with the [API](#api) methods. See the [API](#api) section for more info.
#### RangeTouch
-Some touch browsers (particularly Mobile Safari on iOS) seem to have issues with `<input type="range">` elements whereby touching the track to set the value doesn't work and sliding the thumb can be tricky. To combat this, I've created [RangeTouch](https://rangetouch.com) which I'd recommend including in your solution. It's a tiny script with a nice benefit for users on touch devices.
+Some touch browsers (particularly Mobile Safari on iOS) seem to have issues with `<input type="range">` elements whereby touching the track to set the value doesn't work and sliding the thumb can be tricky. To combat this, I've created [RangeTouch](https://rangetouch.com) which I'd recommend including in your solution. It's a tiny script with a nice benefit for users on touch devices.
#### Options
Options must be passed as an object to the `setup()` method as above or as JSON in `data-plyr` attribute on each of your target elements:
@@ -290,7 +290,7 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke
<td><code>blankUrl</code></td>
<td>String</td>
<td><code>https://cdn.selz.com/plyr/blank.mp4</code></td>
- <td>Specify a URL or path to a blank video file used to properly cancel network requests. See <a href="https://github.com/Selz/plyr/issues/174">issue #174</a> for more info.</td>
+ <td>Specify a URL or path to a blank video file used to properly cancel network requests. See <a href="https://github.com/sampotts/plyr/issues/174">issue #174</a> for more info.</td>
</tr>
<tr>
<td><code>debug</code></td>
@@ -456,7 +456,7 @@ This will return an array of all instances that were setup. Another way is to us
var players = plyr.get('.js-player');
```
-If no argument is passed, it will find all instances in the current document. This will return an array of all instances that were found in the given selector.
+If no argument is passed, it will find all instances in the current document. This will return an array of all instances that were found in the given selector.
A final option is to access the instance through the event handlers:
@@ -904,21 +904,19 @@ These events also bubble up the DOM. The event target will be the container elem
Details borrowed from: [https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events)
## Embeds
-YouTube and Vimeo are currently supported and function much like a HTML5 video. Check the relevant documentation sections for any differences.
-
-Plyr references a custom version of the Vimeo Froogaloop API as Vimeo have neglected to maintain the library and there were bugs with their version. You don't need to worry about including your own versions of the Vimeo or YouTube JavaScript APIs.
+YouTube and Vimeo are currently supported and function much like a HTML5 video. Check the relevant documentation sections for any differences. You don't need to worry about including your own versions of the Vimeo or YouTube JavaScript APIs. Plyr will automatically include them.
-The embed third party API's can be accessed through the `getEmbed()` API method.
+The embed third party API's can be accessed through the `getEmbed()` API method.
More info on the respective API's here:
- [YouTube API Reference](https://developers.google.com/youtube/js_api_reference)
-- [Vimeo API Reference](https://developer.vimeo.com/player/js-api#reference)
+- [Vimeo API Reference](https://github.com/vimeo/player.js)
*Please note*: not all API methods may work 100%. Your mileage may vary. It's better to use the universal plyr API where possible.
## Shortcuts
-By default, a player will bind the following keyboard shortcuts when it has focus. If you have the `global` option to `true` and there's only one player in the document then the shortcuts will work when any element has focus, apart from an element that requires input.
+By default, a player will bind the following keyboard shortcuts when it has focus. If you have the `global` option to `true` and there's only one player in the document then the shortcuts will work when any element has focus, apart from an element that requires input.
<table class="table" width="100%">
<thead>
@@ -933,7 +931,7 @@ By default, a player will bind the following keyboard shortcuts when it has focu
<td><code>0</code> to <code>9</code></td>
<td>✔</td>
<td>Seek from 0 to 90% respectively</td>
- </tr>
+ </tr>
<tr>
<td><code>space</code></td>
<td></td>
@@ -982,7 +980,7 @@ By default, a player will bind the following keyboard shortcuts when it has focu
</tbody>
</table>
-## Streaming
+## Streaming
Because Plyr is an extension of the standard HTML5 video and audio elements, third party streaming plugins can be used with Plyr. Massive thanks to Matias Russitto ([@russitto](https://github.com/russitto)) for working on this. Here's a few examples:
- Using [hls.js](https://github.com/dailymotion/hls.js) - [Demo](http://codepen.io/sampotts/pen/JKEMqB)
@@ -990,7 +988,7 @@ Because Plyr is an extension of the standard HTML5 video and audio elements, thi
- Using [dash.js](https://github.com/Dash-Industry-Forum/dash.js) - [Demo](http://codepen.io/sampotts/pen/BzpJXN)
## Fullscreen
-Fullscreen in Plyr is supported by all browsers that [currently support it](http://caniuse.com/#feat=fullscreen).
+Fullscreen in Plyr is supported by all browsers that [currently support it](http://caniuse.com/#feat=fullscreen).
## Browser support
@@ -1039,7 +1037,7 @@ There's an API method for checking support. You can call `plyr.supported()` and
If you find anything weird with Plyr, please let us know using the GitHub issues tracker.
## Author
-Plyr is developed by [@sam_potts](https://twitter.com/sam_potts) / [sampotts.me](http://sampotts.me) with help from the awesome [contributors](https://github.com/Selz/plyr/graphs/contributors)
+Plyr is developed by [@sam_potts](https://twitter.com/sam_potts) / [sampotts.me](http://sampotts.me) with help from the awesome [contributors](https://github.com/sampotts/plyr/graphs/contributors)
## Donate
Plyr costs money to run, not my time - I donate that for free but domains, hosting and more. Any help is appreciated...
@@ -1082,7 +1080,7 @@ Also these links helped created Plyr:
## Thanks
[![Fastly](https://www.fastly.com/sites/all/themes/custom/fastly2016/logo.png)](https://www.fastly.com/)
-Thanks to [Fastly](https://www.fastly.com/) for providing the CDN services.
+Thanks to [Fastly](https://www.fastly.com/) for providing the CDN services.
## Copyright and License
[The MIT license](license.md).
diff --git a/src/js/plyr.js b/src/js/plyr.js
index 1bea40f9..6fee2bf0 100644
--- a/src/js/plyr.js
+++ b/src/js/plyr.js
@@ -1,192 +1,214 @@
-// ==========================================================================
+// ==========================================================================
// Plyr
-// plyr.js v2.0.12
-// https://github.com/selz/plyr
+// plyr.js v2.0.16
+// https://github.com/sampotts/plyr
// License: The MIT License (MIT)
// ==========================================================================
// Credits: http://paypal.github.io/accessible-html5-video-player/
// ==========================================================================
-;(function(root, factory) {
- 'use strict';
+(function(root, factory) {
+ "use strict";
/*global define,module*/
- if (typeof module === 'object' && typeof module.exports === 'object') {
+ if (typeof module === "object" && typeof module.exports === "object") {
// Node, CommonJS-like
module.exports = factory(root, document);
- } else if (typeof define === 'function' && define.amd) {
+ } else if (typeof define === "function" && define.amd) {
// AMD
- define([], function () { return factory(root, document); });
+ define([], function() {
+ return factory(root, document);
+ });
} else {
// Browser globals (root is window)
root.plyr = factory(root, document);
}
-}(typeof window !== 'undefined' ? window : this, function(window, document) {
- 'use strict';
+})(typeof window !== "undefined" ? window : this, function(window, document) {
+ "use strict";
// Globals
var fullscreen,
- scroll = { x: 0, y: 0 },
-
- // Default config
- defaults = {
- enabled: true,
- debug: false,
- autoplay: false,
- loop: false,
- seekTime: 10,
- volume: 10,
- volumeMin: 0,
- volumeMax: 10,
- volumeStep: 1,
- duration: null,
- displayDuration: true,
- loadSprite: true,
- iconPrefix: 'plyr',
- iconUrl: 'https://cdn.plyr.io/2.0.12/plyr.svg',
- blankUrl: 'https://cdn.selz.com/plyr/blank.mp4',
- clickToPlay: true,
- hideControls: true,
- showPosterOnEnd: false,
- disableContextMenu: true,
- keyboardShorcuts: {
- focused: true,
- global: false
- },
- tooltips: {
- controls: false,
- seek: true
- },
- selectors: {
- html5: 'video, audio',
- embed: '[data-type]',
- editable: 'input, textarea, select, [contenteditable]',
- container: '.plyr',
- controls: {
- container: null,
- wrapper: '.plyr__controls'
+ scroll = { x: 0, y: 0 },
+ // Default config
+ defaults = {
+ enabled: true,
+ debug: false,
+ autoplay: false,
+ loop: false,
+ seekTime: 10,
+ volume: 10,
+ volumeMin: 0,
+ volumeMax: 10,
+ volumeStep: 1,
+ duration: null,
+ displayDuration: true,
+ loadSprite: true,
+ iconPrefix: "plyr",
+ iconUrl: "https://cdn.plyr.io/2.0.16/plyr.svg",
+ blankUrl: "https://cdn.plyr.io/static/blank.mp4",
+ clickToPlay: true,
+ hideControls: true,
+ showPosterOnEnd: false,
+ disableContextMenu: true,
+ keyboardShorcuts: {
+ focused: true,
+ global: false
},
- labels: '[data-plyr]',
- buttons: {
- seek: '[data-plyr="seek"]',
- play: '[data-plyr="play"]',
- pause: '[data-plyr="pause"]',
- restart: '[data-plyr="restart"]',
- rewind: '[data-plyr="rewind"]',
- forward: '[data-plyr="fast-forward"]',
- mute: '[data-plyr="mute"]',
- captions: '[data-plyr="captions"]',
- fullscreen: '[data-plyr="fullscreen"]'
+ tooltips: {
+ controls: false,
+ seek: true
},
- volume: {
- input: '[data-plyr="volume"]',
- display: '.plyr__volume--display'
+ selectors: {
+ html5: "video, audio",
+ embed: "[data-type]",
+ editable: "input, textarea, select, [contenteditable]",
+ container: ".plyr",
+ controls: {
+ container: null,
+ wrapper: ".plyr__controls"
+ },
+ labels: "[data-plyr]",
+ buttons: {
+ seek: '[data-plyr="seek"]',
+ play: '[data-plyr="play"]',
+ pause: '[data-plyr="pause"]',
+ restart: '[data-plyr="restart"]',
+ rewind: '[data-plyr="rewind"]',
+ forward: '[data-plyr="fast-forward"]',
+ mute: '[data-plyr="mute"]',
+ captions: '[data-plyr="captions"]',
+ fullscreen: '[data-plyr="fullscreen"]'
+ },
+ volume: {
+ input: '[data-plyr="volume"]',
+ display: ".plyr__volume--display"
+ },
+ progress: {
+ container: ".plyr__progress",
+ buffer: ".plyr__progress--buffer",
+ played: ".plyr__progress--played"
+ },
+ captions: ".plyr__captions",
+ currentTime: ".plyr__time--current",
+ duration: ".plyr__time--duration"
},
- progress: {
- container: '.plyr__progress',
- buffer: '.plyr__progress--buffer',
- played: '.plyr__progress--played'
+ classes: {
+ setup: "plyr--setup",
+ ready: "plyr--ready",
+ videoWrapper: "plyr__video-wrapper",
+ embedWrapper: "plyr__video-embed",
+ type: "plyr--{0}",
+ stopped: "plyr--stopped",
+ playing: "plyr--playing",
+ muted: "plyr--muted",
+ loading: "plyr--loading",
+ hover: "plyr--hover",
+ tooltip: "plyr__tooltip",
+ hidden: "plyr__sr-only",
+ hideControls: "plyr--hide-controls",
+ isIos: "plyr--is-ios",
+ isTouch: "plyr--is-touch",
+ captions: {
+ enabled: "plyr--captions-enabled",
+ active: "plyr--captions-active"
+ },
+ fullscreen: {
+ enabled: "plyr--fullscreen-enabled",
+ fallback: "plyr--fullscreen-fallback",
+ active: "plyr--fullscreen-active"
+ },
+ tabFocus: "tab-focus"
},
- captions: '.plyr__captions',
- currentTime: '.plyr__time--current',
- duration: '.plyr__time--duration'
- },
- classes: {
- setup: 'plyr--setup',
- ready: 'plyr--ready',
- videoWrapper: 'plyr__video-wrapper',
- embedWrapper: 'plyr__video-embed',
- type: 'plyr--{0}',
- stopped: 'plyr--stopped',
- playing: 'plyr--playing',
- muted: 'plyr--muted',
- loading: 'plyr--loading',
- hover: 'plyr--hover',
- tooltip: 'plyr__tooltip',
- hidden: 'plyr__sr-only',
- hideControls: 'plyr--hide-controls',
- isIos: 'plyr--is-ios',
- isTouch: 'plyr--is-touch',
captions: {
- enabled: 'plyr--captions-enabled',
- active: 'plyr--captions-active'
+ defaultActive: false
},
fullscreen: {
- enabled: 'plyr--fullscreen-enabled',
- active: 'plyr--fullscreen-active'
+ enabled: true,
+ fallback: true,
+ allowAudio: false
},
- tabFocus: 'tab-focus'
- },
- captions: {
- defaultActive: false
- },
- fullscreen: {
- enabled: true,
- fallback: true,
- allowAudio: false
- },
- storage: {
- enabled: true,
- key: 'plyr'
- },
- controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'captions', 'fullscreen'],
- i18n: {
- restart: 'Restart',
- rewind: 'Rewind {seektime} secs',
- play: 'Play',
- pause: 'Pause',
- forward: 'Forward {seektime} secs',
- played: 'played',
- buffered: 'buffered',
- currentTime: 'Current time',
- duration: 'Duration',
- volume: 'Volume',
- toggleMute: 'Toggle Mute',
- toggleCaptions: 'Toggle Captions',
- toggleFullscreen: 'Toggle Fullscreen',
- frameTitle: 'Player for {title}'
- },
- types: {
- embed: ['youtube', 'vimeo', 'soundcloud'],
- html5: ['video', 'audio']
- },
- // URLs
- urls: {
- vimeo: {
- api: 'https://player.vimeo.com/api/player.js',
+ storage: {
+ enabled: true,
+ key: "plyr"
},
- youtube: {
- api: 'https://www.youtube.com/iframe_api'
+ controls: ["play-large", "play", "progress", "current-time", "mute", "volume", "captions", "fullscreen"],
+ i18n: {
+ restart: "Restart",
+ rewind: "Rewind {seektime} secs",
+ play: "Play",
+ pause: "Pause",
+ forward: "Forward {seektime} secs",
+ played: "played",
+ buffered: "buffered",
+ currentTime: "Current time",
+ duration: "Duration",
+ volume: "Volume",
+ toggleMute: "Toggle Mute",
+ toggleCaptions: "Toggle Captions",
+ toggleFullscreen: "Toggle Fullscreen",
+ frameTitle: "Player for {title}"
},
- soundcloud: {
- api: 'https://w.soundcloud.com/player/api.js'
- }
- },
- // Custom control listeners
- listeners: {
- seek: null,
- play: null,
- pause: null,
- restart: null,
- rewind: null,
- forward: null,
- mute: null,
- volume: null,
- captions: null,
- fullscreen: null
- },
- // Events to watch on HTML5 media elements
- events: ['ready', 'ended', 'progress', 'stalled', 'playing', 'waiting', 'canplay', 'canplaythrough', 'loadstart', 'loadeddata', 'loadedmetadata', 'timeupdate', 'volumechange', 'play', 'pause', 'error', 'seeking', 'seeked', 'emptied'],
- // Logging
- logPrefix: '[Plyr]'
- };
+ types: {
+ embed: ["youtube", "vimeo", "soundcloud"],
+ html5: ["video", "audio"]
+ },
+ // URLs
+ urls: {
+ vimeo: {
+ api: "https://player.vimeo.com/api/player.js"
+ },
+ youtube: {
+ api: "https://www.youtube.com/iframe_api"
+ },
+ soundcloud: {
+ api: "https://w.soundcloud.com/player/api.js"
+ }
+ },
+ // Custom control listeners
+ listeners: {
+ seek: null,
+ play: null,
+ pause: null,
+ restart: null,
+ rewind: null,
+ forward: null,
+ mute: null,
+ volume: null,
+ captions: null,
+ fullscreen: null
+ },
+ // Events to watch on HTML5 media elements
+ events: [
+ "ready",
+ "ended",
+ "progress",
+ "stalled",
+ "playing",
+ "waiting",
+ "canplay",
+ "canplaythrough",
+ "loadstart",
+ "loadeddata",
+ "loadedmetadata",
+ "timeupdate",
+ "volumechange",
+ "play",
+ "pause",
+ "error",
+ "seeking",
+ "seeked",
+ "emptied"
+ ],
+ // Logging
+ logPrefix: "[Plyr]"
+ };
// Credits: http://paypal.github.io/accessible-html5-video-player/
// Unfortunately, due to mixed support, UA sniffing is required
function _browserSniff() {
var ua = navigator.userAgent,
name = navigator.appName,
- fullVersion = '' + parseFloat(navigator.appVersion),
+ fullVersion = "" + parseFloat(navigator.appVersion),
majorVersion = parseInt(navigator.appVersion, 10),
nameOffset,
verOffset,
@@ -196,37 +218,37 @@
isChrome = false,
isSafari = false;
- if ((navigator.appVersion.indexOf('Windows NT') !== -1) && (navigator.appVersion.indexOf('rv:11') !== -1)) {
+ if (navigator.appVersion.indexOf("Windows NT") !== -1 && navigator.appVersion.indexOf("rv:11") !== -1) {
// MSIE 11
isIE = true;
- name = 'IE';
- fullVersion = '11';
- } else if ((verOffset = ua.indexOf('MSIE')) !== -1) {
+ name = "IE";
+ fullVersion = "11";
+ } else if ((verOffset = ua.indexOf("MSIE")) !== -1) {
// MSIE
isIE = true;
- name = 'IE';
+ name = "IE";
fullVersion = ua.substring(verOffset + 5);
- } else if ((verOffset = ua.indexOf('Chrome')) !== -1) {
+ } else if ((verOffset = ua.indexOf("Chrome")) !== -1) {
// Chrome
isChrome = true;
- name = 'Chrome';
+ name = "Chrome";
fullVersion = ua.substring(verOffset + 7);
- } else if ((verOffset = ua.indexOf('Safari')) !== -1) {
+ } else if ((verOffset = ua.indexOf("Safari")) !== -1) {
// Safari
isSafari = true;
- name = 'Safari';
+ name = "Safari";
fullVersion = ua.substring(verOffset + 7);
- if ((verOffset = ua.indexOf('Version')) !== -1) {
+ if ((verOffset = ua.indexOf("Version")) !== -1) {
fullVersion = ua.substring(verOffset + 8);
}
- } else if ((verOffset = ua.indexOf('Firefox')) !== -1) {
+ } else if ((verOffset = ua.indexOf("Firefox")) !== -1) {
// Firefox
isFirefox = true;
- name = 'Firefox';
+ name = "Firefox";
fullVersion = ua.substring(verOffset + 8);
- } else if ((nameOffset = ua.lastIndexOf(' ') + 1) < (verOffset = ua.lastIndexOf('/'))) {
+ } else if ((nameOffset = ua.lastIndexOf(" ") + 1) < (verOffset = ua.lastIndexOf("/"))) {
// In most other browsers, 'name/version' is at the end of userAgent
- name = ua.substring(nameOffset,verOffset);
+ name = ua.substring(nameOffset, verOffset);
fullVersion = ua.substring(verOffset + 1);
if (name.toLowerCase() === name.toUpperCase()) {
@@ -235,31 +257,31 @@
}
// Trim the fullVersion string at semicolon/space if present
- if ((ix = fullVersion.indexOf(';')) !== -1) {
+ if ((ix = fullVersion.indexOf(";")) !== -1) {
fullVersion = fullVersion.substring(0, ix);
}
- if ((ix = fullVersion.indexOf(' ')) !== -1) {
+ if ((ix = fullVersion.indexOf(" ")) !== -1) {
fullVersion = fullVersion.substring(0, ix);
}
// Get major version
- majorVersion = parseInt('' + fullVersion, 10);
+ majorVersion = parseInt("" + fullVersion, 10);
if (isNaN(majorVersion)) {
- fullVersion = '' + parseFloat(navigator.appVersion);
+ fullVersion = "" + parseFloat(navigator.appVersion);
majorVersion = parseInt(navigator.appVersion, 10);
}
// Return data
return {
- name: name,
- version: majorVersion,
- isIE: isIE,
- isFirefox: isFirefox,
- isChrome: isChrome,
- isSafari: isSafari,
- isIos: /(iPad|iPhone|iPod)/g.test(navigator.platform),
- isIphone: /(iPhone|iPod)/g.test(navigator.userAgent),
- isTouch: 'ontouchstart' in document.documentElement
+ name: name,
+ version: majorVersion,
+ isIE: isIE,
+ isFirefox: isFirefox,
+ isChrome: isChrome,
+ isSafari: isSafari,
+ isIos: /(iPad|iPhone|iPod)/g.test(navigator.platform),
+ isIphone: /(iPhone|iPod)/g.test(navigator.userAgent),
+ isTouch: "ontouchstart" in document.documentElement
};
}
@@ -269,19 +291,30 @@
function _supportMime(plyr, mimeType) {
var media = plyr.media;
- if (plyr.type === 'video') {
+ if (plyr.type === "video") {
// Check type
switch (mimeType) {
- case 'video/webm': return !!(media.canPlayType && media.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/, ''));
- case 'video/mp4': return !!(media.canPlayType && media.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, ''));
- case 'video/ogg': return !!(media.canPlayType && media.canPlayType('video/ogg; codecs="theora"').replace(/no/, ''));
- }
- } else if (plyr.type === 'audio') {
+ case "video/webm":
+ return !!(
+ media.canPlayType && media.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/, "")
+ );
+ case "video/mp4":
+ return !!(
+ media.canPlayType &&
+ media.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, "")
+ );
+ case "video/ogg":
+ return !!(media.canPlayType && media.canPlayType('video/ogg; codecs="theora"').replace(/no/, ""));
+ }
+ } else if (plyr.type === "audio") {
// Check type
switch (mimeType) {
- case 'audio/mpeg': return !!(media.canPlayType && media.canPlayType('audio/mpeg;').replace(/no/, ''));
- case 'audio/ogg': return !!(media.canPlayType && media.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, ''));
- case 'audio/wav': return !!(media.canPlayType && media.canPlayType('audio/wav; codecs="1"').replace(/no/, ''));
+ case "audio/mpeg":
+ return !!(media.canPlayType && media.canPlayType("audio/mpeg;").replace(/no/, ""));
+ case "audio/ogg":
+ return !!(media.canPlayType && media.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, ""));
+ case "audio/wav":
+ return !!(media.canPlayType && media.canPlayType('audio/wav; codecs="1"').replace(/no/, ""));
}
}
@@ -295,20 +328,20 @@
return;
}
- var tag = document.createElement('script');
+ var tag = document.createElement("script");
tag.src = source;
- var firstScriptTag = document.getElementsByTagName('script')[0];
+ var firstScriptTag = document.getElementsByTagName("script")[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
}
// Element exists in an array
function _inArray(haystack, needle) {
- return Array.prototype.indexOf && (haystack.indexOf(needle) !== -1);
+ return Array.prototype.indexOf && haystack.indexOf(needle) !== -1;
}
// Replace all
function _replaceAll(string, find, replace) {
- return string.replace(new RegExp(find.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, '\\$1'), 'g'), replace);
+ return string.replace(new RegExp(find.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, "\\$1"), "g"), replace);
}
// Wrap an element
@@ -321,11 +354,11 @@
// Loops backwards to prevent having to clone the wrapper on the
// first element (see `child` below).
for (var i = elements.length - 1; i >= 0; i--) {
- var child = (i > 0) ? wrapper.cloneNode(true) : wrapper;
+ var child = i > 0 ? wrapper.cloneNode(true) : wrapper;
var element = elements[i];
// Cache the current parent and sibling.
- var parent = element.parentNode;
+ var parent = element.parentNode;
var sibling = element.nextSibling;
// Wrap the element (is automatically removed from its current
@@ -376,7 +409,7 @@
// Set attributes
function _setAttributes(element, attributes) {
for (var key in attributes) {
- element.setAttribute(key, (_is.boolean(attributes[key]) && attributes[key]) ? '' : attributes[key]);
+ element.setAttribute(key, _is.boolean(attributes[key]) && attributes[key] ? "" : attributes[key]);
}
}
@@ -394,17 +427,17 @@
// Get a classname from selector
function _getClassname(selector) {
- return selector.replace('.', '');
+ return selector.replace(".", "");
}
// Toggle class on an element
function _toggleClass(element, className, state) {
if (element) {
if (element.classList) {
- element.classList[state ? 'add' : 'remove'](className);
+ element.classList[state ? "add" : "remove"](className);
} else {
- var name = (' ' + element.className + ' ').replace(/\s+/g, ' ').replace(' ' + className + ' ', '');
- element.className = name + (state ? ' ' + className : '');
+ var name = (" " + element.className + " ").replace(/\s+/g, " ").replace(" " + className + " ", "");
+ element.className = name + (state ? " " + className : "");
}
}
}
@@ -415,7 +448,7 @@
if (element.classList) {
return element.classList.contains(className);
} else {
- return new RegExp('(\\s|^)' + className + '(\\s|$)').test(element.className);
+ return new RegExp("(\\s|^)" + className + "(\\s|$)").test(element.className);
}
}
return false;
@@ -425,26 +458,44 @@
function _matches(element, selector) {
var p = Element.prototype;
- var f = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || function(s) {
- return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
- };
+ var f =
+ p.matches ||
+ p.webkitMatchesSelector ||
+ p.mozMatchesSelector ||
+ p.msMatchesSelector ||
+ function(s) {
+ return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
+ };
return f.call(element, selector);
}
// Bind along with custom handler
function _proxyListener(element, eventName, userListener, defaultListener, useCapture) {
- _on(element, eventName, function(event) {
- if (userListener) {
- userListener.apply(element, [event]);
- }
- defaultListener.apply(element, [event]);
- }, useCapture);
+ if(userListener) {
+ // Register this before defaultListener
+ _on(
+ element,
+ eventName,
+ function(event) {
+ userListener.apply(element, [event]);
+ },
+ useCapture
+ );
+ }
+ _on(
+ element,
+ eventName,
+ function(event) {
+ defaultListener.apply(element, [event]);
+ },
+ useCapture
+ );
}
// Toggle event listener
function _toggleListener(element, events, callback, toggle, useCapture) {
- var eventList = events.split(' ');
+ var eventList = events.split(" ");
// Whether the listener is a capturing listener or not
// Default to false
@@ -464,7 +515,7 @@
// If a single node is passed, bind the event listener
for (var i = 0; i < eventList.length; i++) {
- element[toggle ? 'addEventListener' : 'removeEventListener'](eventList[i], callback, useCapture);
+ element[toggle ? "addEventListener" : "removeEventListener"](eventList[i], callback, useCapture);
}
}
@@ -476,11 +527,11 @@
}
// Unbind event
- /*function _off(element, events, callback, useCapture) {
+ function _off(element, events, callback, useCapture) {
if (element) {
_toggleListener(element, events, callback, false, useCapture);
}
- }*/
+ }
// Trigger event
function _event(element, type, bubbles, properties) {
@@ -496,8 +547,8 @@
// Create and dispatch the event
var event = new CustomEvent(type, {
- bubbles: bubbles,
- detail: properties
+ bubbles: bubbles,
+ detail: properties
});
// Dispatch the event
@@ -513,10 +564,10 @@
}
// Get state
- state = (_is.boolean(state) ? state : !target.getAttribute('aria-pressed'));
+ state = _is.boolean(state) ? state : !target.getAttribute("aria-pressed");
// Set the attribute on target
- target.setAttribute('aria-pressed', state);
+ target.setAttribute("aria-pressed", state);
return state;
}
@@ -526,7 +577,7 @@
if (current === 0 || max === 0 || isNaN(current) || isNaN(max)) {
return 0;
}
- return ((current / max) * 100).toFixed(2);
+ return (current / max * 100).toFixed(2);
}
// Deep extend/merge destination object with N more objects
@@ -548,7 +599,7 @@
// First object is the destination
var destination = Array.prototype.shift.call(objects),
- length = objects.length;
+ length = objects.length;
// Loop through all objects to merge
for (var i = 0; i < length; i++) {
@@ -570,19 +621,26 @@
// Check variable types
var _is = {
object: function(input) {
- return input !== null && typeof(input) === 'object';
+ return input !== null && typeof input === "object";
},
array: function(input) {
- return input !== null && (typeof(input) === 'object' && input.constructor === Array);
+ return input !== null && (typeof input === "object" && input.constructor === Array);
},
number: function(input) {
- return input !== null && (typeof(input) === 'number' && !isNaN(input - 0) || (typeof input === 'object' && input.constructor === Number));
+ return (
+ input !== null &&
+ ((typeof input === "number" && !isNaN(input - 0)) ||
+ (typeof input === "object" && input.constructor === Number))
+ );
},
string: function(input) {
- return input !== null && (typeof input === 'string' || (typeof input === 'object' && input.constructor === String));
+ return (
+ input !== null &&
+ (typeof input === "string" || (typeof input === "object" && input.constructor === String))
+ );
},
boolean: function(input) {
- return input !== null && typeof input === 'boolean';
+ return input !== null && typeof input === "boolean";
},
nodeList: function(input) {
return input !== null && input instanceof NodeList;
@@ -591,52 +649,54 @@
return input !== null && input instanceof HTMLElement;
},
function: function(input) {
- return input !== null && typeof input === 'function';
+ return input !== null && typeof input === "function";
},
undefined: function(input) {
- return input !== null && typeof input === 'undefined';
+ return input !== null && typeof input === "undefined";
}
};
// Parse YouTube ID from url
function _parseYouTubeId(url) {
var regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
- return (url.match(regex)) ? RegExp.$2 : url;
+ return url.match(regex) ? RegExp.$2 : url;
}
- // Parse Vimeo ID from url
- function _parseVimeoId(url) {
+ // Is this a Vimeo url link?
+ function _isVimeoUrl(url) {
var regex = /^.*(vimeo.com\/|video\/)(\d+).*/;
- return (url.match(regex)) ? RegExp.$2 : url;
+ return url.match(regex);
}
// Fullscreen API
function _fullscreen() {
var fullscreen = {
supportsFullScreen: false,
- isFullScreen: function() { return false; },
+ isFullScreen: function() {
+ return false;
+ },
requestFullScreen: function() {},
cancelFullScreen: function() {},
- fullScreenEventName: '',
+ fullScreenEventName: "",
element: null,
- prefix: ''
+ prefix: ""
},
- browserPrefixes = 'webkit o moz ms khtml'.split(' ');
+ browserPrefixes = "webkit o moz ms khtml".split(" ");
// Check for native support
if (!_is.undefined(document.cancelFullScreen)) {
fullscreen.supportsFullScreen = true;
} else {
// Check for fullscreen support by vendor prefix
- for (var i = 0, il = browserPrefixes.length; i < il; i++ ) {
+ for (var i = 0, il = browserPrefixes.length; i < il; i++) {
fullscreen.prefix = browserPrefixes[i];
- if (!_is.undefined(document[fullscreen.prefix + 'CancelFullScreen'])) {
+ if (!_is.undefined(document[fullscreen.prefix + "CancelFullScreen"])) {
fullscreen.supportsFullScreen = true;
break;
} else if (!_is.undefined(document.msExitFullscreen) && document.msFullscreenEnabled) {
// Special case for MS (when isn't it?)
- fullscreen.prefix = 'ms';
+ fullscreen.prefix = "ms";
fullscreen.supportsFullScreen = true;
break;
}
@@ -647,32 +707,37 @@
if (fullscreen.supportsFullScreen) {
// Yet again Microsoft awesomeness,
// Sometimes the prefix is 'ms', sometimes 'MS' to keep you on your toes
- fullscreen.fullScreenEventName = (fullscreen.prefix === 'ms' ? 'MSFullscreenChange' : fullscreen.prefix + 'fullscreenchange');
+ fullscreen.fullScreenEventName =
+ fullscreen.prefix === "ms" ? "MSFullscreenChange" : fullscreen.prefix + "fullscreenchange";
fullscreen.isFullScreen = function(element) {
if (_is.undefined(element)) {
element = document.body;
}
switch (this.prefix) {
- case '':
+ case "":
return document.fullscreenElement === element;
- case 'moz':
+ case "moz":
return document.mozFullScreenElement === element;
default:
- return document[this.prefix + 'FullscreenElement'] === element;
+ return document[this.prefix + "FullscreenElement"] === element;
}
};
fullscreen.requestFullScreen = function(element) {
if (_is.undefined(element)) {
element = document.body;
}
- return (this.prefix === '') ? element.requestFullScreen() : element[this.prefix + (this.prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')]();
+ return this.prefix === ""
+ ? element.requestFullScreen()
+ : element[this.prefix + (this.prefix === "ms" ? "RequestFullscreen" : "RequestFullScreen")]();
};
fullscreen.cancelFullScreen = function() {
- return (this.prefix === '') ? document.cancelFullScreen() : document[this.prefix + (this.prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen')]();
+ return this.prefix === ""
+ ? document.cancelFullScreen()
+ : document[this.prefix + (this.prefix === "ms" ? "ExitFullscreen" : "CancelFullScreen")]();
};
fullscreen.element = function() {
- return (this.prefix === '') ? document.fullscreenElement : document[this.prefix + 'FullscreenElement'];
+ return this.prefix === "" ? document.fullscreenElement : document[this.prefix + "FullscreenElement"];
};
}
@@ -682,26 +747,21 @@
// Local storage
var _storage = {
supported: (function() {
- if (!('localStorage' in window)) {
- return false;
- }
-
// Try to use it (it might be disabled, e.g. user is in private/porn mode)
- // see: https://github.com/Selz/plyr/issues/131
+ // see: https://github.com/sampotts/plyr/issues/131
try {
// Add test item
- window.localStorage.setItem('___test', 'OK');
+ window.localStorage.setItem("___test", "OK");
// Get the test item
- var result = window.localStorage.getItem('___test');
+ var result = window.localStorage.getItem("___test");
// Clean up
- window.localStorage.removeItem('___test');
+ window.localStorage.removeItem("___test");
// Check if value matches
- return (result === 'OK');
- }
- catch (e) {
+ return result === "OK";
+ } catch (e) {
return false;
}
@@ -712,8 +772,8 @@
// Player instance
function Plyr(media, config) {
var plyr = this,
- timers = {},
- api;
+ timers = {},
+ api;
// Set media
plyr.media = media;
@@ -721,9 +781,14 @@
// Trigger events, with plyr instance passed
function _triggerEvent(element, type, bubbles, properties) {
- _event(element, type, bubbles, _extend({}, properties, {
- plyr: api
- }));
+ _event(
+ element,
+ type,
+ bubbles,
+ _extend({}, properties, {
+ plyr: api
+ })
+ );
}
// Debugging
@@ -738,94 +803,101 @@
console[type].apply(console, args);
}
}
- var _log = function() { _console('log', arguments) },
- _warn = function() { _console('warn', arguments) };
+ var _log = function() {
+ _console("log", arguments);
+ },
+ _warn = function() {
+ _console("warn", arguments);
+ };
// Log config options
- _log('Config', config);
+ _log("Config", config);
// Get icon URL
function _getIconUrl() {
return {
url: config.iconUrl,
- absolute: (config.iconUrl.indexOf("http") === 0) || (plyr.browser.isIE && !window.svg4everybody) // If you're using svg4everybody you don't need absolute paths
+ // If you're using svg4everybody you don't need absolute paths
+ absolute: config.iconUrl.indexOf("http") === 0 || (plyr.browser.isIE && !window.svg4everybody)
};
}
// Build the default HTML
function _buildControls() {
// Create html array
- var html = [],
- iconUrl = _getIconUrl(),
- iconPath = (!iconUrl.absolute ? iconUrl.url : '') + '#' + config.iconPrefix;
+ var html = [],
+ iconUrl = _getIconUrl(),
+ iconPath = (!iconUrl.absolute ? iconUrl.url : "") + "#" + config.iconPrefix;
// Larger overlaid play button
- if (_inArray(config.controls, 'play-large')) {
+ if (_inArray(config.controls, "play-large")) {
html.push(
'<button type="button" data-plyr="play" class="plyr__play-large">',
- '<svg><use xlink:href="' + iconPath + '-play" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.play + '</span>',
- '</button>'
+ '<svg><use xlink:href="' + iconPath + '-play" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.play + "</span>",
+ "</button>"
);
}
html.push('<div class="plyr__controls">');
// Restart button
- if (_inArray(config.controls, 'restart')) {
+ if (_inArray(config.controls, "restart")) {
html.push(
'<button type="button" data-plyr="restart">',
- '<svg><use xlink:href="' + iconPath + '-restart" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.restart + '</span>',
- '</button>'
+ '<svg><use xlink:href="' + iconPath + '-restart" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.restart + "</span>",
+ "</button>"
);
}
// Rewind button
- if (_inArray(config.controls, 'rewind')) {
+ if (_inArray(config.controls, "rewind")) {
html.push(
'<button type="button" data-plyr="rewind">',
- '<svg><use xlink:href="' + iconPath + '-rewind" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.rewind + '</span>',
- '</button>'
+ '<svg><use xlink:href="' + iconPath + '-rewind" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.rewind + "</span>",
+ "</button>"
);
}
// Play Pause button
// TODO: This should be a toggle button really?
- if (_inArray(config.controls, 'play')) {
+ if (_inArray(config.controls, "play")) {
html.push(
'<button type="button" data-plyr="play">',
- '<svg><use xlink:href="' + iconPath + '-play" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.play + '</span>',
- '</button>',
+ '<svg><use xlink:href="' + iconPath + '-play" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.play + "</span>",
+ "</button>",
'<button type="button" data-plyr="pause">',
- '<svg><use xlink:href="' + iconPath + '-pause" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.pause + '</span>',
- '</button>'
+ '<svg><use xlink:href="' + iconPath + '-pause" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.pause + "</span>",
+ "</button>"
);
}
// Fast forward button
- if (_inArray(config.controls, 'fast-forward')) {
+ if (_inArray(config.controls, "fast-forward")) {
html.push(
'<button type="button" data-plyr="fast-forward">',
- '<svg><use xlink:href="' + iconPath + '-fast-forward" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.forward + '</span>',
- '</button>'
+ '<svg><use xlink:href="' + iconPath + '-fast-forward" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.forward + "</span>",
+ "</button>"
);
}
// Progress
- if (_inArray(config.controls, 'progress')) {
+ if (_inArray(config.controls, "progress")) {
// Create progress
- html.push('<span class="plyr__progress">',
+ html.push(
+ '<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>% ' + config.i18n.buffered,
- '</progress>');
+ "<span>0</span>% " + config.i18n.buffered,
+ "</progress>"
+ );
// Seek tooltip
if (config.tooltips.seek) {
@@ -833,77 +905,87 @@
}
// Close
- html.push('</span>');
+ html.push("</span>");
}
// Media current time display
- if (_inArray(config.controls, 'current-time')) {
+ if (_inArray(config.controls, "current-time")) {
html.push(
'<span class="plyr__time">',
- '<span class="plyr__sr-only">' + config.i18n.currentTime + '</span>',
- '<span class="plyr__time--current">00:00</span>',
- '</span>'
+ '<span class="plyr__sr-only">' + config.i18n.currentTime + "</span>",
+ '<span class="plyr__time--current">00:00</span>',
+ "</span>"
);
}
// Media duration display
- if (_inArray(config.controls, 'duration')) {
+ if (_inArray(config.controls, "duration")) {
html.push(
'<span class="plyr__time">',
- '<span class="plyr__sr-only">' + config.i18n.duration + '</span>',
- '<span class="plyr__time--duration">00:00</span>',
- '</span>'
+ '<span class="plyr__sr-only">' + config.i18n.duration + "</span>",
+ '<span class="plyr__time--duration">00:00</span>',
+ "</span>"
);
}
// Toggle mute button
- if (_inArray(config.controls, 'mute')) {
+ if (_inArray(config.controls, "mute")) {
html.push(
'<button type="button" data-plyr="mute">',
- '<svg class="icon--muted"><use xlink:href="' + iconPath + '-muted" /></svg>',
- '<svg><use xlink:href="' + iconPath + '-volume" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.toggleMute + '</span>',
- '</button>'
+ '<svg class="icon--muted"><use xlink:href="' + iconPath + '-muted" /></svg>',
+ '<svg><use xlink:href="' + iconPath + '-volume" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.toggleMute + "</span>",
+ "</button>"
);
}
// Volume range control
- if (_inArray(config.controls, 'volume')) {
+ if (_inArray(config.controls, "volume")) {
html.push(
'<span class="plyr__volume">',
- '<label for="volume{id}" class="plyr__sr-only">' + config.i18n.volume + '</label>',
- '<input id="volume{id}" class="plyr__volume--input" type="range" min="' + config.volumeMin + '" max="' + config.volumeMax + '" value="' + config.volume + '" data-plyr="volume">',
- '<progress class="plyr__volume--display" max="' + config.volumeMax + '" value="' + config.volumeMin + '" role="presentation"></progress>',
- '</span>'
+ '<label for="volume{id}" class="plyr__sr-only">' + config.i18n.volume + "</label>",
+ '<input id="volume{id}" class="plyr__volume--input" type="range" min="' +
+ config.volumeMin +
+ '" max="' +
+ config.volumeMax +
+ '" value="' +
+ config.volume +
+ '" data-plyr="volume">',
+ '<progress class="plyr__volume--display" max="' +
+ config.volumeMax +
+ '" value="' +
+ config.volumeMin +
+ '" role="presentation"></progress>',
+ "</span>"
);
}
// Toggle captions button
- if (_inArray(config.controls, 'captions')) {
+ if (_inArray(config.controls, "captions")) {
html.push(
'<button type="button" data-plyr="captions">',
- '<svg class="icon--captions-on"><use xlink:href="' + iconPath + '-captions-on" /></svg>',
- '<svg><use xlink:href="' + iconPath+ '-captions-off" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.toggleCaptions + '</span>',
- '</button>'
+ '<svg class="icon--captions-on"><use xlink:href="' + iconPath + '-captions-on" /></svg>',
+ '<svg><use xlink:href="' + iconPath + '-captions-off" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.toggleCaptions + "</span>",
+ "</button>"
);
}
// Toggle fullscreen button
- if (_inArray(config.controls, 'fullscreen')) {
+ if (_inArray(config.controls, "fullscreen")) {
html.push(
'<button type="button" data-plyr="fullscreen">',
- '<svg class="icon--exit-fullscreen"><use xlink:href="' + iconPath + '-exit-fullscreen" /></svg>',
- '<svg><use xlink:href="' + iconPath + '-enter-fullscreen" /></svg>',
- '<span class="plyr__sr-only">' + config.i18n.toggleFullscreen + '</span>',
- '</button>'
+ '<svg class="icon--exit-fullscreen"><use xlink:href="' + iconPath + '-exit-fullscreen" /></svg>',
+ '<svg><use xlink:href="' + iconPath + '-enter-fullscreen" /></svg>',
+ '<span class="plyr__sr-only">' + config.i18n.toggleFullscreen + "</span>",
+ "</button>"
);
}
// Close everything
- html.push('</div>');
+ html.push("</div>");
- return html.join('');
+ return html.join("");
}
// Setup fullscreen
@@ -912,17 +994,22 @@
return;
}
- if ((plyr.type !== 'audio' || config.fullscreen.allowAudio) && config.fullscreen.enabled) {
+ if ((plyr.type !== "audio" || config.fullscreen.allowAudio) && config.fullscreen.enabled) {
// Check for native support
var nativeSupport = fullscreen.supportsFullScreen;
if (nativeSupport || (config.fullscreen.fallback && !_inFrame())) {
- _log((nativeSupport ? 'Native' : 'Fallback') + ' fullscreen enabled');
+ _log((nativeSupport ? "Native" : "Fallback") + " fullscreen enabled");
+
+ // Add styling hook
+ if (!nativeSupport) {
+ _toggleClass(plyr.container, config.classes.fullscreen.fallback, true);
+ }
// Add styling hook
_toggleClass(plyr.container, config.classes.fullscreen.enabled, true);
} else {
- _log('Fullscreen not supported and fallback disabled');
+ _log("Fullscreen not supported and fallback disabled");
}
// Toggle state
@@ -938,13 +1025,16 @@
// Setup captions
function _setupCaptions() {
// Bail if not HTML5 video
- if (plyr.type !== 'video') {
+ if (plyr.type !== "video") {
return;
}
// Inject the container
if (!_getElement(config.selectors.captions)) {
- plyr.videoContainer.insertAdjacentHTML('afterbegin', '<div class="' + _getClassname(config.selectors.captions) + '"></div>');
+ plyr.videoContainer.insertAdjacentHTML(
+ "afterbegin",
+ '<div class="' + _getClassname(config.selectors.captions) + '"></div>'
+ );
}
// Determine if HTML5 textTracks is supported
@@ -954,26 +1044,26 @@
}
// Get URL of caption file if exists
- var captionSrc = '',
+ var captionSrc = "",
kind,
children = plyr.media.childNodes;
for (var i = 0; i < children.length; i++) {
- if (children[i].nodeName.toLowerCase() === 'track') {
+ if (children[i].nodeName.toLowerCase() === "track") {
kind = children[i].kind;
- if (kind === 'captions' || kind === 'subtitles') {
- captionSrc = children[i].getAttribute('src');
+ if (kind === "captions" || kind === "subtitles") {
+ captionSrc = children[i].getAttribute("src");
}
}
}
// Record if caption file exists or not
plyr.captionExists = true;
- if (captionSrc === '') {
+ if (captionSrc === "") {
plyr.captionExists = false;
- _log('No caption track found');
+ _log("No caption track found");
} else {
- _log('Caption track found; URI: ' + captionSrc);
+ _log("Caption track found; URI: " + captionSrc);
}
// If no caption file exists, hide container for caption text
@@ -984,7 +1074,7 @@
// This doesn't seem to work in Safari 7+, so the <track> elements are removed from the dom below
var tracks = plyr.media.textTracks;
for (var x = 0; x < tracks.length; x++) {
- tracks[x].mode = 'hidden';
+ tracks[x].mode = "hidden";
}
// Enable UI
@@ -992,11 +1082,12 @@
// Disable unsupported browsers than report false positive
// Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1033144
- if ((plyr.browser.isIE && plyr.browser.version >= 10) ||
- (plyr.browser.isFirefox && plyr.browser.version >= 31)) {
-
+ if (
+ (plyr.browser.isIE && plyr.browser.version >= 10) ||
+ (plyr.browser.isFirefox && plyr.browser.version >= 31)
+ ) {
// Debugging
- _log('Detected browser with known TextTrack issues - using manual fallback');
+ _log("Detected browser with known TextTrack issues - using manual fallback");
// Set to false so skips to 'manual' captioning
plyr.usingTextTracks = false;
@@ -1005,15 +1096,15 @@
// Rendering caption tracks
// Native support required - http://caniuse.com/webvtt
if (plyr.usingTextTracks) {
- _log('TextTracks supported');
+ _log("TextTracks supported");
for (var y = 0; y < tracks.length; y++) {
var track = tracks[y];
- if (track.kind === 'captions' || track.kind === 'subtitles') {
- _on(track, 'cuechange', function() {
+ if (track.kind === "captions" || track.kind === "subtitles") {
+ _on(track, "cuechange", function() {
// Display a cue, if there is one
- if (this.activeCues[0] && 'text' in this.activeCues[0]) {
+ if (this.activeCues[0] && "text" in this.activeCues[0]) {
_setCaption(this.activeCues[0].getCueAsHTML());
} else {
_setCaption();
@@ -1023,13 +1114,13 @@
}
} else {
// Caption tracks not natively supported
- _log('TextTracks not supported so rendering captions manually');
+ _log("TextTracks not supported so rendering captions manually");
// Render captions from array at appropriate time
- plyr.currentCaption = '';
+ plyr.currentCaption = "";
plyr.captions = [];
- if (captionSrc !== '') {
+ if (captionSrc !== "") {
// Create XMLHttpRequest Object
var xhr = new XMLHttpRequest();
@@ -1042,16 +1133,16 @@
//According to webvtt spec, line terminator consists of one of the following
// CRLF (U+000D U+000A), LF (U+000A) or CR (U+000D)
- var lineSeparator = '\r\n';
- if(req.indexOf(lineSeparator+lineSeparator) === -1) {
- if(req.indexOf('\r\r') !== -1){
- lineSeparator = '\r';
+ var lineSeparator = "\r\n";
+ if (req.indexOf(lineSeparator + lineSeparator) === -1) {
+ if (req.indexOf("\r\r") !== -1) {
+ lineSeparator = "\r";
} else {
- lineSeparator = '\n';
+ lineSeparator = "\n";
}
}
- captions = req.split(lineSeparator+lineSeparator);
+ captions = req.split(lineSeparator + lineSeparator);
for (var r = 0; r < captions.length; r++) {
caption = captions[r];
@@ -1072,14 +1163,14 @@
// Remove first element ('VTT')
plyr.captions.shift();
- _log('Successfully loaded the caption file via AJAX');
+ _log("Successfully loaded the caption file via AJAX");
} else {
- _warn(config.logPrefix + 'There was a problem loading the caption file via AJAX');
+ _warn(config.logPrefix + "There was a problem loading the caption file via AJAX");
}
}
};
- xhr.open('get', captionSrc, true);
+ xhr.open("get", captionSrc, true);
xhr.send();
}
@@ -1091,14 +1182,14 @@
function _setCaption(caption) {
/* jshint unused:false */
var container = _getElement(config.selectors.captions),
- content = document.createElement('span');
+ content = document.createElement("span");
// Empty the container
- container.innerHTML = '';
+ container.innerHTML = "";
// Default to empty
if (_is.undefined(caption)) {
- caption = '';
+ caption = "";
}
// Set the span content
@@ -1121,8 +1212,8 @@
// Utilities for caption time codes
function _timecodeCommon(tc, pos) {
var tcpair = [];
- tcpair = tc.split(' --> ');
- for(var i = 0; i < tcpair.length; i++) {
+ tcpair = tc.split(" --> ");
+ for (var i = 0; i < tcpair.length; i++) {
// WebVTT allows for extra meta data after the timestamp line
// So get rid of this if it exists
tcpair[i] = tcpair[i].replace(/(\d+:\d+:\d+\.\d+).*/, "$1");
@@ -1142,15 +1233,15 @@
var tc1 = [],
tc2 = [],
seconds;
- tc1 = tc.split(',');
- tc2 = tc1[0].split(':');
- seconds = Math.floor(tc2[0]*60*60) + Math.floor(tc2[1]*60) + Math.floor(tc2[2]);
+ tc1 = tc.split(",");
+ tc2 = tc1[0].split(":");
+ seconds = Math.floor(tc2[0] * 60 * 60) + Math.floor(tc2[1] * 60) + Math.floor(tc2[2]);
return seconds;
}
}
// If it's not video, or we're using textTracks, bail.
- if (plyr.usingTextTracks || plyr.type !== 'video' || !plyr.supported.full) {
+ if (plyr.usingTextTracks || plyr.type !== "video" || !plyr.supported.full) {
return;
}
@@ -1176,9 +1267,11 @@
}
// Check if the next caption is in the current time range
- if (plyr.media.currentTime.toFixed(1) >= _timecodeMin(plyr.captions[plyr.subcount][0]) &&
- plyr.media.currentTime.toFixed(1) <= _timecodeMax(plyr.captions[plyr.subcount][0])) {
- plyr.currentCaption = plyr.captions[plyr.subcount][1];
+ if (
+ plyr.media.currentTime.toFixed(1) >= _timecodeMin(plyr.captions[plyr.subcount][0]) &&
+ plyr.media.currentTime.toFixed(1) <= _timecodeMax(plyr.captions[plyr.subcount][0])
+ ) {
+ plyr.currentCaption = plyr.captions[plyr.subcount][1];
// Render the caption
_setCaption(plyr.currentCaption);
@@ -1224,17 +1317,16 @@
function _inFrame() {
try {
return window.self !== window.top;
- }
- catch (e) {
+ } catch (e) {
return true;
}
}
// Trap focus inside container
function _focusTrap() {
- var tabbables = _getElements('input:not([disabled]), button:not([disabled])'),
- first = tabbables[0],
- last = tabbables[tabbables.length - 1];
+ var tabbables = _getElements("input:not([disabled]), button:not([disabled])"),
+ first = tabbables[0],
+ last = tabbables[tabbables.length - 1];
function _checkFocus(event) {
// If it is TAB
@@ -1252,13 +1344,13 @@
}
// Bind the handler
- _on(plyr.container, 'keydown', _checkFocus);
+ _on(plyr.container, "keydown", _checkFocus);
}
// Add elements to HTML5 media (source, tracks, etc)
function _insertChildElements(type, attributes) {
if (_is.string(attributes)) {
- _insertElement(type, plyr.media, { src: attributes });
+ _insertElement(type, plyr.media, { src: attributes });
} else if (attributes.constructor === Array) {
for (var i = attributes.length - 1; i >= 0; i--) {
_insertElement(type, plyr.media, attributes[i]);
@@ -1274,10 +1366,10 @@
// Only load external sprite using AJAX
if (iconUrl.absolute) {
- _log('AJAX loading absolute SVG sprite' + (plyr.browser.isIE ? ' (due to IE)' : ''));
+ _log("AJAX loading absolute SVG sprite" + (plyr.browser.isIE ? " (due to IE)" : ""));
loadSprite(iconUrl.url, "sprite-plyr");
} else {
- _log('Sprite will be used as external resource directly');
+ _log("Sprite will be used as external resource directly");
}
}
@@ -1285,7 +1377,7 @@
var html = config.html;
// Insert custom video controls
- _log('Injecting custom controls');
+ _log("Injecting custom controls");
// If no controls are specified, create default
if (!html) {
@@ -1293,10 +1385,15 @@
}
// Replace seek time instances
- html = _replaceAll(html, '{seektime}', config.seekTime);
+ html = _replaceAll(html, "{seektime}", config.seekTime);
// Replace all id references with random numbers
- html = _replaceAll(html, '{id}', Math.floor(Math.random() * (10000)));
+ html = _replaceAll(html, "{id}", Math.floor(Math.random() * 10000));
+
+ // Replace Title, if it exists
+ if (config.title){
+ html = _replaceAll(html, '{title}', config.title);
+ }
// Controls container
var target;
@@ -1308,15 +1405,19 @@
// Inject into the container by default
if (!_is.htmlElement(target)) {
- target = plyr.container
+ target = plyr.container;
}
// Inject controls HTML
- target.insertAdjacentHTML('beforeend', html);
+ target.insertAdjacentHTML("beforeend", html);
// Setup tooltips
if (config.tooltips.controls) {
- var labels = _getElements([config.selectors.controls.wrapper, ' ', config.selectors.labels, ' .', config.classes.hidden].join(''));
+ var labels = _getElements(
+ [config.selectors.controls.wrapper, " ", config.selectors.labels, " .", config.classes.hidden].join(
+ ""
+ )
+ );
for (var i = labels.length - 1; i >= 0; i--) {
var label = labels[i];
@@ -1330,51 +1431,52 @@
// Find the UI controls and store references
function _findElements() {
try {
- plyr.controls = _getElement(config.selectors.controls.wrapper);
+ plyr.controls = _getElement(config.selectors.controls.wrapper);
// Buttons
plyr.buttons = {};
- plyr.buttons.seek = _getElement(config.selectors.buttons.seek);
- plyr.buttons.play = _getElements(config.selectors.buttons.play);
- plyr.buttons.pause = _getElement(config.selectors.buttons.pause);
- plyr.buttons.restart = _getElement(config.selectors.buttons.restart);
- plyr.buttons.rewind = _getElement(config.selectors.buttons.rewind);
- plyr.buttons.forward = _getElement(config.selectors.buttons.forward);
- plyr.buttons.fullscreen = _getElement(config.selectors.buttons.fullscreen);
+ plyr.buttons.seek = _getElement(config.selectors.buttons.seek);
+ plyr.buttons.play = _getElements(config.selectors.buttons.play);
+ plyr.buttons.pause = _getElement(config.selectors.buttons.pause);
+ plyr.buttons.restart = _getElement(config.selectors.buttons.restart);
+ plyr.buttons.rewind = _getElement(config.selectors.buttons.rewind);
+ plyr.buttons.forward = _getElement(config.selectors.buttons.forward);
+ plyr.buttons.fullscreen = _getElement(config.selectors.buttons.fullscreen);
// Inputs
- plyr.buttons.mute = _getElement(config.selectors.buttons.mute);
- plyr.buttons.captions = _getElement(config.selectors.buttons.captions);
+ plyr.buttons.mute = _getElement(config.selectors.buttons.mute);
+ plyr.buttons.captions = _getElement(config.selectors.buttons.captions);
// Progress
plyr.progress = {};
- plyr.progress.container = _getElement(config.selectors.progress.container);
+ plyr.progress.container = _getElement(config.selectors.progress.container);
// Progress - Buffering
- plyr.progress.buffer = {};
- plyr.progress.buffer.bar = _getElement(config.selectors.progress.buffer);
- plyr.progress.buffer.text = plyr.progress.buffer.bar && plyr.progress.buffer.bar.getElementsByTagName('span')[0];
+ plyr.progress.buffer = {};
+ plyr.progress.buffer.bar = _getElement(config.selectors.progress.buffer);
+ plyr.progress.buffer.text =
+ plyr.progress.buffer.bar && plyr.progress.buffer.bar.getElementsByTagName("span")[0];
// Progress - Played
- plyr.progress.played = _getElement(config.selectors.progress.played);
+ plyr.progress.played = _getElement(config.selectors.progress.played);
// Seek tooltip
- plyr.progress.tooltip = plyr.progress.container && plyr.progress.container.querySelector('.' + config.classes.tooltip);
+ plyr.progress.tooltip =
+ plyr.progress.container && plyr.progress.container.querySelector("." + config.classes.tooltip);
// Volume
- plyr.volume = {};
- plyr.volume.input = _getElement(config.selectors.volume.input);
- plyr.volume.display = _getElement(config.selectors.volume.display);
+ plyr.volume = {};
+ plyr.volume.input = _getElement(config.selectors.volume.input);
+ plyr.volume.display = _getElement(config.selectors.volume.display);
// Timing
- plyr.duration = _getElement(config.selectors.duration);
- plyr.currentTime = _getElement(config.selectors.currentTime);
- plyr.seekTime = _getElements(config.selectors.seekTime);
+ plyr.duration = _getElement(config.selectors.duration);
+ plyr.currentTime = _getElement(config.selectors.currentTime);
+ plyr.seekTime = _getElements(config.selectors.seekTime);
return true;
- }
- catch(e) {
- _warn('It looks like there is a problem with your controls HTML');
+ } catch (e) {
+ _warn("It looks like there is a problem with your controls HTML");
// Restore native video controls
_toggleNativeControls(true);
@@ -1385,15 +1487,15 @@
// Toggle style hook
function _toggleStyleHook() {
- _toggleClass(plyr.container, config.selectors.container.replace('.', ''), plyr.supported.full);
+ _toggleClass(plyr.container, config.selectors.container.replace(".", ""), plyr.supported.full);
}
// Toggle native controls
function _toggleNativeControls(toggle) {
if (toggle && _inArray(config.types.html5, plyr.type)) {
- plyr.media.setAttribute('controls', '');
+ plyr.media.setAttribute("controls", "");
} else {
- plyr.media.removeAttribute('controls');
+ plyr.media.removeAttribute("controls");
}
}
@@ -1404,23 +1506,23 @@
// If there's a media title set, use that for the label
if (_is.string(config.title) && config.title.length) {
- label += ', ' + config.title;
+ label += ", " + config.title;
// Set container label
- plyr.container.setAttribute('aria-label', config.title);
+ plyr.container.setAttribute("aria-label", config.title);
}
// If there's a play button, set label
if (plyr.supported.full && plyr.buttons.play) {
for (var i = plyr.buttons.play.length - 1; i >= 0; i--) {
- plyr.buttons.play[i].setAttribute('aria-label', label);
+ plyr.buttons.play[i].setAttribute("aria-label", label);
}
}
// Set iframe title
- // https://github.com/Selz/plyr/issues/124
+ // https://github.com/sampotts/plyr/issues/124
if (_is.htmlElement(iframe)) {
- iframe.setAttribute('title', config.i18n.frameTitle.replace('{title}', config.title));
+ iframe.setAttribute("title", config.i18n.frameTitle.replace("{title}", config.title));
}
}
@@ -1435,8 +1537,8 @@
}
// Clean up old volume
- // https://github.com/Selz/plyr/issues/171
- window.localStorage.removeItem('plyr-volume');
+ // https://github.com/sampotts/plyr/issues/171
+ window.localStorage.removeItem("plyr-volume");
// load value from the current key
value = window.localStorage.getItem(config.storage.key);
@@ -1446,9 +1548,9 @@
return;
} else if (/^\d+(\.\d+)?$/.test(value)) {
// If value is a number, it's probably volume from an older
- // version of plyr. See: https://github.com/Selz/plyr/pull/313
+ // version of plyr. See: https://github.com/sampotts/plyr/pull/313
// Update the key to be JSON
- _updateStorage({volume: parseFloat(value)});
+ _updateStorage({ volume: parseFloat(value) });
} else {
// Assume it's JSON from this or a later version of plyr
plyr.storage = JSON.parse(value);
@@ -1473,18 +1575,18 @@
function _setupMedia() {
// If there's no media, bail
if (!plyr.media) {
- _warn('No media element found!');
+ _warn("No media element found!");
return;
}
if (plyr.supported.full) {
// Add type class
- _toggleClass(plyr.container, config.classes.type.replace('{0}', plyr.type), true);
+ _toggleClass(plyr.container, config.classes.type.replace("{0}", plyr.type), true);
// Add video class for embeds
// This will require changes if audio embeds are added
if (_inArray(config.types.embed, plyr.type)) {
- _toggleClass(plyr.container, config.classes.type.replace('{0}', 'video'), true);
+ _toggleClass(plyr.container, config.classes.type.replace("{0}", "video"), true);
}
// If there's no autoplay attribute, assume the video is stopped and add state class
@@ -1497,10 +1599,10 @@
_toggleClass(plyr.container, config.classes.isTouch, plyr.browser.isTouch);
// Inject the player wrapper
- if (plyr.type === 'video') {
+ if (plyr.type === "video") {
// Create the wrapper div
- var wrapper = document.createElement('div');
- wrapper.setAttribute('class', config.classes.videoWrapper);
+ var wrapper = document.createElement("div");
+ wrapper.setAttribute("class", config.classes.videoWrapper);
// Wrap the video in a container
_wrap(plyr.media, wrapper);
@@ -1518,18 +1620,26 @@
// Setup YouTube/Vimeo
function _setupEmbed() {
- var container = document.createElement('div'),
+ var container = document.createElement("div"),
mediaId,
- id = plyr.type + '-' + Math.floor(Math.random() * (10000));
+ mediaUrl,
+ id = plyr.type + "-" + Math.floor(Math.random() * 10000);
// Parse IDs from URLs if supplied
switch (plyr.type) {
- case 'youtube':
+ case "youtube":
mediaId = _parseYouTubeId(plyr.embedId);
break;
- case 'vimeo':
- mediaId = _parseVimeoId(plyr.embedId);
+ case "vimeo":
+ if (_isVimeoUrl(plyr.embedId)) {
+ mediaId = null;
+ mediaUrl = plyr.embedId;
+ } else {
+ mediaId = parseInt(plyr.embedId);
+ mediaUrl = null;
+ }
+
break;
default:
@@ -1546,12 +1656,12 @@
_toggleClass(plyr.media, config.classes.videoWrapper, true);
_toggleClass(plyr.media, config.classes.embedWrapper, true);
- if (plyr.type === 'youtube') {
+ if (plyr.type === "youtube") {
// Create the YouTube container
plyr.media.appendChild(container);
// Set ID
- container.setAttribute('id', id);
+ container.setAttribute("id", id);
// Setup API
if (_is.object(window.YT)) {
@@ -1564,14 +1674,18 @@
window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];
// Add to queue
- window.onYouTubeReadyCallbacks.push(function() { _youTubeReady(mediaId, container); });
+ window.onYouTubeReadyCallbacks.push(function() {
+ _youTubeReady(mediaId, container);
+ });
// Set callback to process queue
- window.onYouTubeIframeAPIReady = function () {
- window.onYouTubeReadyCallbacks.forEach(function(callback) { callback(); });
+ window.onYouTubeIframeAPIReady = function() {
+ window.onYouTubeReadyCallbacks.forEach(function(callback) {
+ callback();
+ });
};
}
- } else if (plyr.type === 'vimeo') {
+ } else if (plyr.type === "vimeo") {
// Vimeo needs an extra div to hide controls on desktop (which has full support)
if (plyr.supported.full) {
plyr.media.appendChild(container);
@@ -1580,7 +1694,7 @@
}
// Set ID
- container.setAttribute('id', id);
+ container.setAttribute("id", id);
// Load the API if not already
if (!_is.object(window.Vimeo)) {
@@ -1590,24 +1704,26 @@
var vimeoTimer = window.setInterval(function() {
if (_is.object(window.Vimeo)) {
window.clearInterval(vimeoTimer);
- _vimeoReady(mediaId, container);
+ _vimeoReady(mediaId, mediaUrl, container);
}
}, 50);
} else {
- _vimeoReady(mediaId, container);
+ _vimeoReady(mediaId, mediaUrl, container);
}
- } else if (plyr.type === 'soundcloud') {
+ } else if (plyr.type === "soundcloud") {
// TODO: Currently unsupported and undocumented
// Inject the iframe
- var soundCloud = document.createElement('iframe');
+ var soundCloud = document.createElement("iframe");
// Watch for iframe load
soundCloud.loaded = false;
- _on(soundCloud, 'load', function() { soundCloud.loaded = true; });
+ _on(soundCloud, "load", function() {
+ soundCloud.loaded = true;
+ });
_setAttributes(soundCloud, {
- 'src': 'https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/' + mediaId,
- 'id': id
+ src: "https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/" + mediaId,
+ id: id
});
container.appendChild(soundCloud);
@@ -1637,7 +1753,7 @@
}
// Set title
- _setTitle(_getElement('iframe'));
+ _setTitle(_getElement("iframe"));
}
// Handle YouTube API ready
@@ -1647,26 +1763,26 @@
plyr.embed = new window.YT.Player(container.id, {
videoId: videoId,
playerVars: {
- autoplay: (config.autoplay ? 1 : 0),
- controls: (plyr.supported.full ? 0 : 1),
- rel: 0,
- showinfo: 0,
+ autoplay: config.autoplay ? 1 : 0,
+ controls: plyr.supported.full ? 0 : 1,
+ rel: 0,
+ showinfo: 0,
iv_load_policy: 3,
- cc_load_policy: (config.captions.defaultActive ? 1 : 0),
- cc_lang_pref: 'en',
- wmode: 'transparent',
+ cc_load_policy: config.captions.defaultActive ? 1 : 0,
+ cc_lang_pref: "en",
+ wmode: "transparent",
modestbranding: 1,
- disablekb: 1,
- origin: '*' // https://code.google.com/p/gdata-issues/issues/detail?id=5788#c45
+ disablekb: 1,
+ origin: "*" // https://code.google.com/p/gdata-issues/issues/detail?id=5788#c45
},
events: {
- 'onError': function(event) {
- _triggerEvent(plyr.container, 'error', true, {
- code: event.data,
- embed: event.target
+ onError: function(event) {
+ _triggerEvent(plyr.container, "error", true, {
+ code: event.data,
+ embed: event.target
});
},
- 'onReady': function(event) {
+ onReady: function(event) {
// Get the instance
var instance = event.target;
@@ -1693,17 +1809,17 @@
// Set the tabindex
if (plyr.supported.full) {
- plyr.media.querySelector('iframe').setAttribute('tabindex', '-1');
+ plyr.media.querySelector("iframe").setAttribute("tabindex", "-1");
}
// Update UI
_embedReady();
// Trigger timeupdate
- _triggerEvent(plyr.media, 'timeupdate');
+ _triggerEvent(plyr.media, "timeupdate");
// Trigger timeupdate
- _triggerEvent(plyr.media, 'durationchange');
+ _triggerEvent(plyr.media, "durationchange");
// Reset timer
window.clearInterval(timers.buffering);
@@ -1715,7 +1831,7 @@
// Trigger progress only when we actually buffer something
if (plyr.media.lastBuffered === null || plyr.media.lastBuffered < plyr.media.buffered) {
- _triggerEvent(plyr.media, 'progress');
+ _triggerEvent(plyr.media, "progress");
}
// Set last buffer point
@@ -1726,11 +1842,11 @@
window.clearInterval(timers.buffering);
// Trigger event
- _triggerEvent(plyr.media, 'canplaythrough');
+ _triggerEvent(plyr.media, "canplaythrough");
}
}, 200);
},
- 'onStateChange': function(event) {
+ onStateChange: function(event) {
// Get the instance
var instance = event.target;
@@ -1747,7 +1863,7 @@
switch (event.data) {
case 0:
plyr.media.paused = true;
- _triggerEvent(plyr.media, 'ended');
+ _triggerEvent(plyr.media, "ended");
break;
case 1:
@@ -1755,12 +1871,12 @@
// If we were seeking, fire seeked event
if (plyr.media.seeking) {
- _triggerEvent(plyr.media, 'seeked');
+ _triggerEvent(plyr.media, "seeked");
}
plyr.media.seeking = false;
- _triggerEvent(plyr.media, 'play');
- _triggerEvent(plyr.media, 'playing');
+ _triggerEvent(plyr.media, "play");
+ _triggerEvent(plyr.media, "playing");
// Poll to get playback progress
timers.playing = window.setInterval(function() {
@@ -1768,26 +1884,26 @@
plyr.media.currentTime = instance.getCurrentTime();
// Trigger timeupdate
- _triggerEvent(plyr.media, 'timeupdate');
+ _triggerEvent(plyr.media, "timeupdate");
}, 100);
// Check duration again due to YouTube bug
- // https://github.com/Selz/plyr/issues/374
+ // https://github.com/sampotts/plyr/issues/374
// https://code.google.com/p/gdata-issues/issues/detail?id=8690
if (plyr.media.duration !== instance.getDuration()) {
plyr.media.duration = instance.getDuration();
- _triggerEvent(plyr.media, 'durationchange');
+ _triggerEvent(plyr.media, "durationchange");
}
break;
case 2:
plyr.media.paused = true;
- _triggerEvent(plyr.media, 'pause');
+ _triggerEvent(plyr.media, "pause");
break;
}
- _triggerEvent(plyr.container, 'statechange', false, {
+ _triggerEvent(plyr.container, "statechange", false, {
code: event.data
});
}
@@ -1796,17 +1912,27 @@
}
// Vimeo ready
- function _vimeoReady(mediaId, container) {
+ function _vimeoReady(mediaId, mediaUrl, container) {
// Setup instance
// https://github.com/vimeo/player.js
- plyr.embed = new window.Vimeo.Player(container, {
- id: parseInt(mediaId),
+
+ var vimeoOptions = {
loop: config.loop,
autoplay: config.autoplay,
byline: false,
portrait: false,
title: false
- });
+ };
+
+ if (mediaId) {
+ vimeoOptions.id = mediaId;
+ }
+
+ if (mediaUrl) {
+ vimeoOptions.url = mediaUrl;
+ }
+
+ plyr.embed = new window.Vimeo.Player(container, vimeoOptions);
// Create a faux HTML5 API using the Vimeo API
plyr.media.play = function() {
@@ -1832,14 +1958,14 @@
plyr.media.currentTime = value;
// Trigger timeupdate
- _triggerEvent(plyr.media, 'timeupdate');
+ _triggerEvent(plyr.media, "timeupdate");
});
plyr.embed.getDuration().then(function(value) {
plyr.media.duration = value;
// Trigger timeupdate
- _triggerEvent(plyr.media, 'durationchange');
+ _triggerEvent(plyr.media, "durationchange");
});
// TODO: Captions
@@ -1847,50 +1973,50 @@
plyr.embed.enableTextTrack('en');
}*/
- plyr.embed.on('loaded', function() {
+ plyr.embed.on("loaded", function() {
// Fix keyboard focus issues
- // https://github.com/Selz/plyr/issues/317
+ // https://github.com/sampotts/plyr/issues/317
if (_is.htmlElement(plyr.embed.element) && plyr.supported.full) {
- plyr.embed.element.setAttribute('tabindex', '-1');
+ plyr.embed.element.setAttribute("tabindex", "-1");
}
});
- plyr.embed.on('play', function() {
+ plyr.embed.on("play", function() {
plyr.media.paused = false;
- _triggerEvent(plyr.media, 'play');
- _triggerEvent(plyr.media, 'playing');
+ _triggerEvent(plyr.media, "play");
+ _triggerEvent(plyr.media, "playing");
});
- plyr.embed.on('pause', function() {
+ plyr.embed.on("pause", function() {
plyr.media.paused = true;
- _triggerEvent(plyr.media, 'pause');
+ _triggerEvent(plyr.media, "pause");
});
- plyr.embed.on('timeupdate', function(data) {
+ plyr.embed.on("timeupdate", function(data) {
plyr.media.seeking = false;
plyr.media.currentTime = data.seconds;
- _triggerEvent(plyr.media, 'timeupdate');
+ _triggerEvent(plyr.media, "timeupdate");
});
- plyr.embed.on('progress', function(data) {
+ plyr.embed.on("progress", function(data) {
plyr.media.buffered = data.percent;
- _triggerEvent(plyr.media, 'progress');
+ _triggerEvent(plyr.media, "progress");
if (parseInt(data.percent) === 1) {
// Trigger event
- _triggerEvent(plyr.media, 'canplaythrough');
+ _triggerEvent(plyr.media, "canplaythrough");
}
});
- plyr.embed.on('seeked', function() {
+ plyr.embed.on("seeked", function() {
plyr.media.seeking = false;
- _triggerEvent(plyr.media, 'seeked');
- _triggerEvent(plyr.media, 'play');
+ _triggerEvent(plyr.media, "seeked");
+ _triggerEvent(plyr.media, "play");
});
- plyr.embed.on('ended', function() {
+ plyr.embed.on("ended", function() {
plyr.media.paused = true;
- _triggerEvent(plyr.media, 'ended');
+ _triggerEvent(plyr.media, "ended");
});
}
@@ -1920,7 +2046,7 @@
plyr.media.currentTime = 0;
plyr.embed.getDuration(function(value) {
- plyr.media.duration = value/1000;
+ plyr.media.duration = value / 1000;
// Update UI
_embedReady();
@@ -1930,53 +2056,53 @@
plyr.media.currentTime = value;
// Trigger timeupdate
- _triggerEvent(plyr.media, 'timeupdate');
+ _triggerEvent(plyr.media, "timeupdate");
});
plyr.embed.bind(window.SC.Widget.Events.PLAY, function() {
plyr.media.paused = false;
- _triggerEvent(plyr.media, 'play');
- _triggerEvent(plyr.media, 'playing');
+ _triggerEvent(plyr.media, "play");
+ _triggerEvent(plyr.media, "playing");
});
plyr.embed.bind(window.SC.Widget.Events.PAUSE, function() {
plyr.media.paused = true;
- _triggerEvent(plyr.media, 'pause');
+ _triggerEvent(plyr.media, "pause");
});
plyr.embed.bind(window.SC.Widget.Events.PLAY_PROGRESS, function(data) {
plyr.media.seeking = false;
- plyr.media.currentTime = data.currentPosition/1000;
- _triggerEvent(plyr.media, 'timeupdate');
+ plyr.media.currentTime = data.currentPosition / 1000;
+ _triggerEvent(plyr.media, "timeupdate");
});
plyr.embed.bind(window.SC.Widget.Events.LOAD_PROGRESS, function(data) {
plyr.media.buffered = data.loadProgress;
- _triggerEvent(plyr.media, 'progress');
+ _triggerEvent(plyr.media, "progress");
if (parseInt(data.loadProgress) === 1) {
// Trigger event
- _triggerEvent(plyr.media, 'canplaythrough');
+ _triggerEvent(plyr.media, "canplaythrough");
}
});
plyr.embed.bind(window.SC.Widget.Events.FINISH, function() {
plyr.media.paused = true;
- _triggerEvent(plyr.media, 'ended');
+ _triggerEvent(plyr.media, "ended");
});
});
}
// Play media
function _play() {
- if ('play' in plyr.media) {
+ if ("play" in plyr.media) {
plyr.media.play();
}
}
// Pause media
function _pause() {
- if ('pause' in plyr.media) {
+ if ("pause" in plyr.media) {
plyr.media.pause();
}
}
@@ -2018,16 +2144,16 @@
// Seek to time
// The input parameter can be an event or a number
function _seek(input) {
- var targetTime = 0,
- paused = plyr.media.paused,
- duration = _getDuration();
+ var targetTime = 0,
+ paused = plyr.media.paused,
+ duration = _getDuration();
if (_is.number(input)) {
targetTime = input;
- } else if (_is.object(input) && _inArray(['input', 'change'], input.type)) {
+ } else if (_is.object(input) && _inArray(["input", "change"], input.type)) {
// It's the seek slider
// Seek to the selected time
- targetTime = ((input.target.value / input.target.max) * duration);
+ targetTime = input.target.value / input.target.max * duration;
}
// Normalise targetTime
@@ -2044,22 +2170,21 @@
// Try/catch incase the media isn't set and we're calling seek() from source() and IE moans
try {
plyr.media.currentTime = targetTime.toFixed(4);
- }
- catch(e) {}
+ } catch (e) {}
// Embeds
if (_inArray(config.types.embed, plyr.type)) {
- switch(plyr.type) {
- case 'youtube':
+ switch (plyr.type) {
+ case "youtube":
plyr.embed.seekTo(targetTime);
break;
- case 'vimeo':
+ case "vimeo":
// Round to nearest second for vimeo
plyr.embed.setCurrentTime(targetTime.toFixed(0));
break;
- case 'soundcloud':
+ case "soundcloud":
plyr.embed.seekTo(targetTime * 1000);
break;
}
@@ -2069,17 +2194,17 @@
}
// Trigger timeupdate
- _triggerEvent(plyr.media, 'timeupdate');
+ _triggerEvent(plyr.media, "timeupdate");
// Set seeking flag
plyr.media.seeking = true;
// Trigger seeking
- _triggerEvent(plyr.media, 'seeking');
+ _triggerEvent(plyr.media, "seeking");
}
// Logging
- _log('Seeking to ' + plyr.media.currentTime + ' seconds');
+ _log("Seeking to " + plyr.media.currentTime + " seconds");
// Special handling for 'manual' captions
_seekManualCaptions(targetTime);
@@ -2089,9 +2214,8 @@
function _getDuration() {
// It should be a number, but parse it just incase
var duration = parseInt(config.duration),
-
- // True duration
- mediaDuration = 0;
+ // True duration
+ mediaDuration = 0;
// Only if duration available
if (plyr.media.duration !== null && !isNaN(plyr.media.duration)) {
@@ -2099,7 +2223,7 @@
}
// If custom duration is funky, use regular duration
- return (isNaN(duration) ? mediaDuration : duration);
+ return isNaN(duration) ? mediaDuration : duration;
}
// Check playing state
@@ -2156,7 +2280,7 @@
plyr.isFullscreen = !plyr.isFullscreen;
// Bind/unbind escape key
- document.body.style.overflow = plyr.isFullscreen ? 'hidden' : '';
+ document.body.style.overflow = plyr.isFullscreen ? "hidden" : "";
}
// Set class hook
@@ -2171,7 +2295,7 @@
}
// Trigger an event
- _triggerEvent(plyr.container, plyr.isFullscreen ? 'enterfullscreen' : 'exitfullscreen', true);
+ _triggerEvent(plyr.container, plyr.isFullscreen ? "enterfullscreen" : "exitfullscreen", true);
// Restore scroll position
if (!plyr.isFullscreen && nativeSupport) {
@@ -2200,19 +2324,19 @@
// Embeds
if (_inArray(config.types.embed, plyr.type)) {
// YouTube
- switch(plyr.type) {
- case 'youtube':
- plyr.embed[plyr.media.muted ? 'mute' : 'unMute']();
+ switch (plyr.type) {
+ case "youtube":
+ plyr.embed[plyr.media.muted ? "mute" : "unMute"]();
break;
- case 'vimeo':
- case 'soundcloud':
+ case "vimeo":
+ case "soundcloud":
plyr.embed.setVolume(plyr.media.muted ? 0 : parseFloat(config.volume / config.volumeMax));
break;
}
// Trigger volumechange for embeds
- _triggerEvent(plyr.media, 'volumechange');
+ _triggerEvent(plyr.media, "volumechange");
}
}
@@ -2250,19 +2374,19 @@
// Embeds
if (_inArray(config.types.embed, plyr.type)) {
- switch(plyr.type) {
- case 'youtube':
+ switch (plyr.type) {
+ case "youtube":
plyr.embed.setVolume(plyr.media.volume * 100);
break;
- case 'vimeo':
- case 'soundcloud':
+ case "vimeo":
+ case "soundcloud":
plyr.embed.setVolume(plyr.media.volume);
break;
}
// Trigger volumechange for embeds
- _triggerEvent(plyr.media, 'volumechange');
+ _triggerEvent(plyr.media, "volumechange");
}
// Toggle muted state
@@ -2275,7 +2399,7 @@
// Increase volume
function _increaseVolume(step) {
- var volume = plyr.media.muted ? 0 : (plyr.media.volume * config.volumeMax);
+ var volume = plyr.media.muted ? 0 : plyr.media.volume * config.volumeMax;
if (!_is.number(step)) {
step = config.volumeStep;
@@ -2286,7 +2410,7 @@
// Decrease volume
function _decreaseVolume(step) {
- var volume = plyr.media.muted ? 0 : (plyr.media.volume * config.volumeMax);
+ var volume = plyr.media.muted ? 0 : plyr.media.volume * config.volumeMax;
if (!_is.number(step)) {
step = config.volumeStep;
@@ -2298,7 +2422,7 @@
// Update volume UI and storage
function _updateVolume() {
// Get the current volume
- var volume = plyr.media.muted ? 0 : (plyr.media.volume * config.volumeMax);
+ var volume = plyr.media.muted ? 0 : plyr.media.volume * config.volumeMax;
// Update the <input type="range"> if present
if (plyr.supported.full) {
@@ -2311,14 +2435,14 @@
}
// Update the volume in storage
- _updateStorage({volume: volume});
+ _updateStorage({ volume: volume });
// Toggle class if muted
- _toggleClass(plyr.container, config.classes.muted, (volume === 0));
+ _toggleClass(plyr.container, config.classes.muted, volume === 0);
// Update checkbox for mute state
if (plyr.supported.full && plyr.buttons.mute) {
- _toggleState(plyr.buttons.mute, (volume === 0));
+ _toggleState(plyr.buttons.mute, volume === 0);
}
}
@@ -2331,7 +2455,7 @@
// If the method is called without parameter, toggle based on current value
if (!_is.boolean(show)) {
- show = (plyr.container.className.indexOf(config.classes.captions.active) === -1);
+ show = plyr.container.className.indexOf(config.classes.captions.active) === -1;
}
// Set global
@@ -2344,15 +2468,15 @@
_toggleClass(plyr.container, config.classes.captions.active, plyr.captionsEnabled);
// Trigger an event
- _triggerEvent(plyr.container, plyr.captionsEnabled ? 'captionsenabled' : 'captionsdisabled', true);
+ _triggerEvent(plyr.container, plyr.captionsEnabled ? "captionsenabled" : "captionsdisabled", true);
// Save captions state to localStorage
- _updateStorage({captionsEnabled: plyr.captionsEnabled});
+ _updateStorage({ captionsEnabled: plyr.captionsEnabled });
}
// Check if media is loading
function _checkLoading(event) {
- var loading = (event.type === 'waiting');
+ var loading = event.type === "waiting";
// Clear timer
clearTimeout(timers.loading);
@@ -2364,7 +2488,7 @@
// Show controls if loading, hide if done
_toggleControls(loading);
- }, (loading ? 250 : 0));
+ }, loading ? 250 : 0);
}
// Update <progress> elements
@@ -2373,15 +2497,15 @@
return;
}
- var progress = plyr.progress.played,
- value = 0,
- duration = _getDuration();
+ var progress = plyr.progress.played,
+ value = 0,
+ duration = _getDuration();
if (event) {
switch (event.type) {
// Video playing
- case 'timeupdate':
- case 'seeking':
+ case "timeupdate":
+ case "seeking":
if (plyr.controls.pressed) {
return;
}
@@ -2389,17 +2513,17 @@
value = _getPercentage(plyr.media.currentTime, duration);
// Set seek range value only if it's a 'natural' time event
- if (event.type === 'timeupdate' && plyr.buttons.seek) {
+ if (event.type === "timeupdate" && plyr.buttons.seek) {
plyr.buttons.seek.value = value;
}
break;
// Check buffer status
- case 'playing':
- case 'progress':
- progress = plyr.progress.buffer;
- value = (function() {
+ case "playing":
+ case "progress":
+ progress = plyr.progress.buffer;
+ value = (function() {
var buffered = plyr.media.buffered;
if (buffered && buffered.length) {
@@ -2407,7 +2531,7 @@
return _getPercentage(buffered.end(0), duration);
} else if (_is.number(buffered)) {
// YouTube returns between 0 and 1
- return (buffered * 100);
+ return buffered * 100;
}
return 0;
@@ -2468,17 +2592,17 @@
plyr.secs = parseInt(time % 60);
plyr.mins = parseInt((time / 60) % 60);
- plyr.hours = parseInt(((time / 60) / 60) % 60);
+ plyr.hours = parseInt((time / 60 / 60) % 60);
// Do we need to display hours?
- var displayHours = (parseInt(((_getDuration() / 60) / 60) % 60) > 0);
+ var displayHours = parseInt((_getDuration() / 60 / 60) % 60) > 0;
// Ensure it's two digits. For example, 03 rather than 3.
- plyr.secs = ('0' + plyr.secs).slice(-2);
- plyr.mins = ('0' + plyr.mins).slice(-2);
+ plyr.secs = ("0" + plyr.secs).slice(-2);
+ plyr.mins = ("0" + plyr.mins).slice(-2);
// Render
- element.innerHTML = (displayHours ? plyr.hours + ':' : '') + plyr.mins + ':' + plyr.secs;
+ element.innerHTML = (displayHours ? plyr.hours + ":" : "") + plyr.mins + ":" + plyr.secs;
}
// Show the duration on metadataloaded
@@ -2510,7 +2634,7 @@
_updateTimeDisplay(plyr.media.currentTime, plyr.currentTime);
// Ignore updates while seeking
- if (event && event.type === 'timeupdate' && plyr.media.seeking) {
+ if (event && event.type === "timeupdate" && plyr.media.seeking) {
return;
}
@@ -2525,8 +2649,8 @@
time = 0;
}
- var duration = _getDuration(),
- value = _getPercentage(time, duration);
+ var duration = _getDuration(),
+ value = _getPercentage(time, duration);
// Update progress
if (plyr.progress && plyr.progress.played) {
@@ -2549,19 +2673,19 @@
}
// Calculate percentage
- var clientRect = plyr.progress.container.getBoundingClientRect(),
- percent = 0,
- visible = config.classes.tooltip + '--visible';
+ var clientRect = plyr.progress.container.getBoundingClientRect(),
+ percent = 0,
+ visible = config.classes.tooltip + "--visible";
// Determine percentage, if already visible
if (!event) {
if (_hasClass(plyr.progress.tooltip, visible)) {
- percent = plyr.progress.tooltip.style.left.replace('%', '');
+ percent = plyr.progress.tooltip.style.left.replace("%", "");
} else {
return;
}
} else {
- percent = ((100 / clientRect.width) * (event.pageX - clientRect.left));
+ percent = 100 / clientRect.width * (event.pageX - clientRect.left);
}
// Set bounds
@@ -2572,22 +2696,22 @@
}
// Display the time a click would seek to
- _updateTimeDisplay(((duration / 100) * percent), plyr.progress.tooltip);
+ _updateTimeDisplay(duration / 100 * percent, plyr.progress.tooltip);
// Set position
plyr.progress.tooltip.style.left = percent + "%";
// Show/hide the tooltip
// If the event is a moues in/out and percentage is inside bounds
- if (event && _inArray(['mouseenter', 'mouseleave'], event.type)) {
- _toggleClass(plyr.progress.tooltip, visible, (event.type === 'mouseenter'));
+ if (event && _inArray(["mouseenter", "mouseleave"], event.type)) {
+ _toggleClass(plyr.progress.tooltip, visible, event.type === "mouseenter");
}
}
// Show the player controls in fullscreen mode
function _toggleControls(toggle) {
// Don't hide if config says not to, it's audio, or not ready or loading
- if (!config.hideControls || plyr.type === 'audio') {
+ if (!config.hideControls || plyr.type === "audio") {
return;
}
@@ -2600,18 +2724,18 @@
if (!_is.boolean(toggle)) {
if (toggle && toggle.type) {
// Is the enter fullscreen event
- isEnterFullscreen = (toggle.type === 'enterfullscreen');
+ isEnterFullscreen = toggle.type === "enterfullscreen";
// Whether to show controls
- show = _inArray(['mousemove', 'touchstart', 'mouseenter', 'focus'], toggle.type);
+ show = _inArray(["mousemove", "touchstart", "mouseenter", "focus"], toggle.type);
// Delay hiding on move events
- if (_inArray(['mousemove', 'touchmove'], toggle.type)) {
+ if (_inArray(["mousemove", "touchmove"], toggle.type)) {
delay = 2000;
}
// Delay a little more for keyboard users
- if (toggle.type === 'focus') {
+ if (toggle.type === "focus") {
delay = 3000;
}
} else {
@@ -2661,18 +2785,18 @@
// Return the current source
var url;
- switch(plyr.type) {
- case 'youtube':
+ switch (plyr.type) {
+ case "youtube":
url = plyr.embed.getVideoUrl();
break;
- case 'vimeo':
- plyr.embed.getVideoUrl.then(function (value) {
+ case "vimeo":
+ plyr.embed.getVideoUrl.then(function(value) {
url = value;
});
break;
- case 'soundcloud':
+ case "soundcloud":
plyr.embed.getCurrentSound(function(object) {
url = object.permalink_url;
});
@@ -2683,14 +2807,14 @@
break;
}
- return url || '';
+ return url || "";
}
// Update source
// Sources are not checked for support so be careful
function _updateSource(source) {
- if (!_is.object(source) || !('sources' in source) || !source.sources.length) {
- _warn('Invalid source format');
+ if (!_is.object(source) || !("sources" in source) || !source.sources.length) {
+ _warn("Invalid source format");
return;
}
@@ -2718,24 +2842,24 @@
_remove(plyr.media);
// Remove video container
- if (plyr.type === 'video' && plyr.videoContainer) {
+ if (plyr.type === "video" && plyr.videoContainer) {
_remove(plyr.videoContainer);
}
// Reset class name
if (plyr.container) {
- plyr.container.removeAttribute('class');
+ plyr.container.removeAttribute("class");
}
// Set the type
- if ('type' in source) {
+ if ("type" in source) {
plyr.type = source.type;
// Get child type for video (it might be an embed)
- if (plyr.type === 'video') {
+ if (plyr.type === "video") {
var firstSource = source.sources[0];
- if ('type' in firstSource && _inArray(config.types.embed, firstSource.type)) {
+ if ("type" in firstSource && _inArray(config.types.embed, firstSource.type)) {
plyr.type = firstSource.type;
}
}
@@ -2745,19 +2869,19 @@
plyr.supported = supported(plyr.type);
// Create new markup
- switch(plyr.type) {
- case 'video':
- plyr.media = document.createElement('video');
+ switch (plyr.type) {
+ case "video":
+ plyr.media = document.createElement("video");
break;
- case 'audio':
- plyr.media = document.createElement('audio');
+ case "audio":
+ plyr.media = document.createElement("audio");
break;
- case 'youtube':
- case 'vimeo':
- case 'soundcloud':
- plyr.media = document.createElement('div');
+ case "youtube":
+ case "vimeo":
+ case "soundcloud":
+ plyr.media = document.createElement("div");
plyr.embedId = source.sources[0].src;
break;
}
@@ -2773,16 +2897,16 @@
// Set attributes for audio and video
if (_inArray(config.types.html5, plyr.type)) {
if (config.crossorigin) {
- plyr.media.setAttribute('crossorigin', '');
+ plyr.media.setAttribute("crossorigin", "");
}
if (config.autoplay) {
- plyr.media.setAttribute('autoplay', '');
+ plyr.media.setAttribute("autoplay", "");
}
- if ('poster' in source) {
- plyr.media.setAttribute('poster', source.poster);
+ if ("poster" in source) {
+ plyr.media.setAttribute("poster", source.poster);
}
if (config.loop) {
- plyr.media.setAttribute('loop', '');
+ plyr.media.setAttribute("loop", "");
}
}
@@ -2793,7 +2917,7 @@
// Set new sources for html5
if (_inArray(config.types.html5, plyr.type)) {
- _insertChildElements('source', source.sources);
+ _insertChildElements("source", source.sources);
}
// Set up from scratch
@@ -2802,8 +2926,8 @@
// HTML5 stuff
if (_inArray(config.types.html5, plyr.type)) {
// Setup captions
- if ('tracks' in source) {
- _insertChildElements('track', source.tracks);
+ if ("tracks" in source) {
+ _insertChildElements("track", source.tracks);
}
// Load HTML5 sources
@@ -2811,7 +2935,10 @@
}
// If HTML5 or embed but not fully supported, setupInterface and call ready now
- if (_inArray(config.types.html5, plyr.type) || (_inArray(config.types.embed, plyr.type) && !plyr.supported.full)) {
+ if (
+ _inArray(config.types.html5, plyr.type) ||
+ (_inArray(config.types.embed, plyr.type) && !plyr.supported.full)
+ ) {
// Setup interface
_setupInterface();
@@ -2831,29 +2958,35 @@
// Update poster
function _updatePoster(source) {
- if (plyr.type === 'video') {
- plyr.media.setAttribute('poster', source);
+ if (plyr.type === "video") {
+ plyr.media.setAttribute("poster", source);
}
}
+ function onBodyClick() {
+ _toggleClass(_getElement('.' + config.classes.tabFocus), config.classes.tabFocus, false);
+ }
+
// Listen for control events
function _controlListeners() {
// IE doesn't support input event, so we fallback to change
- var inputEvent = (plyr.browser.isIE ? 'change' : 'input');
+ var inputEvent = plyr.browser.isIE ? "change" : "input";
// Click play/pause helper
function togglePlay() {
var play = _togglePlay();
// Determine which buttons
- var trigger = plyr.buttons[play ? 'play' : 'pause'],
- target = plyr.buttons[play ? 'pause' : 'play'];
+ var trigger = plyr.buttons[play ? "play" : "pause"],
+ target = plyr.buttons[play ? "pause" : "play"];
// Get the last play button to account for the large play button
- if (target && target.length > 1) {
- target = target[target.length - 1];
- } else {
- target = target[0];
+ if (target) {
+ if (target.length > 1) {
+ target = target[target.length - 1];
+ } else {
+ target = target[0];
+ }
}
// Setup focus and tab focus
@@ -2878,7 +3011,7 @@
if (!focused || focused === document.body) {
focused = null;
} else {
- focused = document.querySelector(':focus');
+ focused = document.querySelector(":focus");
}
return focused;
@@ -2896,10 +3029,10 @@
if (_is.nodeList(element)) {
for (var i = 0; i < element.length; i++) {
- _toggleClass(element[i], config.classes.tabFocus, (element[i] === focused));
+ _toggleClass(element[i], config.classes.tabFocus, element[i] === focused);
}
} else {
- _toggleClass(element, config.classes.tabFocus, (element === focused));
+ _toggleClass(element, config.classes.tabFocus, element === focused);
}
}
}
@@ -2910,29 +3043,33 @@
// Handle global presses
if (config.keyboardShorcuts.global) {
- _on(window, 'keydown keyup', function(event) {
+ _on(window, "keydown keyup", function(event) {
var code = getKeyCode(event),
- focused = getFocusElement(),
- allowed = [48,49,50,51,52,53,54,56,57,75,77,70,67],
- count = get().length;
+ focused = getFocusElement(),
+ allowed = [48, 49, 50, 51, 52, 53, 54, 56, 57, 75, 77, 70, 67],
+ count = get().length;
// Only handle global key press if there's only one player
// and the key is in the allowed keys
// and if the focused element is not editable (e.g. text input)
// and any that accept key input http://webaim.org/techniques/keyboard/
- if (count === 1 && _inArray(allowed, code) && (!_is.htmlElement(focused) || !_matches(focused, config.selectors.editable))) {
+ if (
+ count === 1 &&
+ _inArray(allowed, code) &&
+ (!_is.htmlElement(focused) || !_matches(focused, config.selectors.editable))
+ ) {
handleKey(event);
}
});
}
// Handle presses on focused
- _on(plyr.container, 'keydown keyup', handleKey);
+ _on(plyr.container, "keydown keyup", handleKey);
}
function handleKey(event) {
var code = getKeyCode(event),
- pressed = event.type === 'keydown',
+ pressed = event.type === "keydown",
held = pressed && code === last;
// If the event is bubbled from the media element
@@ -2952,14 +3089,14 @@
}
// Divide the max duration into 10th's and times by the number value
- _seek((duration / 10) * (code - 48));
+ _seek(duration / 10 * (code - 48));
}
// Handle the key on keydown
// Reset on keyup
if (pressed) {
// Which keycodes should we prevent default
- var preventDefault = [48,49,50,51,52,53,54,56,57,32,75,38,40,77,39,37,70,67];
+ var preventDefault = [48, 49, 50, 51, 52, 53, 54, 56, 57, 32, 75, 38, 40, 77, 39, 37, 70, 67];
// If the code is found prevent default (e.g. prevent scrolling for arrows)
if (_inArray(preventDefault, code)) {
@@ -2967,7 +3104,7 @@
event.stopPropagation();
}
- switch(code) {
+ switch (code) {
// 0-9
case 48:
case 49:
@@ -2978,24 +3115,50 @@
case 54:
case 55:
case 56:
- case 57: if (!held) { seekByKey(); } break;
+ case 57:
+ if (!held) {
+ seekByKey();
+ }
+ break;
// Space and K key
case 32:
- case 75: if (!held) { _togglePlay(); } break;
+ case 75:
+ if (!held) {
+ _togglePlay();
+ }
+ break;
// Arrow up
- case 38: _increaseVolume(); break;
+ case 38:
+ _increaseVolume();
+ break;
// Arrow down
- case 40: _decreaseVolume(); break;
+ case 40:
+ _decreaseVolume();
+ break;
// M key
- case 77: if (!held) { _toggleMute() } break;
+ case 77:
+ if (!held) {
+ _toggleMute();
+ }
+ break;
// Arrow forward
- case 39: _forward(); break;
+ case 39:
+ _forward();
+ break;
// Arrow back
- case 37: _rewind(); break;
+ case 37:
+ _rewind();
+ break;
// F key
- case 70: _toggleFullscreen(); break;
+ case 70:
+ _toggleFullscreen();
+ break;
// C key
- case 67: if (!held) { _toggleCaptions(); } break;
+ case 67:
+ if (!held) {
+ _toggleCaptions();
+ }
+ break;
}
// Escape is handle natively when in full screen
@@ -3012,7 +3175,7 @@
}
// Focus/tab management
- _on(window, 'keyup', function(event) {
+ _on(window, "keyup", function(event) {
var code = getKeyCode(event),
focused = getFocusElement();
@@ -3020,31 +3183,29 @@
checkTabFocus(focused);
}
});
- _on(document.body, 'click', function() {
- _toggleClass(_getElement('.' + config.classes.tabFocus), config.classes.tabFocus, false);
- });
+ _on(document.body, "click", onBodyClick);
for (var button in plyr.buttons) {
var element = plyr.buttons[button];
- _on(element, 'blur', function() {
- _toggleClass(element, 'tab-focus', false);
+ _on(element, "blur", function() {
+ _toggleClass(element, "tab-focus", false);
});
}
// Play
- _proxyListener(plyr.buttons.play, 'click', config.listeners.play, togglePlay);
+ _proxyListener(plyr.buttons.play, "click", config.listeners.play, togglePlay);
// Pause
- _proxyListener(plyr.buttons.pause, 'click', config.listeners.pause, togglePlay);
+ _proxyListener(plyr.buttons.pause, "click", config.listeners.pause, togglePlay);
// Restart
- _proxyListener(plyr.buttons.restart, 'click', config.listeners.restart, _seek);
+ _proxyListener(plyr.buttons.restart, "click", config.listeners.restart, _seek);
// Rewind
- _proxyListener(plyr.buttons.rewind, 'click', config.listeners.rewind, _rewind);
+ _proxyListener(plyr.buttons.rewind, "click", config.listeners.rewind, _rewind);
// Fast forward
- _proxyListener(plyr.buttons.forward, 'click', config.listeners.forward, _forward);
+ _proxyListener(plyr.buttons.forward, "click", config.listeners.forward, _forward);
// Seek
_proxyListener(plyr.buttons.seek, inputEvent, config.listeners.seek, _seek);
@@ -3055,10 +3216,10 @@
});
// Mute
- _proxyListener(plyr.buttons.mute, 'click', config.listeners.mute, _toggleMute);
+ _proxyListener(plyr.buttons.mute, "click", config.listeners.mute, _toggleMute);
// Fullscreen
- _proxyListener(plyr.buttons.fullscreen, 'click', config.listeners.fullscreen, _toggleFullscreen);
+ _proxyListener(plyr.buttons.fullscreen, "click", config.listeners.fullscreen, _toggleFullscreen);
// Handle user exiting fullscreen by escaping etc
if (fullscreen.supportsFullScreen) {
@@ -3066,38 +3227,42 @@
}
// Captions
- _proxyListener(plyr.buttons.captions, 'click', config.listeners.captions, _toggleCaptions);
+ _proxyListener(plyr.buttons.captions, "click", config.listeners.captions, _toggleCaptions);
// Seek tooltip
- _on(plyr.progress.container, 'mouseenter mouseleave mousemove', _updateSeekTooltip);
+ _on(plyr.progress.container, "mouseenter mouseleave mousemove", _updateSeekTooltip);
// Toggle controls visibility based on mouse movement
if (config.hideControls) {
// Toggle controls on mouse events and entering fullscreen
- _on(plyr.container, 'mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen', _toggleControls);
+ _on(
+ plyr.container,
+ "mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen",
+ _toggleControls
+ );
// Watch for cursor over controls so they don't hide when trying to interact
- _on(plyr.controls, 'mouseenter mouseleave', function(event) {
- plyr.controls.hover = event.type === 'mouseenter';
+ _on(plyr.controls, "mouseenter mouseleave", function(event) {
+ plyr.controls.hover = event.type === "mouseenter";
});
- // Watch for cursor over controls so they don't hide when trying to interact
- _on(plyr.controls, 'mousedown mouseup touchstart touchend touchcancel', function(event) {
- plyr.controls.pressed = _inArray(['mousedown', 'touchstart'], event.type);
+ // Watch for cursor over controls so they don't hide when trying to interact
+ _on(plyr.controls, "mousedown mouseup touchstart touchend touchcancel", function(event) {
+ plyr.controls.pressed = _inArray(["mousedown", "touchstart"], event.type);
});
// Focus in/out on controls
- _on(plyr.controls, 'focus blur', _toggleControls, true);
+ _on(plyr.controls, "focus blur", _toggleControls, true);
}
// Adjust volume on scroll
- _on(plyr.volume.input, 'wheel', function(event) {
+ _on(plyr.volume.input, "wheel", function(event) {
event.preventDefault();
// Detect "natural" scroll - suppored on OS X Safari only
// Other browsers on OS X will be inverted until support improves
var inverted = event.webkitDirectionInvertedFromDevice,
- step = (config.volumeStep / 5);
+ step = config.volumeStep / 5;
// Scroll down (or up on natural) to decrease
if (event.deltaY < 0 || event.deltaX > 0) {
@@ -3122,20 +3287,20 @@
// Listen for media events
function _mediaListeners() {
// Time change on media
- _on(plyr.media, 'timeupdate seeking', _timeUpdate);
+ _on(plyr.media, "timeupdate seeking", _timeUpdate);
// Update manual captions
- _on(plyr.media, 'timeupdate', _seekManualCaptions);
+ _on(plyr.media, "timeupdate", _seekManualCaptions);
// Display duration
- _on(plyr.media, 'durationchange loadedmetadata', _displayDuration);
+ _on(plyr.media, "durationchange loadedmetadata", _displayDuration);
// Handle the media finishing
- _on(plyr.media, 'ended', function() {
+ _on(plyr.media, "ended", function() {
// Show poster on end
- if (plyr.type === 'video' && config.showPosterOnEnd) {
+ if (plyr.type === "video" && config.showPosterOnEnd) {
// Clear
- if (plyr.type === 'video') {
+ if (plyr.type === "video") {
_setCaption();
}
@@ -3148,21 +3313,21 @@
});
// Check for buffer progress
- _on(plyr.media, 'progress playing', _updateProgress);
+ _on(plyr.media, "progress playing", _updateProgress);
// Handle native mute
- _on(plyr.media, 'volumechange', _updateVolume);
+ _on(plyr.media, "volumechange", _updateVolume);
// Handle native play/pause
- _on(plyr.media, 'play pause ended', _checkPlaying);
+ _on(plyr.media, "play pause ended", _checkPlaying);
// Loading
- _on(plyr.media, 'waiting canplay seeked', _checkLoading);
+ _on(plyr.media, "waiting canplay seeked", _checkLoading);
// Click video
- if (config.clickToPlay && plyr.type !== 'audio') {
+ if (config.clickToPlay && plyr.type !== "audio") {
// Re-fetch the wrapper
- var wrapper = _getElement('.' + config.classes.videoWrapper);
+ var wrapper = _getElement("." + config.classes.videoWrapper);
// Bail if there's no wrapper (this should never happen)
if (!wrapper) {
@@ -3173,7 +3338,7 @@
wrapper.style.cursor = "pointer";
// On click play, pause ore restart
- _on(wrapper, 'click', function() {
+ _on(wrapper, "click", function() {
// Touch devices will just show controls (if we're hiding controls)
if (config.hideControls && plyr.browser.isTouch && !plyr.media.paused) {
return;
@@ -3192,25 +3357,27 @@
// Disable right click
if (config.disableContextMenu) {
- _on(plyr.media, 'contextmenu', function(event) { event.preventDefault(); });
+ _on(plyr.media, "contextmenu", function(event) {
+ event.preventDefault();
+ });
}
// Proxy events to container
// Bubble up key events for Edge
- _on(plyr.media, config.events.concat(['keyup', 'keydown']).join(' '), function(event) {
+ _on(plyr.media, config.events.concat(["keyup", "keydown"]).join(" "), function(event) {
_triggerEvent(plyr.container, event.type, true);
});
}
// Cancel current network requests
- // See https://github.com/Selz/plyr/issues/174
+ // See https://github.com/sampotts/plyr/issues/174
function _cancelRequests() {
if (!_inArray(config.types.html5, plyr.type)) {
return;
}
// Remove child sources
- var sources = plyr.media.querySelectorAll('source');
+ var sources = plyr.media.querySelectorAll("source");
for (var i = 0; i < sources.length; i++) {
_remove(sources[i]);
}
@@ -3218,15 +3385,15 @@
// 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
- plyr.media.setAttribute('src', config.blankUrl);
+ plyr.media.setAttribute("src", config.blankUrl);
// Load the new empty source
// This will cancel existing requests
- // See https://github.com/Selz/plyr/issues/174
+ // See https://github.com/sampotts/plyr/issues/174
plyr.media.load();
// Debugging
- _log('Cancelled network requests');
+ _log("Cancelled network requests");
}
// Destroy an instance
@@ -3240,7 +3407,7 @@
// Type specific stuff
switch (plyr.type) {
- case 'youtube':
+ case "youtube":
// Clear timers
window.clearInterval(timers.buffering);
window.clearInterval(timers.playing);
@@ -3253,7 +3420,7 @@
break;
- case 'vimeo':
+ case "vimeo":
// Destroy Vimeo API
// then clean up (wait, to prevent postmessage errors)
plyr.embed.unload().then(cleanUp);
@@ -3263,8 +3430,8 @@
break;
- case 'video':
- case 'audio':
+ case "video":
+ case "audio":
// Restore native video controls
_toggleNativeControls(true);
@@ -3298,11 +3465,17 @@
// Replace the container with the original element provided
plyr.container.parentNode.replaceChild(original, plyr.container);
+ // Free container in order for GC to remove it and prevent memory leaks due to added events
+ plyr.container = null;
+
// Allow overflow (set on fullscreen)
- document.body.style.overflow = '';
+ document.body.style.overflow = "";
+
+ //remove events
+ _off(document.body, 'click', onBodyClick);
// Event
- _triggerEvent(original, 'destroyed', true);
+ _triggerEvent(original, "destroyed", true);
}
}
@@ -3330,18 +3503,18 @@
// Set media type based on tag or data attribute
// Supported: video, audio, vimeo, youtube
var tagName = media.tagName.toLowerCase();
- if (tagName === 'div') {
- plyr.type = media.getAttribute('data-type');
- plyr.embedId = media.getAttribute('data-video-id');
+ if (tagName === "div") {
+ plyr.type = media.getAttribute("data-type");
+ plyr.embedId = media.getAttribute("data-video-id");
// Clean up
- media.removeAttribute('data-type');
- media.removeAttribute('data-video-id');
+ media.removeAttribute("data-type");
+ media.removeAttribute("data-video-id");
} else {
- plyr.type = tagName;
- config.crossorigin = (media.getAttribute('crossorigin') !== null);
- config.autoplay = (config.autoplay || (media.getAttribute('autoplay') !== null));
- config.loop = (config.loop || (media.getAttribute('loop') !== null));
+ plyr.type = tagName;
+ config.crossorigin = media.getAttribute("crossorigin") !== null;
+ config.autoplay = config.autoplay || media.getAttribute("autoplay") !== null;
+ config.loop = config.loop || media.getAttribute("loop") !== null;
}
// Check for support
@@ -3353,23 +3526,26 @@
}
// Wrap media
- plyr.container = _wrap(media, document.createElement('div'));
+ plyr.container = _wrap(media, document.createElement("div"));
// Allow focus to be captured
- plyr.container.setAttribute('tabindex', 0);
+ plyr.container.setAttribute("tabindex", 0);
// Add style hook
_toggleStyleHook();
// Debug info
- _log('' + plyr.browser.name + ' ' + plyr.browser.version);
+ _log("" + plyr.browser.name + " " + plyr.browser.version);
// Setup media
_setupMedia();
// Setup interface
// If embed but not fully supported, setupInterface (to avoid flash of controls) and call ready now
- if (_inArray(config.types.html5, plyr.type) || (_inArray(config.types.embed, plyr.type) && !plyr.supported.full)) {
+ if (
+ _inArray(config.types.html5, plyr.type) ||
+ (_inArray(config.types.embed, plyr.type) && !plyr.supported.full)
+ ) {
// Setup UI
_setupInterface();
@@ -3388,7 +3564,7 @@
function _setupInterface() {
// Don't setup interface if no support
if (!plyr.supported.full) {
- _warn('Basic support only', plyr.type);
+ _warn("Basic support only", plyr.type);
// Remove controls
_remove(_getElement(config.selectors.controls.wrapper));
@@ -3441,47 +3617,82 @@
// Update the UI
_checkPlaying();
+
+ // Display duration
+ _displayDuration();
}
api = {
- getOriginal: function() { return original; },
- getContainer: function() { return plyr.container },
- getEmbed: function() { return plyr.embed; },
- getMedia: function() { return plyr.media; },
- getType: function() { return plyr.type; },
- getDuration: _getDuration,
- getCurrentTime: function() { return plyr.media.currentTime; },
- getVolume: function() { return plyr.media.volume; },
- isMuted: function() { return plyr.media.muted; },
- isReady: function() { return _hasClass(plyr.container, config.classes.ready); },
- isLoading: function() { return _hasClass(plyr.container, config.classes.loading); },
- isPaused: function() { return plyr.media.paused; },
- on: function(event, callback) { _on(plyr.container, event, callback); return this; },
- play: _play,
- pause: _pause,
- stop: function() { _pause(); _seek(); },
- restart: _seek,
- rewind: _rewind,
- forward: _forward,
- seek: _seek,
- source: _source,
- poster: _updatePoster,
- setVolume: _setVolume,
- togglePlay: _togglePlay,
- toggleMute: _toggleMute,
- toggleCaptions: _toggleCaptions,
- toggleFullscreen: _toggleFullscreen,
- toggleControls: _toggleControls,
- isFullscreen: function() { return plyr.isFullscreen || false; },
- support: function(mimeType) { return _supportMime(plyr, mimeType); },
- destroy: _destroy
+ getOriginal: function() {
+ return original;
+ },
+ getContainer: function() {
+ return plyr.container;
+ },
+ getEmbed: function() {
+ return plyr.embed;
+ },
+ getMedia: function() {
+ return plyr.media;
+ },
+ getType: function() {
+ return plyr.type;
+ },
+ getDuration: _getDuration,
+ getCurrentTime: function() {
+ return plyr.media.currentTime;
+ },
+ getVolume: function() {
+ return plyr.media.volume;
+ },
+ isMuted: function() {
+ return plyr.media.muted;
+ },
+ isReady: function() {
+ return _hasClass(plyr.container, config.classes.ready);
+ },
+ isLoading: function() {
+ return _hasClass(plyr.container, config.classes.loading);
+ },
+ isPaused: function() {
+ return plyr.media.paused;
+ },
+ on: function(event, callback) {
+ _on(plyr.container, event, callback);
+ return this;
+ },
+ play: _play,
+ pause: _pause,
+ stop: function() {
+ _pause();
+ _seek();
+ },
+ restart: _seek,
+ rewind: _rewind,
+ forward: _forward,
+ seek: _seek,
+ source: _source,
+ poster: _updatePoster,
+ setVolume: _setVolume,
+ togglePlay: _togglePlay,
+ toggleMute: _toggleMute,
+ toggleCaptions: _toggleCaptions,
+ toggleFullscreen: _toggleFullscreen,
+ toggleControls: _toggleControls,
+ isFullscreen: function() {
+ return plyr.isFullscreen || false;
+ },
+ support: function(mimeType) {
+ return _supportMime(plyr, mimeType);
+ },
+ destroy: _destroy
};
// Everything done
function _ready() {
// Ready event at end of execution stack
window.setTimeout(function() {
- _triggerEvent(plyr.media, 'ready');
+ _triggerEvent(plyr.media, "ready");
}, 0);
// Set class hook on media element
@@ -3515,21 +3726,21 @@
var x = new XMLHttpRequest();
// If the id is set and sprite exists, bail
- if (_is.string(id) && _is.htmlElement(document.querySelector('#' + id))) {
+ if (_is.string(id) && _is.htmlElement(document.querySelector("#" + id))) {
return;
}
// Create placeholder (to prevent loading twice)
- var container = document.createElement('div');
- container.setAttribute('hidden', '');
+ var container = document.createElement("div");
+ container.setAttribute("hidden", "");
if (_is.string(id)) {
- container.setAttribute('id', id);
+ container.setAttribute("id", id);
}
document.body.insertBefore(container, document.body.childNodes[0]);
// Check for CORS support
- if ('withCredentials' in x) {
- x.open('GET', url, true);
+ if ("withCredentials" in x) {
+ x.open("GET", url, true);
} else {
return;
}
@@ -3537,43 +3748,43 @@
// Inject hidden div with sprite on load
x.onload = function() {
container.innerHTML = x.responseText;
- }
+ };
x.send();
}
// Check for support
function supported(type) {
- var browser = _browserSniff(),
- isOldIE = (browser.isIE && browser.version <= 9),
- isIos = browser.isIos,
- isIphone = browser.isIphone,
- audioSupport = !!document.createElement('audio').canPlayType,
- videoSupport = !!document.createElement('video').canPlayType,
- basic = false,
- full = false;
+ var browser = _browserSniff(),
+ isOldIE = browser.isIE && browser.version <= 9,
+ isIos = browser.isIos,
+ isIphone = browser.isIphone,
+ audioSupport = !!document.createElement("audio").canPlayType,
+ videoSupport = !!document.createElement("video").canPlayType,
+ basic = false,
+ full = false;
switch (type) {
- case 'video':
+ case "video":
basic = videoSupport;
- full = (basic && (!isOldIE && !isIphone));
+ full = basic && (!isOldIE && !isIphone);
break;
- case 'audio':
+ case "audio":
basic = audioSupport;
- full = (basic && !isOldIE);
+ full = basic && !isOldIE;
break;
// Vimeo does not seem to be supported on iOS via API
// Issue raised https://github.com/vimeo/player.js/issues/87
- case 'vimeo':
+ case "vimeo":
basic = true;
- full = (!isOldIE && !isIos);
+ full = !isOldIE && !isIos;
break;
- case 'youtube':
+ case "youtube":
basic = true;
- full = (!isOldIE && !isIos);
+ full = !isOldIE && !isIos;
// YouTube seems to work on iOS 10+ on iPad
if (isIos && !isIphone && browser.version >= 10) {
@@ -3582,37 +3793,37 @@
break;
- case 'soundcloud':
+ case "soundcloud":
basic = true;
- full = (!isOldIE && !isIphone);
+ full = !isOldIE && !isIphone;
break;
default:
- basic = (audioSupport && videoSupport);
- full = (basic && !isOldIE);
+ basic = audioSupport && videoSupport;
+ full = basic && !isOldIE;
}
return {
- basic: basic,
- full: full
+ basic: basic,
+ full: full
};
}
// Setup function
function setup(targets, options) {
// Get the players
- var players = [],
- instances = [],
- selector = [defaults.selectors.html5, defaults.selectors.embed].join(',');
+ var players = [],
+ instances = [],
+ selector = [defaults.selectors.html5, defaults.selectors.embed].join(",");
// Select the elements
if (_is.string(targets)) {
// String selector passed
targets = document.querySelectorAll(targets);
- } else if (_is.htmlElement(targets)) {
+ } else if (_is.htmlElement(targets)) {
// Single HTMLElement passed
targets = [targets];
- } else if (!_is.nodeList(targets) && !_is.array(targets) && !_is.string(targets)) {
+ } else if (!_is.nodeList(targets) && !_is.array(targets) && !_is.string(targets)) {
// No selector passed, possibly options as first argument
// If options are the first argument
if (_is.undefined(options) && _is.object(targets)) {
@@ -3641,9 +3852,9 @@
// Always wrap in a <div> for styling
//container: _wrap(media, document.createElement('div')),
// Could be a container or the media itself
- target: target,
+ target: target,
// This should be the <video>, <audio> or <div> (YouTube/Vimeo)
- media: media
+ media: media
});
}
}
@@ -3668,9 +3879,9 @@
// Create a player instance for each element
players.forEach(function(player) {
- var element = player.target,
- media = player.media,
- match = false;
+ var element = player.target,
+ media = player.media,
+ match = false;
// The target element can also be the media element
if (media === element) {
@@ -3682,8 +3893,9 @@
var data = {};
// Try parsing data attribute config
- try { data = JSON.parse(element.getAttribute('data-plyr')); }
- catch(e) { }
+ try {
+ data = JSON.parse(element.getAttribute("data-plyr"));
+ } catch (e) {}
var config = _extend({}, defaults, options, data);
@@ -3702,15 +3914,22 @@
// Listen for events if debugging
if (config.debug) {
- var events = config.events.concat(['setup', 'statechange', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled']);
-
- _on(instance.getContainer(), events.join(' '), function(event) {
- console.log([config.logPrefix, 'event:', event.type].join(' '), event.detail.plyr);
+ var events = config.events.concat([
+ "setup",
+ "statechange",
+ "enterfullscreen",
+ "exitfullscreen",
+ "captionsenabled",
+ "captionsdisabled"
+ ]);
+
+ _on(instance.getContainer(), events.join(" "), function(event) {
+ console.log([config.logPrefix, "event:", event.type].join(" "), event.detail.plyr);
});
}
// Callback
- _event(instance.getContainer(), 'setup', true, {
+ _event(instance.getContainer(), "setup", true, {
plyr: instance
});
@@ -3733,7 +3952,7 @@
// If we have a HTML element
if (_is.htmlElement(container)) {
- var elements = container.querySelectorAll('.' + defaults.classes.setup),
+ var elements = container.querySelectorAll("." + defaults.classes.setup),
instances = [];
Array.prototype.slice.call(elements).forEach(function(element) {
@@ -3749,23 +3968,23 @@
}
return {
- setup: setup,
- supported: supported,
+ setup: setup,
+ supported: supported,
loadSprite: loadSprite,
- get: get
+ get: get
};
-}));
+});
// Custom event polyfill
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
-(function () {
- if (typeof window.CustomEvent === 'function') {
+(function() {
+ if (typeof window.CustomEvent === "function") {
return;
}
function CustomEvent(event, params) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
- var evt = document.createEvent('CustomEvent');
+ var evt = document.createEvent("CustomEvent");
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
return evt;
}
diff --git a/src/less/plyr.less b/src/less/plyr.less
index c9e3d7c3..3b1c21b6 100644
--- a/src/less/plyr.less
+++ b/src/less/plyr.less
@@ -9,7 +9,9 @@
// Animation
// ---------------------------------------
@keyframes plyr-progress {
- to { background-position: @plyr-progress-loading-size 0; }
+ to {
+ background-position: @plyr-progress-loading-size 0;
+ }
}
// Styles
@@ -35,7 +37,10 @@
& when (@plyr-touch-action = true) {
// Fix 300ms delay
- a, button, input, label {
+ a,
+ button,
+ input,
+ label {
touch-action: manipulation;
}
}
@@ -56,7 +61,7 @@
// Range inputs
// Specificity is for bootstrap compatibility
- input[type='range'] {
+ input[type="range"] {
display: block;
height: (@plyr-range-thumb-height * @plyr-range-thumb-active-scale);
width: 100%;
@@ -137,12 +142,12 @@
}
// Video range inputs
-.plyr--video input[type='range'].tab-focus:focus {
+.plyr--video input[type="range"].tab-focus:focus {
outline: 1px dotted fade(@plyr-video-control-color, 50%);
}
// Audio range inputs
-.plyr--audio input[type='range'].tab-focus:focus {
+.plyr--audio input[type="range"].tab-focus:focus {
outline: 1px dotted fade(@plyr-audio-control-color, 50%);
}
@@ -221,7 +226,7 @@
width: 100%;
padding: (@plyr-control-spacing * 2);
transform: translateY(-(@plyr-control-spacing * 4));
- transition: transform .3s ease;
+ transition: transform 0.3s ease;
color: @plyr-captions-color;
font-size: @plyr-font-size-captions-base;
text-align: center;
@@ -268,6 +273,11 @@
align-items: center;
line-height: 1;
text-align: center;
+ pointer-events: none;
+
+ & > * {
+ pointer-events: all;
+ }
// Spacing
> button,
@@ -298,7 +308,7 @@
background: transparent;
border-radius: 3px;
cursor: pointer;
- transition: background .3s ease, color .3s ease, opacity .3s ease;
+ transition: background 0.3s ease, color 0.3s ease, opacity 0.3s ease;
color: inherit;
svg {
@@ -347,7 +357,7 @@
border-bottom-left-radius: inherit;
border-bottom-right-radius: inherit;
color: @plyr-video-control-color;
- transition: opacity .3s ease;
+ transition: opacity 0.3s ease;
button {
// Hover and tab focus
@@ -391,7 +401,7 @@
border-radius: 100%;
box-shadow: 0 1px 1px fade(#000, 15%);
color: @plyr-video-control-color;
- transition: all .3s ease;
+ transition: all 0.3s ease;
svg {
position: relative;
@@ -418,11 +428,11 @@
}
// States
-.plyr__controls [data-plyr='pause'],
-.plyr--playing .plyr__controls [data-plyr='play'] {
+.plyr__controls [data-plyr="pause"],
+.plyr--playing .plyr__controls [data-plyr="play"] {
display: none;
}
-.plyr--playing .plyr__controls [data-plyr='pause'] {
+.plyr--playing .plyr__controls [data-plyr="pause"] {
display: inline-block;
}
@@ -438,12 +448,12 @@
}
// Some options are hidden by default
-.plyr [data-plyr='captions'],
-.plyr [data-plyr='fullscreen'] {
+.plyr [data-plyr="captions"],
+.plyr [data-plyr="fullscreen"] {
display: none;
}
-.plyr--captions-enabled [data-plyr='captions'],
-.plyr--fullscreen-enabled [data-plyr='fullscreen'] {
+.plyr--captions-enabled [data-plyr="captions"],
+.plyr--fullscreen-enabled [data-plyr="fullscreen"] {
display: inline-block;
}
@@ -465,13 +475,13 @@
font-size: @plyr-font-size-small;
line-height: 1.3;
- transform: translate(-50%, 10px) scale(.8);
+ transform: translate(-50%, 10px) scale(0.8);
transform-origin: 50% 100%;
- transition: transform .2s .1s ease, opacity .2s .1s ease;
+ transition: transform 0.2s 0.1s ease, opacity 0.2s 0.1s ease;
&::before {
// Arrows
- content: '';
+ content: "";
position: absolute;
width: 0;
height: 0;
@@ -499,7 +509,7 @@
// First tooltip
.plyr__controls button:first-child .plyr__tooltip {
left: 0;
- transform: translate(0, 10px) scale(.8);
+ transform: translate(0, 10px) scale(0.8);
transform-origin: 0 100%;
&::before {
@@ -510,7 +520,7 @@
// Last tooltip
.plyr__controls button:last-child .plyr__tooltip {
right: 0;
- transform: translate(0, 10px) scale(.8);
+ transform: translate(0, 10px) scale(0.8);
transform-origin: 100% 100%;
&::before {
@@ -529,7 +539,6 @@
}
}
-
// Playback progress
// --------------------------------------------------------------
// <progress> element
@@ -621,13 +630,13 @@
}
.plyr__progress--buffer {
&::-webkit-progress-value {
- transition: width .2s ease;
+ transition: width 0.2s ease;
}
&::-moz-progress-bar {
- transition: width .2s ease;
+ transition: width 0.2s ease;
}
&::-ms-fill {
- transition: width .2s ease;
+ transition: width 0.2s ease;
}
}
.plyr--video .plyr__progress--buffer,
@@ -658,7 +667,8 @@
@plyr-progress-loading-bg 50%,
@plyr-progress-loading-bg 75%,
transparent 75%,
- transparent);
+ transparent
+ );
color: transparent;
}
.plyr--video.plyr--loading .plyr__progress--buffer {
@@ -685,7 +695,7 @@
// Add a slash in before
&::before {
- content: '\2044';
+ content: "\2044";
margin-right: @plyr-control-spacing;
}
}
@@ -716,21 +726,15 @@
// It's not supported to change volume using JavaScript:
// https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html
.plyr--is-ios .plyr__volume,
-.plyr--is-ios [data-plyr='mute'] {
+.plyr--is-ios [data-plyr="mute"] {
display: none !important;
}
// Fullscreen
// --------------------------------------------------------------
.plyr--fullscreen-active {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
height: 100%;
width: 100%;
- z-index: 10000000;
background: #000;
border-radius: 0 !important;
@@ -745,12 +749,6 @@
// Revert overflow change
overflow: visible;
}
- .plyr__controls {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- }
// Vimeo requires some different styling
&.plyr--vimeo .plyr__video-wrapper {
@@ -759,3 +757,13 @@
transform: translateY(-50%);
}
}
+
+// Fallback for unsupported browsers
+.plyr--fullscreen-fallback.plyr--fullscreen-active {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 10000000;
+}
diff --git a/src/scss/plyr.scss b/src/scss/plyr.scss
index 91a5d1b2..11488ae4 100644
--- a/src/scss/plyr.scss
+++ b/src/scss/plyr.scss
@@ -9,7 +9,9 @@
// Animation
// ---------------------------------------
@keyframes plyr-progress {
- to { background-position: $plyr-progress-loading-size 0; }
+ to {
+ background-position: $plyr-progress-loading-size 0;
+ }
}
// Styles
@@ -34,10 +36,13 @@
}
@if $plyr-touch-action == true {
- // Fix 300ms delay
- a, button, input, label {
- touch-action: manipulation;
- }
+ // Fix 300ms delay
+ a,
+ button,
+ input,
+ label {
+ touch-action: manipulation;
+ }
}
// Focus
@@ -56,7 +61,7 @@
// Range inputs
// Specificity is for bootstrap compatibility
- input[type='range'] {
+ input[type="range"] {
display: block;
height: ($plyr-range-thumb-height * $plyr-range-thumb-active-scale);
width: 100%;
@@ -137,13 +142,13 @@
}
// Video range inputs
-.plyr--video input[type='range'].tab-focus:focus {
- outline: 1px dotted transparentize($plyr-video-control-color, .5);
+.plyr--video input[type="range"].tab-focus:focus {
+ outline: 1px dotted transparentize($plyr-video-control-color, 0.5);
}
// Audio range inputs
-.plyr--audio input[type='range'].tab-focus:focus {
- outline: 1px dotted transparentize($plyr-audio-control-color, .5);
+.plyr--audio input[type="range"].tab-focus:focus {
+ outline: 1px dotted transparentize($plyr-audio-control-color, 0.5);
}
// Screen reader only elements
@@ -220,7 +225,7 @@
width: 100%;
padding: ($plyr-control-spacing * 2);
transform: translateY(-($plyr-control-spacing * 6));
- transition: transform .3s ease;
+ transition: transform 0.3s ease;
color: $plyr-captions-color;
font-size: $plyr-font-size-captions-base;
text-align: center;
@@ -267,7 +272,12 @@
align-items: center;
line-height: 1;
text-align: center;
-
+ pointer-events: none;
+
+ & > * {
+ pointer-events: all;
+ }
+
// Spacing
> button,
.plyr__progress,
@@ -292,12 +302,12 @@
flex-shrink: 0;
overflow: visible; // IE11
vertical-align: middle;
- padding: ($plyr-control-spacing * .7);
+ padding: ($plyr-control-spacing * 0.7);
border: 0;
background: transparent;
border-radius: 3px;
cursor: pointer;
- transition: background .3s ease, color .3s ease, opacity .3s ease;
+ transition: background 0.3s ease, color 0.3s ease, opacity 0.3s ease;
color: inherit;
svg {
@@ -341,11 +351,14 @@
right: 0;
bottom: 0;
padding: ($plyr-control-spacing * 5) $plyr-control-spacing $plyr-control-spacing;
- background: linear-gradient(transparentize($plyr-video-controls-bg, 1), transparentize($plyr-video-controls-bg, .5));
+ background: linear-gradient(
+ transparentize($plyr-video-controls-bg, 1),
+ transparentize($plyr-video-controls-bg, 0.5)
+ );
border-bottom-left-radius: inherit;
border-bottom-right-radius: inherit;
color: $plyr-video-control-color;
- transition: opacity .3s ease;
+ transition: opacity 0.3s ease;
button {
// Hover and tab focus
@@ -387,9 +400,9 @@
background: $plyr-video-control-bg-hover;
border: 4px solid currentColor;
border-radius: 100%;
- box-shadow: 0 1px 1px transparentize(#000, .85);
+ box-shadow: 0 1px 1px transparentize(#000, 0.85);
color: $plyr-video-control-color;
- transition: all .3s ease;
+ transition: all 0.3s ease;
svg {
position: relative;
@@ -401,7 +414,7 @@
}
&:focus {
- outline: 1px dotted transparentize($plyr-video-control-color, .5);
+ outline: 1px dotted transparentize($plyr-video-control-color, 0.5);
}
}
.plyr .plyr__play-large {
@@ -416,11 +429,11 @@
}
// States
-.plyr__controls [data-plyr='pause'],
-.plyr--playing .plyr__controls [data-plyr='play'] {
+.plyr__controls [data-plyr="pause"],
+.plyr--playing .plyr__controls [data-plyr="play"] {
display: none;
}
-.plyr--playing .plyr__controls [data-plyr='pause'] {
+.plyr--playing .plyr__controls [data-plyr="pause"] {
display: inline-block;
}
@@ -436,12 +449,12 @@
}
// Some options are hidden by default
-.plyr [data-plyr='captions'],
-.plyr [data-plyr='fullscreen'] {
+.plyr [data-plyr="captions"],
+.plyr [data-plyr="fullscreen"] {
display: none;
}
-.plyr--captions-enabled [data-plyr='captions'],
-.plyr--fullscreen-enabled [data-plyr='fullscreen'] {
+.plyr--captions-enabled [data-plyr="captions"],
+.plyr--fullscreen-enabled [data-plyr="fullscreen"] {
display: inline-block;
}
@@ -463,13 +476,13 @@
font-size: $plyr-font-size-small;
line-height: 1.3;
- transform: translate(-50%, 10px) scale(.8);
+ transform: translate(-50%, 10px) scale(0.8);
transform-origin: 50% 100%;
- transition: transform .2s .1s ease, opacity .2s .1s ease;
+ transition: transform 0.2s 0.1s ease, opacity 0.2s 0.1s ease;
&::before {
// Arrows
- content: '';
+ content: "";
position: absolute;
width: 0;
height: 0;
@@ -497,7 +510,7 @@
// First tooltip
.plyr__controls button:first-child .plyr__tooltip {
left: 0;
- transform: translate(0, 10px) scale(.8);
+ transform: translate(0, 10px) scale(0.8);
transform-origin: 0 100%;
&::before {
@@ -508,7 +521,7 @@
// Last tooltip
.plyr__controls button:last-child .plyr__tooltip {
right: 0;
- transform: translate(0, 10px) scale(.8);
+ transform: translate(0, 10px) scale(0.8);
transform-origin: 100% 100%;
&::before {
@@ -618,13 +631,13 @@
}
.plyr__progress--buffer {
&::-webkit-progress-value {
- transition: width .2s ease;
+ transition: width 0.2s ease;
}
&::-moz-progress-bar {
- transition: width .2s ease;
+ transition: width 0.2s ease;
}
&::-ms-fill {
- transition: width .2s ease;
+ transition: width 0.2s ease;
}
}
.plyr--video .plyr__progress--buffer,
@@ -655,7 +668,8 @@
$plyr-progress-loading-bg 50%,
$plyr-progress-loading-bg 75%,
transparent 75%,
- transparent);
+ transparent
+ );
color: transparent;
}
.plyr--video.plyr--loading .plyr__progress--buffer {
@@ -682,7 +696,7 @@
// Add a slash in before
&::before {
- content: '\2044';
+ content: "\2044";
margin-right: $plyr-control-spacing;
}
}
@@ -713,21 +727,15 @@
// It's not supported to change volume using JavaScript:
// https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html
.plyr--is-ios .plyr__volume,
-.plyr--is-ios [data-plyr='mute'] {
+.plyr--is-ios [data-plyr="mute"] {
display: none !important;
}
// Fullscreen
// --------------------------------------------------------------
.plyr--fullscreen-active {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
height: 100%;
width: 100%;
- z-index: 10000000;
background: #000;
border-radius: 0 !important;
@@ -742,12 +750,6 @@
// Revert overflow change
overflow: visible;
}
- .plyr__controls {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- }
// Vimeo requires some different styling
&.plyr--vimeo .plyr__video-wrapper {
@@ -756,3 +758,13 @@
transform: translateY(-50%);
}
}
+
+// Fallback for unsupported browsers
+.plyr--fullscreen-fallback.plyr--fullscreen-active {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 10000000;
+}