diff options
author | Sam Potts <sam@potts.es> | 2017-11-18 19:30:26 +1100 |
---|---|---|
committer | Sam Potts <sam@potts.es> | 2017-11-18 19:30:26 +1100 |
commit | 6984d6fb1606a71edd35ac043ac1116b6de8e98b (patch) | |
tree | 1dc18a90bb2870b3c4665e40a3dcaeb75f3bb831 | |
parent | d7a1c4428138d2dd5af09e41e998d1e08dafe76e (diff) | |
download | plyr-6984d6fb1606a71edd35ac043ac1116b6de8e98b.tar.lz plyr-6984d6fb1606a71edd35ac043ac1116b6de8e98b.tar.xz plyr-6984d6fb1606a71edd35ac043ac1116b6de8e98b.zip |
Controls cleanup, work on captions bug, click to invert time
32 files changed, 361 insertions, 255 deletions
diff --git a/demo/dist/demo.css b/demo/dist/demo.css index e74489e0..809bec06 100644 --- a/demo/dist/demo.css +++ b/demo/dist/demo.css @@ -1 +1 @@ -@-webkit-keyframes fadein{0%{opacity:0}100%{opacity:1}}@keyframes fadein{0%{opacity:0}100%{opacity:1}}@font-face{font-family:Avenir;src:url(https://cdn.plyr.io/static/fonts/avenir-medium.woff2) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-medium.woff) format('woff');font-style:normal;font-weight:500;font-display:swap}@font-face{font-family:Avenir;src:url(https://cdn.plyr.io/static/fonts/avenir-bold.woff2) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-bold.woff) format('woff');font-style:normal;font-weight:700;font-display:swap}@font-face{font-family:Avenir;src:url(https://cdn.plyr.io/static/fonts/avenir-black.woff2?v=3) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-black.woff?v=3) format('woff');font-style:normal;font-weight:900;font-display:swap}/*! 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,button.faux-link{background:0 0}a:focus,button.faux-link:focus{outline:thin dotted}a:active,a:hover,button.faux-link:active,button.faux-link: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{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]{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}*,::after,::before{box-sizing:border-box}body,html{display:-webkit-box;display:flex;width:100%}html{background:linear-gradient(to left top,#67caff,#0085cd);background-attachment:fixed;height:100%}body{display:-webkit-box;display:flex;min-height:100%;-webkit-box-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column}main{text-align:center}.grid{-webkit-box-flex:1;flex:1}aside{display:-webkit-box;display:flex;flex-shrink:0;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center;width:100%;padding:15px;background:#fff;text-align:center;color:#55646b;text-shadow:none}aside .icon{margin-right:10px;fill:#4baaf4}aside p{margin:0}aside a,aside button.faux-link{color:#4baaf4}aside a.tab-focus,aside button.faux-link.tab-focus{outline:0;box-shadow:0 0 0 3px rgba(75,170,244,.35)}.grid{margin:0 auto;padding:20px}@media only screen and (min-width:768px){.grid{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;width:100%;max-width:1280px}.grid>*{-webkit-box-flex:1;flex:1}}html{font-size:100%}body{font-family:Avenir,'Helvetica Neue',sans-serif;line-height:1.5;color:#fff;font-weight:500;text-shadow:0 1px 1px rgba(0,0,0,.15);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}button,input,select,textarea{font:inherit}p,small{margin:0 0 20px}small{display:block;font-size:14px;font-size:.875rem}h1{margin:0 0 10px;font-weight:900;letter-spacing:-.025em;font-size:64px;font-size:4rem}.button,.button__count{position:relative;display:-webkit-inline-box;display:inline-flex;vertical-align:middle;-webkit-box-align:center;align-items:center;padding:15px;border-radius:4px;box-shadow:0 1px 1px rgba(0,0,0,.1);background:#fff;border:0;color:#55646b;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-weight:700;text-shadow:none}.button{padding-left:20px;padding-right:20px;transition:all .2s ease}.button:focus,.button:hover{color:#343f4a;outline:0}.button:focus::after,.button:hover::after{display:none}.button.tab-focus{outline:0;box-shadow:0 0 0 3px rgba(255,255,255,.35)}.button__count{margin-left:10px;-webkit-animation:fadein .2s ease;animation:fadein .2s ease}.button__count::before{content:'';position:absolute;width:0;height:0;right:100%;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);border:5px solid transparent;border-right-color:#fff;border-left-width:0}header{padding-bottom:20px;text-align:center}header p{margin-bottom:30px;font-size:18px;font-size:1.125rem}header .action{display:-webkit-inline-box;display:inline-flex}header .action .button .icon{flex-shrink:0}@media only screen and (min-width:768px){header{max-width:400px;margin-right:40px;padding-bottom:40px;text-align:left}}.icon{fill:currentColor;width:16px;height:16px;vertical-align:-.15em}a svg,button svg,button.faux-link svg,label svg{pointer-events:none}.btn .icon,a .icon,button.faux-link .icon{margin-right:5px}button.faux-link{position:relative;margin:0;padding:0;width:auto;border:0;background:0 0;vertical-align:baseline;text-align:inherit;font:inherit;line-height:1.5;cursor:pointer;-moz-user-select:text;text-shadow:inherit;border-radius:0}a,button.faux-link{position:relative;border-bottom:1px dotted currentColor;transition:all .2s ease;text-decoration:none;color:#fff;font-weight:700}a::after,button.faux-link::after{content:'';position:absolute;top:100%;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:0;height:1px;transition:width .2s ease;background:currentColor}a:focus,a:hover,button.faux-link:focus,button.faux-link:hover{border-bottom-color:transparent;outline:0}a:focus::after,a:hover::after,button.faux-link:focus::after,button.faux-link:hover::after{width:100%}a.tab-focus,button.faux-link.tab-focus{outline:0;box-shadow:0 0 0 3px rgba(255,255,255,.35)}li,ul{list-style:none;margin:0;padding:0}nav{display:-webkit-box;display:flex;-webkit-box-pack:center;justify-content:center;margin-bottom:20px}video{max-width:100%;vertical-align:middle}.plyr{margin:0 auto;border-radius:4px;box-shadow:0 2px 5px rgba(0,0,0,.2)}.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 +@-webkit-keyframes fadein{0%{opacity:0}100%{opacity:1}}@keyframes fadein{0%{opacity:0}100%{opacity:1}}@font-face{font-family:Avenir;src:local('Avenir-Medium'),url(https://cdn.plyr.io/static/fonts/avenir-medium.woff2) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-medium.woff) format('woff');font-style:normal;font-weight:500;font-display:swap}@font-face{font-family:Avenir;src:local('Avenir-Heavy'),url(https://cdn.plyr.io/static/fonts/avenir-bold.woff2) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-bold.woff) format('woff');font-style:normal;font-weight:700;font-display:swap}@font-face{font-family:Avenir;src:local('Avenir-Black'),url(https://cdn.plyr.io/static/fonts/avenir-black.woff2?v=3) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-black.woff?v=3) format('woff');font-style:normal;font-weight:900;font-display:swap}/*! 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,button.faux-link{background:0 0}a:focus,button.faux-link:focus{outline:thin dotted}a:active,a:hover,button.faux-link:active,button.faux-link: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{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]{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}*,::after,::before{box-sizing:border-box}body,html{display:-webkit-box;display:flex;width:100%}html{background:linear-gradient(to left top,#67caff,#0085cd);background-attachment:fixed;height:100%}body{display:-webkit-box;display:flex;min-height:100%;-webkit-box-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column}.grid{-webkit-box-flex:1;flex:1;overflow:auto}main{margin:auto;text-align:center}aside{position:relative;display:-webkit-box;display:flex;flex-shrink:0;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center;width:100%;padding:15px;background:#fff;text-align:center;color:#55646b;text-shadow:none}aside .icon{margin-right:10px;fill:#4baaf4}aside p{margin:0}aside a,aside button.faux-link{color:#4baaf4}aside a.tab-focus,aside button.faux-link.tab-focus{outline:0;box-shadow:0 0 0 3px rgba(75,170,244,.35)}.grid{margin:0 auto;padding:20px}@media only screen and (min-width:768px){.grid{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;width:100%;max-width:1280px}.grid>*{-webkit-box-flex:1;flex:1}}html{font-size:100%}body{font-family:Avenir,'Helvetica Neue',sans-serif;line-height:1.5;color:#fff;font-weight:500;text-shadow:0 1px 1px rgba(0,0,0,.15);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}button,input,select,textarea{font:inherit}p,small{margin:0 0 20px}small{display:block;font-size:14px;font-size:.875rem}h1{margin:0 0 10px;font-weight:900;letter-spacing:-.025em;font-size:64px;font-size:4rem}.button,.button__count{position:relative;display:-webkit-inline-box;display:inline-flex;vertical-align:middle;-webkit-box-align:center;align-items:center;padding:15px;border-radius:4px;box-shadow:0 1px 1px rgba(0,0,0,.1);background:#fff;border:0;color:#55646b;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-weight:700;text-shadow:none}.button{padding-left:20px;padding-right:20px;transition:all .2s ease}.button:focus,.button:hover{color:#343f4a;outline:0}.button:focus::after,.button:hover::after{display:none}.button.tab-focus{outline:0;box-shadow:0 0 0 3px rgba(255,255,255,.35)}.button__count{margin-left:10px;-webkit-animation:fadein .2s ease;animation:fadein .2s ease}.button__count::before{content:'';position:absolute;width:0;height:0;right:100%;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);border:5px solid transparent;border-right-color:#fff;border-left-width:0}header{padding-bottom:20px;text-align:center}header p{margin-bottom:30px;font-size:18px;font-size:1.125rem}header .action{display:-webkit-inline-box;display:inline-flex}header .action .button .icon{flex-shrink:0}@media only screen and (min-width:768px){header{max-width:400px;margin-right:40px;padding-bottom:40px;text-align:left}}.icon{fill:currentColor;width:16px;height:16px;vertical-align:-.15em}a svg,button svg,button.faux-link svg,label svg{pointer-events:none}.btn .icon,a .icon,button.faux-link .icon{margin-right:5px}button.faux-link{position:relative;margin:0;padding:0;width:auto;border:0;background:0 0;vertical-align:baseline;text-align:inherit;font:inherit;line-height:1.5;cursor:pointer;-moz-user-select:text;text-shadow:inherit;border-radius:0}a,button.faux-link{position:relative;border-bottom:1px dotted currentColor;transition:all .2s ease;text-decoration:none;color:#fff;font-weight:700}a::after,button.faux-link::after{content:'';position:absolute;top:100%;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:0;height:1px;transition:width .2s ease;background:currentColor}a:focus,a:hover,button.faux-link:focus,button.faux-link:hover{border-bottom-color:transparent;outline:0}a:focus::after,a:hover::after,button.faux-link:focus::after,button.faux-link:hover::after{width:100%}a.tab-focus,button.faux-link.tab-focus{outline:0;box-shadow:0 0 0 3px rgba(255,255,255,.35)}li,ul{list-style:none;margin:0;padding:0}nav{display:-webkit-box;display:flex;-webkit-box-pack:center;justify-content:center;margin-bottom:20px}video{max-width:100%;vertical-align:middle}.plyr{margin:20px auto;border-radius:4px;box-shadow:0 2px 5px rgba(0,0,0,.2)}.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/dist/demo.js b/demo/dist/demo.js index 0443b142..867ea774 100644 --- a/demo/dist/demo.js +++ b/demo/dist/demo.js @@ -1,3 +1,3 @@ -document.addEventListener("DOMContentLoaded",function(){function e(e,t,o){e&&e.classList[o?"add":"remove"](t)}function t(t,a){if(t in n&&(a||t!==r)&&(r.length||t!==n.video)){switch(t){case n.video:o.source={type:"video",title:"View From A Blue Moon",sources:[{src:"https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4",type:"video/mp4"}],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:!0},{kind:"captions",label:"French",srclang:"fr",src:"https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt"}]};break;case n.audio:o.source={type:"audio",title:"Kishi Bashi – “It All Began With A Burst”",sources:[{src:"https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3",type:"audio/mp3"},{src:"https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg",type:"audio/ogg"}]};break;case n.youtube:o.source={type:"video",title:"View From A Blue Moon",sources:[{src:"https://youtube.com/watch?v=bTqVqk7FSmY",type:"youtube"}]};break;case n.vimeo:o.source={type:"video",sources:[{src:"https://vimeo.com/76979871",type:"vimeo"}]}}r=t,Array.from(i).forEach(function(t){return e(t.parentElement,"active",!1)}),e(document.querySelector('[data-source="'+t+'"]'),"active",!0),Array.from(document.querySelectorAll(".plyr__cite")).forEach(function(e){e.setAttribute("hidden","")}),document.querySelector(".plyr__cite--"+t).removeAttribute("hidden")}}window.shr&&window.shr.setup({count:{classname:"button__count"}});document.addEventListener("focusout",function(e){e.target.classList.remove("tab-focus")}),document.addEventListener("keydown",function(e){9===e.keyCode&&window.setTimeout(function(){document.activeElement.classList.add("tab-focus")},0)});var o=new window.Plyr("#player",{debug:!0,title:"View From A Blue Moon",iconUrl:"../dist/plyr.svg",keyboard:{global:!0},tooltips:{controls:!0},captions:{active:!0},controls:["play-large","play","progress","current-time","mute","volume","captions","settings","fullscreen","pip","airplay"]});window.player=o;var i=document.querySelectorAll("[data-source]"),n={video:"video",audio:"audio",youtube:"youtube",vimeo:"vimeo"},r=window.location.hash.replace("#",""),a=window.history&&window.history.pushState;if(Array.from(i).forEach(function(e){e.addEventListener("click",function(){var o=e.getAttribute("data-source");t(o),a&&window.history.pushState({type:o},"","#"+o)})}),window.addEventListener("popstate",function(e){e.state&&"type"in e.state&&t(e.state.type)}),a){var s=!r.length;s&&(r=n.video),r in n&&window.history.replaceState({type:r},"",s?"":"#"+r),r!==n.video&&t(r,!0)}}),"plyr.io"===window.location.host&&(!function(e,t,o,i,n,r,a){e.GoogleAnalyticsObject=n,e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,r=t.createElement(o),a=t.getElementsByTagName(o)[0],r.async=1,r.src="//www.google-analytics.com/analytics.js",a.parentNode.insertBefore(r,a)}(window,document,"script",0,"ga"),window.ga("create","UA-40881672-11","auto"),window.ga("send","pageview")); +document.addEventListener("DOMContentLoaded",function(){function e(e,t,o){e&&e.classList[o?"add":"remove"](t)}function t(t,r){if(t in a&&(r||t!==n)&&(n.length||t!==a.video)){switch(t){case a.video:o.source={type:"video",title:"View From A Blue Moon",sources:[{src:"media/View_From_A_Blue_Moon_Trailer-HD.mp4",type:"video/mp4"}],poster:"hmedia/View_From_A_Blue_Moon_Trailer-HD.jpg",tracks:[{kind:"captions",label:"English",srclang:"en",src:"media/View_From_A_Blue_Moon_Trailer-HD.en.vtt",default:!0},{kind:"captions",label:"French",srclang:"fr",src:"media/View_From_A_Blue_Moon_Trailer-HD.fr.vtt"}]};break;case a.audio:o.source={type:"audio",title:"Kishi Bashi – “It All Began With A Burst”",sources:[{src:"https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3",type:"audio/mp3"},{src:"https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg",type:"audio/ogg"}]};break;case a.youtube:o.source={type:"video",title:"View From A Blue Moon",sources:[{src:"https://youtube.com/watch?v=bTqVqk7FSmY",type:"youtube"}]};break;case a.vimeo:o.source={type:"video",sources:[{src:"https://vimeo.com/76979871",type:"vimeo"}]}}n=t,Array.from(i).forEach(function(t){return e(t.parentElement,"active",!1)}),e(document.querySelector('[data-source="'+t+'"]'),"active",!0),Array.from(document.querySelectorAll(".plyr__cite")).forEach(function(e){e.setAttribute("hidden","")}),document.querySelector(".plyr__cite--"+t).removeAttribute("hidden")}}window.shr&&window.shr.setup({count:{classname:"button__count"}});document.addEventListener("focusout",function(e){e.target.classList.remove("tab-focus")}),document.addEventListener("keydown",function(e){9===e.keyCode&&window.setTimeout(function(){document.activeElement.classList.add("tab-focus")},0)});var o=new window.Plyr("#player",{debug:!0,title:"View From A Blue Moon",iconUrl:"../dist/plyr.svg",keyboard:{global:!0},tooltips:{controls:!0},captions:{active:!0},controls:["play-large","play","progress","current-time","mute","volume","captions","settings","fullscreen","pip","airplay"],keys:{google:"AIzaSyDrNwtN3nLH_8rjCmu5Wq3ZCm4MNAVdc0c"}});window.player=o;var i=document.querySelectorAll("[data-source]"),a={video:"video",audio:"audio",youtube:"youtube",vimeo:"vimeo"},n=window.location.hash.replace("#",""),r=window.history&&window.history.pushState;if(Array.from(i).forEach(function(e){e.addEventListener("click",function(){var o=e.getAttribute("data-source");t(o),r&&window.history.pushState({type:o},"","#"+o)})}),window.addEventListener("popstate",function(e){e.state&&"type"in e.state&&t(e.state.type)}),r){var s=!n.length;s&&(n=a.video),n in a&&window.history.replaceState({type:n},"",s?"":"#"+n),n!==a.video&&t(n,!0)}}),"plyr.io"===window.location.host&&(!function(e,t,o,i,a,n,r){e.GoogleAnalyticsObject=a,e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,n=t.createElement(o),r=t.getElementsByTagName(o)[0],n.async=1,n.src="//www.google-analytics.com/analytics.js",r.parentNode.insertBefore(n,r)}(window,document,"script",0,"ga"),window.ga("create","UA-40881672-11","auto"),window.ga("send","pageview")); //# sourceMappingURL=demo.js.map diff --git a/demo/dist/demo.js.map b/demo/dist/demo.js.map index ecac2a4a..b480fb6b 100644 --- a/demo/dist/demo.js.map +++ b/demo/dist/demo.js.map @@ -1 +1 @@ -{"version":3,"file":"demo.js","sources":["demo/src/js/demo.js"],"sourcesContent":["// ==========================================================================\n// Plyr.io demo\n// This code is purely for the https://plyr.io website\n// Please see readme.md in the root or github.com/sampotts/plyr\n// ==========================================================================\n\ndocument.addEventListener('DOMContentLoaded', () => {\n if (window.shr) {\n window.shr.setup({\n count: {\n classname: 'button__count',\n },\n });\n }\n\n // Setup tab focus\n const tabClassName = 'tab-focus';\n\n // Remove class on blur\n document.addEventListener('focusout', event => {\n event.target.classList.remove(tabClassName);\n });\n\n // Add classname to tabbed elements\n document.addEventListener('keydown', event => {\n if (event.keyCode !== 9) {\n return;\n }\n\n // Delay the adding of classname until the focus has changed\n // This event fires before the focusin event\n window.setTimeout(() => {\n document.activeElement.classList.add(tabClassName);\n }, 0);\n });\n\n /* document.body.addEventListener('ready', function(event) {\n console.log(event);\n }); */\n\n // Setup the player\n const player = new window.Plyr('#player', {\n debug: true,\n title: 'View From A Blue Moon',\n iconUrl: '../dist/plyr.svg',\n keyboard: {\n global: true,\n },\n tooltips: {\n controls: true,\n },\n captions: {\n active: true,\n },\n controls: [\n 'play-large',\n 'play',\n 'progress',\n 'current-time',\n 'mute',\n 'volume',\n 'captions',\n 'settings',\n 'fullscreen',\n 'pip',\n 'airplay',\n ],\n });\n\n // Expose for testing\n window.player = player;\n\n // Setup type toggle\n const buttons = document.querySelectorAll('[data-source]');\n const types = {\n video: 'video',\n audio: 'audio',\n youtube: 'youtube',\n vimeo: 'vimeo',\n };\n let currentType = window.location.hash.replace('#', '');\n const historySupport = window.history && window.history.pushState;\n\n // Toggle class on an element\n function toggleClass(element, className, state) {\n if (element) {\n element.classList[state ? 'add' : 'remove'](className);\n }\n }\n\n // Set a new source\n function newSource(type, init) {\n // 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\n if (!(type in types) || (!init && type === currentType) || (!currentType.length && type === types.video)) {\n return;\n }\n\n switch (type) {\n case types.video:\n player.source = {\n type: 'video',\n title: 'View From A Blue Moon',\n sources: [\n {\n src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4',\n type: 'video/mp4',\n },\n ],\n poster: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg',\n tracks: [\n {\n kind: 'captions',\n label: 'English',\n srclang: 'en',\n src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt',\n default: true,\n },\n {\n kind: 'captions',\n label: 'French',\n srclang: 'fr',\n src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt',\n },\n ],\n };\n\n break;\n\n case types.audio:\n player.source = {\n type: 'audio',\n title: 'Kishi Bashi – “It All Began With A Burst”',\n sources: [\n {\n src: 'https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3',\n type: 'audio/mp3',\n },\n {\n src: 'https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg',\n type: 'audio/ogg',\n },\n ],\n };\n\n break;\n\n case types.youtube:\n player.source = {\n type: 'video',\n title: 'View From A Blue Moon',\n sources: [\n {\n src: 'https://youtube.com/watch?v=bTqVqk7FSmY',\n type: 'youtube',\n },\n ],\n };\n\n break;\n\n case types.vimeo:\n player.source = {\n type: 'video',\n sources: [\n {\n src: 'https://vimeo.com/76979871',\n type: 'vimeo',\n },\n ],\n };\n\n break;\n\n default:\n break;\n }\n\n // Set the current type for next time\n currentType = type;\n\n // Remove active classes\n Array.from(buttons).forEach(button => toggleClass(button.parentElement, 'active', false));\n\n // Set active on parent\n toggleClass(document.querySelector(`[data-source=\"${type}\"]`), 'active', true);\n\n // Show cite\n Array.from(document.querySelectorAll('.plyr__cite')).forEach(cite => {\n cite.setAttribute('hidden', '');\n });\n document.querySelector(`.plyr__cite--${type}`).removeAttribute('hidden');\n }\n\n // Bind to each button\n Array.from(buttons).forEach(button => {\n button.addEventListener('click', () => {\n const type = button.getAttribute('data-source');\n\n newSource(type);\n\n if (historySupport) {\n window.history.pushState({ type }, '', `#${type}`);\n }\n });\n });\n\n // List for backwards/forwards\n window.addEventListener('popstate', event => {\n if (event.state && 'type' in event.state) {\n newSource(event.state.type);\n }\n });\n\n // On load\n if (historySupport) {\n const video = !currentType.length;\n\n // If there's no current type set, assume video\n if (video) {\n currentType = types.video;\n }\n\n // Replace current history state\n if (currentType in types) {\n window.history.replaceState(\n {\n type: currentType,\n },\n '',\n video ? '' : `#${currentType}`\n );\n }\n\n // If it's not video, load the source\n if (currentType !== types.video) {\n newSource(currentType, true);\n }\n }\n});\n\n// Google analytics\n// For demo site (https://plyr.io) only\n/* eslint-disable */\nif (window.location.host === 'plyr.io') {\n (function(i, s, o, g, r, a, m) {\n i.GoogleAnalyticsObject = r;\n i[r] =\n i[r] ||\n function() {\n (i[r].q = i[r].q || []).push(arguments);\n };\n i[r].l = 1 * new Date();\n a = s.createElement(o);\n m = s.getElementsByTagName(o)[0];\n a.async = 1;\n a.src = g;\n m.parentNode.insertBefore(a, m);\n })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');\n window.ga('create', 'UA-40881672-11', 'auto');\n window.ga('send', 'pageview');\n}\n/* eslint-enable */\n"],"names":["document","addEventListener","toggleClass","element","className","state","classList","newSource","type","init","types","currentType","length","video","source","audio","youtube","vimeo","from","buttons","forEach","button","parentElement","querySelector","querySelectorAll","setAttribute","removeAttribute","window","shr","setup","target","remove","event","keyCode","setTimeout","activeElement","add","player","Plyr","location","hash","replace","historySupport","history","pushState","getAttribute","replaceState","host","i","s","o","g","r","a","m","GoogleAnalyticsObject","q","push","arguments","l","Date","createElement","getElementsByTagName","async","src","parentNode","insertBefore","ga"],"mappings":"AAMAA,SAASC,iBAAiB,mBAAoB,oBA8EjCC,EAAYC,EAASC,EAAWC,GACjCF,KACQG,UAAUD,EAAQ,MAAQ,UAAUD,YAK3CG,EAAUC,EAAMC,MAEfD,KAAQE,IAAYD,GAAQD,IAASG,KAAkBA,EAAYC,QAAUJ,IAASE,EAAMG,eAI1FL,QACCE,EAAMG,QACAC,aACG,cACC,sCAGM,4EACC,qBAGN,qFAGM,iBACC,kBACE,SACJ,mFACI,SAGH,iBACC,iBACE,SACJ,wFAOhBJ,EAAMK,QACAD,aACG,cACC,4EAGM,mFACC,kBAGD,mFACC,0BAOjBJ,EAAMM,UACAF,aACG,cACC,sCAGM,+CACC,wBAOjBJ,EAAMO,QACAH,aACG,sBAGO,kCACC,aAYZN,QAGRU,KAAKC,GAASC,QAAQ,mBAAUlB,EAAYmB,EAAOC,cAAe,UAAU,OAGtEtB,SAASuB,+BAA+Bf,QAAW,UAAU,SAGnEU,KAAKlB,SAASwB,iBAAiB,gBAAgBJ,QAAQ,cACpDK,aAAa,SAAU,eAEvBF,8BAA8Bf,GAAQkB,gBAAgB,WAvL/DC,OAAOC,YACAA,IAAIC,wBAEQ,4BASd5B,iBAAiB,WAAY,cAC5B6B,OAAOxB,UAAUyB,OAJN,wBAQZ9B,iBAAiB,UAAW,YACX,IAAlB+B,EAAMC,gBAMHC,WAAW,oBACLC,cAAc7B,UAAU8B,IAhBpB,cAiBd,SAQDC,EAAS,IAAIV,OAAOW,KAAK,kBACpB,QACA,gCACE,qCAEG,uBAGE,qBAGF,aAGR,aACA,OACA,WACA,eACA,OACA,SACA,WACA,WACA,aACA,MACA,oBAKDD,OAASA,MAGVlB,EAAUnB,SAASwB,iBAAiB,iBACpCd,SACK,cACA,gBACE,gBACF,SAEPC,EAAcgB,OAAOY,SAASC,KAAKC,QAAQ,IAAK,IAC9CC,EAAiBf,OAAOgB,SAAWhB,OAAOgB,QAAQC,mBAiHlD1B,KAAKC,GAASC,QAAQ,cACjBnB,iBAAiB,QAAS,eACvBO,EAAOa,EAAOwB,aAAa,iBAEvBrC,GAENkC,UACOC,QAAQC,WAAYpC,QAAQ,OAAQA,cAMhDP,iBAAiB,WAAY,YAC5B+B,EAAM3B,OAAS,SAAU2B,EAAM3B,SACrB2B,EAAM3B,MAAMG,QAK1BkC,EAAgB,KACV7B,GAASF,EAAYC,OAGvBC,MACcH,EAAMG,OAIpBF,KAAeD,UACRiC,QAAQG,mBAEDnC,GAEV,GACAE,EAAQ,OAASF,GAKrBA,IAAgBD,EAAMG,SACZF,GAAa,MAQN,YAAzBgB,OAAOY,SAASQ,iBACNC,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,KACtBC,sBAAwBH,IAC1B,GACIJ,EAAA,IACA,YACKA,EAAA,GAAKQ,EAAIR,EAAA,GAAKQ,OAASC,KAAKC,cAErC,GAAKC,EAAI,EAAI,IAAIC,OACbX,EAAEY,cAAcX,KAChBD,EAAEa,qBAAqBZ,GAAG,KAC5Ba,MAAQ,IACRC,IAEyB,4CADzBC,WAAWC,aAAab,EAAGC,IAC9B3B,OAAQ3B,SAAU,SAAU,EAA2C,aACnEmE,GAAG,SAAU,iBAAkB,eAC/BA,GAAG,OAAQ"}
\ No newline at end of file +{"version":3,"file":"demo.js","sources":["demo/src/js/demo.js"],"sourcesContent":["// ==========================================================================\n// Plyr.io demo\n// This code is purely for the https://plyr.io website\n// Please see readme.md in the root or github.com/sampotts/plyr\n// ==========================================================================\n\ndocument.addEventListener('DOMContentLoaded', () => {\n if (window.shr) {\n window.shr.setup({\n count: {\n classname: 'button__count',\n },\n });\n }\n\n // Setup tab focus\n const tabClassName = 'tab-focus';\n\n // Remove class on blur\n document.addEventListener('focusout', event => {\n event.target.classList.remove(tabClassName);\n });\n\n // Add classname to tabbed elements\n document.addEventListener('keydown', event => {\n if (event.keyCode !== 9) {\n return;\n }\n\n // Delay the adding of classname until the focus has changed\n // This event fires before the focusin event\n window.setTimeout(() => {\n document.activeElement.classList.add(tabClassName);\n }, 0);\n });\n\n /* document.body.addEventListener('ready', function(event) {\n console.log(event);\n }); */\n\n // Setup the player\n const player = new window.Plyr('#player', {\n debug: true,\n title: 'View From A Blue Moon',\n iconUrl: '../dist/plyr.svg',\n keyboard: {\n global: true,\n },\n tooltips: {\n controls: true,\n },\n captions: {\n active: true,\n },\n controls: [\n 'play-large',\n 'play',\n 'progress',\n 'current-time',\n 'mute',\n 'volume',\n 'captions',\n 'settings',\n 'fullscreen',\n 'pip',\n 'airplay',\n ],\n keys: {\n google: 'AIzaSyDrNwtN3nLH_8rjCmu5Wq3ZCm4MNAVdc0c',\n },\n });\n\n // Expose for testing\n window.player = player;\n\n // Setup type toggle\n const buttons = document.querySelectorAll('[data-source]');\n const types = {\n video: 'video',\n audio: 'audio',\n youtube: 'youtube',\n vimeo: 'vimeo',\n };\n let currentType = window.location.hash.replace('#', '');\n const historySupport = window.history && window.history.pushState;\n\n // Toggle class on an element\n function toggleClass(element, className, state) {\n if (element) {\n element.classList[state ? 'add' : 'remove'](className);\n }\n }\n\n // Set a new source\n function newSource(type, init) {\n // 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\n if (!(type in types) || (!init && type === currentType) || (!currentType.length && type === types.video)) {\n return;\n }\n\n switch (type) {\n case types.video:\n player.source = {\n type: 'video',\n title: 'View From A Blue Moon',\n sources: [\n {\n src: 'media/View_From_A_Blue_Moon_Trailer-HD.mp4',\n type: 'video/mp4',\n },\n ],\n poster: 'hmedia/View_From_A_Blue_Moon_Trailer-HD.jpg',\n tracks: [\n {\n kind: 'captions',\n label: 'English',\n srclang: 'en',\n src: 'media/View_From_A_Blue_Moon_Trailer-HD.en.vtt',\n default: true,\n },\n {\n kind: 'captions',\n label: 'French',\n srclang: 'fr',\n src: 'media/View_From_A_Blue_Moon_Trailer-HD.fr.vtt',\n },\n ],\n };\n\n break;\n\n case types.audio:\n player.source = {\n type: 'audio',\n title: 'Kishi Bashi – “It All Began With A Burst”',\n sources: [\n {\n src: 'https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3',\n type: 'audio/mp3',\n },\n {\n src: 'https://cdn.plyr.io/static/demo/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg',\n type: 'audio/ogg',\n },\n ],\n };\n\n break;\n\n case types.youtube:\n player.source = {\n type: 'video',\n title: 'View From A Blue Moon',\n sources: [\n {\n src: 'https://youtube.com/watch?v=bTqVqk7FSmY',\n type: 'youtube',\n },\n ],\n };\n\n break;\n\n case types.vimeo:\n player.source = {\n type: 'video',\n sources: [\n {\n src: 'https://vimeo.com/76979871',\n type: 'vimeo',\n },\n ],\n };\n\n break;\n\n default:\n break;\n }\n\n // Set the current type for next time\n currentType = type;\n\n // Remove active classes\n Array.from(buttons).forEach(button => toggleClass(button.parentElement, 'active', false));\n\n // Set active on parent\n toggleClass(document.querySelector(`[data-source=\"${type}\"]`), 'active', true);\n\n // Show cite\n Array.from(document.querySelectorAll('.plyr__cite')).forEach(cite => {\n cite.setAttribute('hidden', '');\n });\n document.querySelector(`.plyr__cite--${type}`).removeAttribute('hidden');\n }\n\n // Bind to each button\n Array.from(buttons).forEach(button => {\n button.addEventListener('click', () => {\n const type = button.getAttribute('data-source');\n\n newSource(type);\n\n if (historySupport) {\n window.history.pushState({ type }, '', `#${type}`);\n }\n });\n });\n\n // List for backwards/forwards\n window.addEventListener('popstate', event => {\n if (event.state && 'type' in event.state) {\n newSource(event.state.type);\n }\n });\n\n // On load\n if (historySupport) {\n const video = !currentType.length;\n\n // If there's no current type set, assume video\n if (video) {\n currentType = types.video;\n }\n\n // Replace current history state\n if (currentType in types) {\n window.history.replaceState(\n {\n type: currentType,\n },\n '',\n video ? '' : `#${currentType}`\n );\n }\n\n // If it's not video, load the source\n if (currentType !== types.video) {\n newSource(currentType, true);\n }\n }\n});\n\n// Google analytics\n// For demo site (https://plyr.io) only\n/* eslint-disable */\nif (window.location.host === 'plyr.io') {\n (function(i, s, o, g, r, a, m) {\n i.GoogleAnalyticsObject = r;\n i[r] =\n i[r] ||\n function() {\n (i[r].q = i[r].q || []).push(arguments);\n };\n i[r].l = 1 * new Date();\n a = s.createElement(o);\n m = s.getElementsByTagName(o)[0];\n a.async = 1;\n a.src = g;\n m.parentNode.insertBefore(a, m);\n })(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');\n window.ga('create', 'UA-40881672-11', 'auto');\n window.ga('send', 'pageview');\n}\n/* eslint-enable */\n"],"names":["document","addEventListener","toggleClass","element","className","state","classList","newSource","type","init","types","currentType","length","video","source","audio","youtube","vimeo","from","buttons","forEach","button","parentElement","querySelector","querySelectorAll","setAttribute","removeAttribute","window","shr","setup","target","remove","event","keyCode","setTimeout","activeElement","add","player","Plyr","location","hash","replace","historySupport","history","pushState","getAttribute","replaceState","host","i","s","o","g","r","a","m","GoogleAnalyticsObject","q","push","arguments","l","Date","createElement","getElementsByTagName","async","src","parentNode","insertBefore","ga"],"mappings":"AAMAA,SAASC,iBAAiB,mBAAoB,oBAiFjCC,EAAYC,EAASC,EAAWC,GACjCF,KACQG,UAAUD,EAAQ,MAAQ,UAAUD,YAK3CG,EAAUC,EAAMC,MAEfD,KAAQE,IAAYD,GAAQD,IAASG,KAAkBA,EAAYC,QAAUJ,IAASE,EAAMG,eAI1FL,QACCE,EAAMG,QACAC,aACG,cACC,sCAGM,kDACC,qBAGN,4DAGM,iBACC,kBACE,SACJ,yDACI,SAGH,iBACC,iBACE,SACJ,8DAOhBJ,EAAMK,QACAD,aACG,cACC,4EAGM,mFACC,kBAGD,mFACC,0BAOjBJ,EAAMM,UACAF,aACG,cACC,sCAGM,+CACC,wBAOjBJ,EAAMO,QACAH,aACG,sBAGO,kCACC,aAYZN,QAGRU,KAAKC,GAASC,QAAQ,mBAAUlB,EAAYmB,EAAOC,cAAe,UAAU,OAGtEtB,SAASuB,+BAA+Bf,QAAW,UAAU,SAGnEU,KAAKlB,SAASwB,iBAAiB,gBAAgBJ,QAAQ,cACpDK,aAAa,SAAU,eAEvBF,8BAA8Bf,GAAQkB,gBAAgB,WA1L/DC,OAAOC,YACAA,IAAIC,wBAEQ,4BASd5B,iBAAiB,WAAY,cAC5B6B,OAAOxB,UAAUyB,OAJN,wBAQZ9B,iBAAiB,UAAW,YACX,IAAlB+B,EAAMC,gBAMHC,WAAW,oBACLC,cAAc7B,UAAU8B,IAhBpB,cAiBd,SAQDC,EAAS,IAAIV,OAAOW,KAAK,kBACpB,QACA,gCACE,qCAEG,uBAGE,qBAGF,aAGR,aACA,OACA,WACA,eACA,OACA,SACA,WACA,WACA,aACA,MACA,wBAGQ,oDAKTD,OAASA,MAGVlB,EAAUnB,SAASwB,iBAAiB,iBACpCd,SACK,cACA,gBACE,gBACF,SAEPC,EAAcgB,OAAOY,SAASC,KAAKC,QAAQ,IAAK,IAC9CC,EAAiBf,OAAOgB,SAAWhB,OAAOgB,QAAQC,mBAiHlD1B,KAAKC,GAASC,QAAQ,cACjBnB,iBAAiB,QAAS,eACvBO,EAAOa,EAAOwB,aAAa,iBAEvBrC,GAENkC,UACOC,QAAQC,WAAYpC,QAAQ,OAAQA,cAMhDP,iBAAiB,WAAY,YAC5B+B,EAAM3B,OAAS,SAAU2B,EAAM3B,SACrB2B,EAAM3B,MAAMG,QAK1BkC,EAAgB,KACV7B,GAASF,EAAYC,OAGvBC,MACcH,EAAMG,OAIpBF,KAAeD,UACRiC,QAAQG,mBAEDnC,GAEV,GACAE,EAAQ,OAASF,GAKrBA,IAAgBD,EAAMG,SACZF,GAAa,MAQN,YAAzBgB,OAAOY,SAASQ,iBACNC,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,EAAGC,KACtBC,sBAAwBH,IAC1B,GACIJ,EAAA,IACA,YACKA,EAAA,GAAKQ,EAAIR,EAAA,GAAKQ,OAASC,KAAKC,cAErC,GAAKC,EAAI,EAAI,IAAIC,OACbX,EAAEY,cAAcX,KAChBD,EAAEa,qBAAqBZ,GAAG,KAC5Ba,MAAQ,IACRC,IAEyB,4CADzBC,WAAWC,aAAab,EAAGC,IAC9B3B,OAAQ3B,SAAU,SAAU,EAA2C,aACnEmE,GAAG,SAAU,iBAAkB,eAC/BA,GAAG,OAAQ"}
\ No newline at end of file diff --git a/demo/dist/error.css b/demo/dist/error.css index e25626c2..7ab25fd0 100644 --- a/demo/dist/error.css +++ b/demo/dist/error.css @@ -1 +1 @@ -@font-face{font-family:Avenir;src:url(https://cdn.plyr.io/static/fonts/avenir-medium.woff2) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-medium.woff) format('woff');font-style:normal;font-weight:500;font-display:swap}@font-face{font-family:Avenir;src:url(https://cdn.plyr.io/static/fonts/avenir-bold.woff2) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-bold.woff) format('woff');font-style:normal;font-weight:700;font-display:swap}@font-face{font-family:Avenir;src:url(https://cdn.plyr.io/static/fonts/avenir-black.woff2?v=3) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-black.woff?v=3) format('woff');font-style:normal;font-weight:900;font-display:swap}/*! 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,button.faux-link{background:0 0}a:focus,button.faux-link:focus{outline:thin dotted}a:active,a:hover,button.faux-link:active,button.faux-link: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{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]{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}.error body,html.error{height:100%}html.error{background:linear-gradient(to left top,#67caff,#0085cd);background-attachment:fixed}.error body{width:100%;display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center}.error main{width:100%;padding:20px;text-align:center}.error main p{font-size:18px;font-size:1.125rem}html{font-size:100%}body{font-family:Avenir,'Helvetica Neue',sans-serif;line-height:1.5;color:#fff;font-weight:500;text-shadow:0 1px 1px rgba(0,0,0,.15);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}button,input,select,textarea{font:inherit}p,small{margin:0 0 20px}small{display:block;font-size:14px;font-size:.875rem}h1{margin:0 0 10px;font-weight:900;letter-spacing:-.025em;font-size:64px;font-size:4rem}.button,.button__count{position:relative;display:-webkit-inline-box;display:inline-flex;vertical-align:middle;-webkit-box-align:center;align-items:center;padding:15px;border-radius:4px;box-shadow:0 1px 1px rgba(0,0,0,.1);background:#fff;border:0;color:#55646b;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-weight:700;text-shadow:none}.button{padding-left:20px;padding-right:20px;transition:all .2s ease}.button:focus,.button:hover{color:#343f4a;outline:0}.button:focus::after,.button:hover::after{display:none}.button.tab-focus{outline:0;box-shadow:0 0 0 3px rgba(255,255,255,.35)}.button__count{margin-left:10px;-webkit-animation:fadein .2s ease;animation:fadein .2s ease}.button__count::before{content:'';position:absolute;width:0;height:0;right:100%;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);border:5px solid transparent;border-right-color:#fff;border-left-width:0}button.faux-link{position:relative;margin:0;padding:0;width:auto;border:0;background:0 0;vertical-align:baseline;text-align:inherit;font:inherit;line-height:1.5;cursor:pointer;-moz-user-select:text;text-shadow:inherit;border-radius:0}a,button.faux-link{position:relative;border-bottom:1px dotted currentColor;transition:all .2s ease;text-decoration:none;color:#fff;font-weight:700}a::after,button.faux-link::after{content:'';position:absolute;top:100%;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:0;height:1px;transition:width .2s ease;background:currentColor}a:focus,a:hover,button.faux-link:focus,button.faux-link:hover{border-bottom-color:transparent;outline:0}a:focus::after,a:hover::after,button.faux-link:focus::after,button.faux-link:hover::after{width:100%}a.tab-focus,button.faux-link.tab-focus{outline:0;box-shadow:0 0 0 3px rgba(255,255,255,.35)}
\ No newline at end of file +@font-face{font-family:Avenir;src:local('Avenir-Medium'),url(https://cdn.plyr.io/static/fonts/avenir-medium.woff2) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-medium.woff) format('woff');font-style:normal;font-weight:500;font-display:swap}@font-face{font-family:Avenir;src:local('Avenir-Heavy'),url(https://cdn.plyr.io/static/fonts/avenir-bold.woff2) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-bold.woff) format('woff');font-style:normal;font-weight:700;font-display:swap}@font-face{font-family:Avenir;src:local('Avenir-Black'),url(https://cdn.plyr.io/static/fonts/avenir-black.woff2?v=3) format('woff2'),url(https://cdn.plyr.io/static/fonts/avenir-black.woff?v=3) format('woff');font-style:normal;font-weight:900;font-display:swap}/*! 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,button.faux-link{background:0 0}a:focus,button.faux-link:focus{outline:thin dotted}a:active,a:hover,button.faux-link:active,button.faux-link: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{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]{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}.error body,html.error{height:100%}html.error{background:linear-gradient(to left top,#67caff,#0085cd);background-attachment:fixed}.error body{width:100%;display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center}.error main{width:100%;padding:20px;text-align:center}.error main p{font-size:18px;font-size:1.125rem}html{font-size:100%}body{font-family:Avenir,'Helvetica Neue',sans-serif;line-height:1.5;color:#fff;font-weight:500;text-shadow:0 1px 1px rgba(0,0,0,.15);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}button,input,select,textarea{font:inherit}p,small{margin:0 0 20px}small{display:block;font-size:14px;font-size:.875rem}h1{margin:0 0 10px;font-weight:900;letter-spacing:-.025em;font-size:64px;font-size:4rem}.button,.button__count{position:relative;display:-webkit-inline-box;display:inline-flex;vertical-align:middle;-webkit-box-align:center;align-items:center;padding:15px;border-radius:4px;box-shadow:0 1px 1px rgba(0,0,0,.1);background:#fff;border:0;color:#55646b;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-weight:700;text-shadow:none}.button{padding-left:20px;padding-right:20px;transition:all .2s ease}.button:focus,.button:hover{color:#343f4a;outline:0}.button:focus::after,.button:hover::after{display:none}.button.tab-focus{outline:0;box-shadow:0 0 0 3px rgba(255,255,255,.35)}.button__count{margin-left:10px;-webkit-animation:fadein .2s ease;animation:fadein .2s ease}.button__count::before{content:'';position:absolute;width:0;height:0;right:100%;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);border:5px solid transparent;border-right-color:#fff;border-left-width:0}button.faux-link{position:relative;margin:0;padding:0;width:auto;border:0;background:0 0;vertical-align:baseline;text-align:inherit;font:inherit;line-height:1.5;cursor:pointer;-moz-user-select:text;text-shadow:inherit;border-radius:0}a,button.faux-link{position:relative;border-bottom:1px dotted currentColor;transition:all .2s ease;text-decoration:none;color:#fff;font-weight:700}a::after,button.faux-link::after{content:'';position:absolute;top:100%;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:0;height:1px;transition:width .2s ease;background:currentColor}a:focus,a:hover,button.faux-link:focus,button.faux-link:hover{border-bottom-color:transparent;outline:0}a:focus::after,a:hover::after,button.faux-link:focus::after,button.faux-link:hover::after{width:100%}a.tab-focus,button.faux-link.tab-focus{outline:0;box-shadow:0 0 0 3px rgba(255,255,255,.35)}
\ No newline at end of file diff --git a/demo/index.html b/demo/index.html index e6648d70..ca523f42 100644 --- a/demo/index.html +++ b/demo/index.html @@ -82,17 +82,16 @@ </header> <main> - <video controls crossorigin playsinline loop poster="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg" - id="player"> + <video controls crossorigin playsinline loop poster="media/View_From_A_Blue_Moon_Trailer-HD.jpg" id="player"> <!-- Video files --> - <source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4" type="video/mp4"> + <source src="media/View_From_A_Blue_Moon_Trailer-HD.mp4" type="video/mp4"> <!-- Text track file --> - <track kind="captions" label="English" srclang="en" src="webvtt/View_From_A_Blue_Moon_Trailer-HD.en.vtt" default> - <track kind="captions" label="Français" srclang="fr" src="webvtt/View_From_A_Blue_Moon_Trailer-HD.fr.vtt"> + <track kind="captions" label="English" srclang="en" src="media/View_From_A_Blue_Moon_Trailer-HD.en.vtt" default> + <track kind="captions" label="Français" srclang="fr" src="media/View_From_A_Blue_Moon_Trailer-HD.fr.vtt"> <!-- Fallback for browsers that don't support the <video> element --> - <a href="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4" download>Download</a> + <a href="media/View_From_A_Blue_Moon_Trailer-HD.mp4" download>Download</a> </video> <ul> diff --git a/demo/webvtt/View_From_A_Blue_Moon_Trailer-HD.en.vtt b/demo/media/View_From_A_Blue_Moon_Trailer-HD.en.vtt index 5da5f307..5da5f307 100644 --- a/demo/webvtt/View_From_A_Blue_Moon_Trailer-HD.en.vtt +++ b/demo/media/View_From_A_Blue_Moon_Trailer-HD.en.vtt diff --git a/demo/webvtt/View_From_A_Blue_Moon_Trailer-HD.fr.vtt b/demo/media/View_From_A_Blue_Moon_Trailer-HD.fr.vtt index 52e3af7d..52e3af7d 100644 --- a/demo/webvtt/View_From_A_Blue_Moon_Trailer-HD.fr.vtt +++ b/demo/media/View_From_A_Blue_Moon_Trailer-HD.fr.vtt diff --git a/demo/media/View_From_A_Blue_Moon_Trailer-HD.jpg b/demo/media/View_From_A_Blue_Moon_Trailer-HD.jpg Binary files differnew file mode 100644 index 00000000..9e7b883c --- /dev/null +++ b/demo/media/View_From_A_Blue_Moon_Trailer-HD.jpg diff --git a/demo/src/js/demo.js b/demo/src/js/demo.js index a1fb7f4c..7284250a 100644 --- a/demo/src/js/demo.js +++ b/demo/src/js/demo.js @@ -65,6 +65,9 @@ document.addEventListener('DOMContentLoaded', () => { 'pip', 'airplay', ], + keys: { + google: 'AIzaSyDrNwtN3nLH_8rjCmu5Wq3ZCm4MNAVdc0c', + }, }); // Expose for testing @@ -102,24 +105,24 @@ document.addEventListener('DOMContentLoaded', () => { title: 'View From A Blue Moon', sources: [ { - src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4', + src: 'media/View_From_A_Blue_Moon_Trailer-HD.mp4', type: 'video/mp4', }, ], - poster: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg', + poster: 'hmedia/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', + src: 'media/View_From_A_Blue_Moon_Trailer-HD.en.vtt', default: true, }, { kind: 'captions', label: 'French', srclang: 'fr', - src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt', + src: 'media/View_From_A_Blue_Moon_Trailer-HD.fr.vtt', }, ], }; diff --git a/demo/src/less/components/players.less b/demo/src/less/components/players.less index f932ae5b..c7cc0839 100644 --- a/demo/src/less/components/players.less +++ b/demo/src/less/components/players.less @@ -10,7 +10,7 @@ video { // Example players .plyr { - margin: 0 auto; + margin: @spacing-base auto; border-radius: @border-radius-base; box-shadow: 0 2px 5px fade(#000, 20%); } diff --git a/demo/src/less/layout/core.less b/demo/src/less/layout/core.less index a17a54a7..08352e3d 100644 --- a/demo/src/less/layout/core.less +++ b/demo/src/less/layout/core.less @@ -27,15 +27,18 @@ body { flex-direction: column; } -main { - text-align: center; -} - .grid { flex: 1; + overflow: auto; +} + +main { + margin: auto; + text-align: center; } aside { + position: relative; display: flex; flex-shrink: 0; align-items: center; diff --git a/demo/src/less/lib/fontface.less b/demo/src/less/lib/fontface.less index c6720210..2ae6e8f4 100644 --- a/demo/src/less/lib/fontface.less +++ b/demo/src/less/lib/fontface.less @@ -4,7 +4,7 @@ @font-face { font-family: 'Avenir'; - src: url('https://cdn.plyr.io/static/fonts/avenir-medium.woff2') format('woff2'), + src: local('Avenir-Medium'), url('https://cdn.plyr.io/static/fonts/avenir-medium.woff2') format('woff2'), url('https://cdn.plyr.io/static/fonts/avenir-medium.woff') format('woff'); font-style: normal; font-weight: @font-weight-base; @@ -13,7 +13,7 @@ @font-face { font-family: 'Avenir'; - src: url('https://cdn.plyr.io/static/fonts/avenir-bold.woff2') format('woff2'), + src: local('Avenir-Heavy'), url('https://cdn.plyr.io/static/fonts/avenir-bold.woff2') format('woff2'), url('https://cdn.plyr.io/static/fonts/avenir-bold.woff') format('woff'); font-style: normal; font-weight: @font-weight-bold; @@ -22,7 +22,7 @@ @font-face { font-family: 'Avenir'; - src: url('https://cdn.plyr.io/static/fonts/avenir-black.woff2?v=3') format('woff2'), + src: local('Avenir-Black'), url('https://cdn.plyr.io/static/fonts/avenir-black.woff2?v=3') format('woff2'), url('https://cdn.plyr.io/static/fonts/avenir-black.woff?v=3') format('woff'); font-style: normal; font-weight: @font-weight-heavy; diff --git a/demo/src/less/lib/mixins.less b/demo/src/less/lib/mixins.less index fbf36546..821d2b3e 100644 --- a/demo/src/less/lib/mixins.less +++ b/demo/src/less/lib/mixins.less @@ -33,6 +33,7 @@ // --------------------------------------- .font-size(@font-size: 16) { @rem: round((@font-size / 16), 3); + font-size: (@font-size * 1px); font-size: ~'@{rem}rem'; } diff --git a/dist/plyr.css b/dist/plyr.css index 7e1a1018..54c5d80a 100644 --- a/dist/plyr.css +++ b/dist/plyr.css @@ -1 +1 @@ -@-webkit-keyframes plyr-progress{to{background-position:25px 0}}@keyframes plyr-progress{to{background-position:25px 0}}@-webkit-keyframes plyr-popup{from{-webkit-transform:translateY(10px);transform:translateY(10px);opacity:.5}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes plyr-popup{from{-webkit-transform:translateY(10px);transform:translateY(10px);opacity:.5}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}.plyr{position:relative;max-width:100%;min-width:200px;font-family:Avenir,'Avenir Next','Helvetica Neue','Segoe UI',Helvetica,Arial,sans-serif;font-weight:500;line-height:1.7;direction:ltr;text-shadow:none;-moz-osx-font-smoothing:auto;-webkit-font-smoothing:subpixel-antialiased}.plyr audio,.plyr video{width:100%;height:auto;vertical-align:middle;border-radius:inherit}.plyr--full-ui,.plyr--full-ui *,.plyr--full-ui ::after,.plyr--full-ui ::before{box-sizing:border-box}.plyr--full-ui a,.plyr--full-ui button,.plyr--full-ui input,.plyr--full-ui label{touch-action:manipulation}.plyr__badge{padding:0 4px;border-radius:2px;background:#565d64;color:rgba(255,255,255,.9);font-size:10px;line-height:1.5;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}.plyr__control{position:relative;display:inline-block;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__control svg{width:18px;height:18px;display:block;fill:currentColor;pointer-events:none}.plyr__control .icon--pressed{display:none}.plyr__control:focus{outline:0}.plyr__control[aria-pressed=true] .icon--pressed{display:block}.plyr__control[aria-pressed=true] .icon--not-pressed{display:none}.plyr--audio .plyr__control.plyr__tab-focus,.plyr--audio .plyr__control:hover,.plyr--audio .plyr__control[aria-expanded=true]{background:#1aafff;color:#fff}.plyr__play-large{display:none;position:absolute;z-index:3;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);padding:13px;background:rgba(26,175,255,.8);border:3px solid currentColor;border-radius:100%;box-shadow:0 1px 1px rgba(0,0,0,.15);color:#fff;transition:all .3s ease}.plyr__play-large svg{position:relative;left:2px;width:20px;height:20px;display:block;fill:currentColor;pointer-events:none}.plyr__play-large:focus,.plyr__play-large:hover{background:#1aafff}.plyr__play-large:focus{outline:1px dotted rgba(255,255,255,.5)}.plyr--full-ui.plyr--video .plyr__play-large{display:inline-block}.plyr--playing .plyr__play-large{opacity:0;visibility:hidden}.plyr--full-ui video::-webkit-media-text-track-container{display:none}.plyr__captions{display:none;position:absolute;bottom:0;left:0;width:100%;padding:10px;-webkit-transform:translateY(-40px);transform:translateY(-40px);transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out;color:#fff;font-size:14px;text-align:center;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}.plyr__captions span{border-radius:2px;padding:.2em .5em;background:rgba(0,0,0,.8);-webkit-box-decoration-break:clone;box-decoration-break:clone;line-height:170%;white-space:pre-wrap}.plyr__captions span div{display:inline}.plyr__captions span:empty{display:none}@media (min-width:480px){.plyr__captions{padding:20px;font-size:16px}}@media (min-width:768px){.plyr__captions{font-size:20px}}.plyr--captions-active .plyr__captions{display:block}.plyr--hide-controls .plyr__captions{-webkit-transform:translateY(-15px);transform:translateY(-15px)}.plyr ::-webkit-media-controls{display:none}.plyr__controls{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;text-align:center}.plyr__controls .plyr__menu,.plyr__controls .plyr__progress,.plyr__controls .plyr__time,.plyr__controls>.plyr__control{margin-left:5px}.plyr__controls .plyr__menu:first-child,.plyr__controls .plyr__menu:first-child+[data-plyr=pause],.plyr__controls .plyr__progress:first-child,.plyr__controls .plyr__progress:first-child+[data-plyr=pause],.plyr__controls .plyr__time:first-child,.plyr__controls .plyr__time:first-child+[data-plyr=pause],.plyr__controls>.plyr__control:first-child,.plyr__controls>.plyr__control:first-child+[data-plyr=pause]{margin-left:0}.plyr__controls .plyr__volume{margin-left:5px}@media (min-width:480px){.plyr__controls .plyr__menu,.plyr__controls .plyr__progress,.plyr__controls .plyr__time,.plyr__controls>.plyr__control{margin-left:10px}.plyr__controls .plyr__menu+.plyr__control,.plyr__controls>.plyr__control+.plyr__control,.plyr__controls>.plyr__control+.plyr__menu{margin-left:5px}}.plyr--video .plyr__controls{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:35px 10px 10px;background:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.7));border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;color:#fff;transition:opacity .4s ease-in-out,-webkit-transform .4s ease-in-out;transition:opacity .4s ease-in-out,transform .4s ease-in-out;transition:opacity .4s ease-in-out,transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.plyr--video .plyr__controls .plyr__control svg{-webkit-filter:drop-shadow(0 1px 1px rgba(0, 0, 0, .15));filter:drop-shadow(0 1px 1px rgba(0, 0, 0, .15))}.plyr--video .plyr__controls .plyr__control.plyr__tab-focus,.plyr--video .plyr__controls .plyr__control:hover,.plyr--video .plyr__controls .plyr__control[aria-expanded=true]{background:#1aafff;color:#fff}.plyr--video.plyr--hide-controls .plyr__controls{opacity:0;-webkit-transform:translateY(100%);transform:translateY(100%);pointer-events:none}.plyr--audio .plyr__controls{padding:10px;border-radius:inherit;background:#fff;border:1px solid #dbe3e8;color:#565d64}.plyr__controls [data-plyr=pause]{display:none}.plyr--playing .plyr__controls [data-plyr=play]{display:none}.plyr--playing .plyr__controls [data-plyr=pause]{display:inline-block}.plyr [data-plyr=airplay],.plyr [data-plyr=captions],.plyr [data-plyr=fullscreen],.plyr [data-plyr=pip]{display:none}.plyr--airplay-supported [data-plyr=airplay],.plyr--captions-enabled [data-plyr=captions],.plyr--fullscreen-enabled [data-plyr=fullscreen],.plyr--pip-supported [data-plyr=pip]{display:inline-block}.plyr__video-embed{padding-bottom:56.25%;height: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.9375%);transform:translateY(-35.9375%)}.plyr--full-ui .plyr__video-embed iframe{pointer-events:none}.plyr__menu{position:relative}.plyr__menu .plyr__control svg{transition:-webkit-transform .3s ease;transition:transform .3s ease;transition:transform .3s ease,-webkit-transform .3s ease}.plyr__menu .plyr__control[aria-expanded=true] svg{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.plyr__menu .plyr__control[aria-expanded=true] .plyr__tooltip{display:none}.plyr__menu__container{position:absolute;z-index:1;bottom:100%;right:-3px;margin-bottom:10px;-webkit-animation:plyr-popup .2s ease;animation:plyr-popup .2s ease;background:rgba(255,255,255,.9);border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.15);white-space:nowrap;text-align:left;color:#565d64;font-size:14px}.plyr__menu__container>div{overflow:hidden;transition:height .35s cubic-bezier(.4,0,.2,1),width .35s cubic-bezier(.4,0,.2,1)}.plyr__menu__container::after{content:'';position:absolute;top:100%;right:15px;height:0;width:0;border:4px solid transparent;border-top-color:rgba(255,255,255,.9)}.plyr__menu__container ul{margin:0;padding:7px;list-style:none;overflow:hidden}.plyr__menu__container .plyr__control{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;width:100%;padding:4px 14px;color:#565d64;font-weight:600;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.plyr__menu__container .plyr__control::after{content:'';position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);border:4px solid transparent;transition:border-color .2s ease}.plyr__menu__container .plyr__control--forward{padding-right:28px}.plyr__menu__container .plyr__control--forward::after{right:5px;border-left-color:rgba(86,93,100,.8)}.plyr__menu__container .plyr__control--forward.plyr__tab-focus::after,.plyr__menu__container .plyr__control--forward:hover::after{border-left-color:currentColor}.plyr__menu__container .plyr__control--back{position:relative;width:calc(100% - 14px);margin:7px;margin-bottom:3px;padding-left:28px;font-weight:500}.plyr__menu__container .plyr__control--back::after{left:7px;border-right-color:rgba(86,93,100,.8)}.plyr__menu__container .plyr__control--back::before{content:'';position:absolute;top:100%;left:0;right:0;height:1px;overflow:hidden;margin-top:4px;background:#b6c5cd;box-shadow:0 1px 0 #fff}.plyr__menu__container .plyr__control--back.plyr__tab-focus::after,.plyr__menu__container .plyr__control--back:hover::after{border-right-color:currentColor}.plyr__menu__container label.plyr__control{padding-left:18px}.plyr__menu__container label.plyr__control input[type=radio]{position:relative;left:-7px}.plyr__menu__container .plyr__menu__value{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;margin-left:auto;padding-left:25px;pointer-events:none;overflow:hidden;font-weight:500}.plyr__menu__container .plyr__menu__value .plyr__badge{font-weight:600}.plyr__progress{position:relative;display:none;-webkit-box-flex:1;flex:1}.plyr__progress input[type=range]{position:relative;z-index:2}.plyr__progress .plyr__tooltip{left:0}.plyr .plyr__progress{display:inline-block}.plyr__progress--buffer{position:absolute;left:0;top:50%;width:100%;height:8px;margin:-4px 0 0;padding:0;background:0 0;border:none;border-radius:100px;-webkit-appearance:none}.plyr__progress--buffer::-webkit-progress-bar{background:0 0}.plyr__progress--buffer::-webkit-progress-value{background:currentColor;border-radius:100px;min-width:8px}.plyr__progress--buffer::-moz-progress-bar{background:currentColor;border-radius:100px;min-width:8px}.plyr__progress--buffer::-ms-fill{border-radius:100px}.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{box-shadow:0 1px 1px rgba(0,0,0,.15);color:rgba(255,255,255,.25)}.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(52,63,74,.2) 25%,transparent 25%,transparent 50%,rgba(52,63,74,.2) 50%,rgba(52,63,74,.2) 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--full-ui input[type=range]{display:block;height:20px;width:100%;margin:0;padding:0;cursor:pointer;border:none;background:0 0;color:#1aafff;-webkit-appearance:none}.plyr--full-ui 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--full-ui 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,-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(52,63,74,.2);box-sizing:border-box}.plyr--full-ui input[type=range]::-moz-range-track{height:8px;background:0 0;border:0;border-radius:4px;-moz-user-select:none;user-select:none}.plyr--full-ui 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,-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(52,63,74,.2);box-sizing:border-box}.plyr--full-ui input[type=range]::-moz-range-progress{height:8px;background:currentColor;border-radius:4px}.plyr--full-ui input[type=range]::-ms-track{color:transparent;height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-ms-fill-upper{height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-ms-fill-lower{height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none;background:currentColor}.plyr--full-ui 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,-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(52,63,74,.2);box-sizing:border-box;margin-top:0}.plyr--full-ui input[type=range]::-ms-tooltip{display:none}.plyr--full-ui input[type=range]:focus{outline:0}.plyr--full-ui input[type=range]::-moz-focus-outer{border:0}.plyr--full-ui input[type=range].plyr__tab-focus{outline-offset:3px}.plyr--full-ui input[type=range]:active::-webkit-slider-thumb{background:#1aafff;border-color:#fff;-webkit-transform:scale(1.25);transform:scale(1.25)}.plyr--full-ui input[type=range]:active::-moz-range-thumb{background:#1aafff;border-color:#fff;transform:scale(1.25)}.plyr--full-ui input[type=range]:active::-ms-thumb{background:#1aafff;border-color:#fff;transform:scale(1.25)}.plyr--full-ui.plyr--video input[type=range]::-webkit-slider-runnable-track{background:rgba(255,255,255,.25)}.plyr--full-ui.plyr--video input[type=range]::-moz-range-track{background:rgba(255,255,255,.25)}.plyr--full-ui.plyr--video input[type=range]::-ms-track{background:rgba(255,255,255,.25)}.plyr--full-ui.plyr--video input[type=range].plyr__tab-focus{outline:1px dotted rgba(255,255,255,.5)}.plyr--full-ui.plyr--audio input[type=range]::-webkit-slider-runnable-track{background:rgba(198,214,219,.66)}.plyr--full-ui.plyr--audio input[type=range]::-moz-range-track{background:rgba(198,214,219,.66)}.plyr--full-ui.plyr--audio input[type=range]::-ms-track{background:rgba(198,214,219,.66)}.plyr--full-ui.plyr--audio input[type=range].plyr__tab-focus{outline:1px dotted rgba(86,93,100,.5)}.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--video .plyr__time{text-shadow:0 1px 1px rgba(0,0,0,.15)}.plyr__tooltip{position:absolute;z-index:2;bottom:100%;margin-bottom:10px;padding:5px 7.5px;pointer-events:none;opacity:0;background:rgba(255,255,255,.9);border-radius:3px;box-shadow:0 1px 2px rgba(0,0,0,.15);color:#565d64;font-size:14px;font-weight:500;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%;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(255,255,255,.9);border-left:4px solid transparent;z-index:2}.plyr .plyr__control.plyr__tab-focus .plyr__tooltip,.plyr .plyr__control:hover .plyr__tooltip,.plyr__tooltip--visible{opacity:1;-webkit-transform:translate(-50%,0) scale(1);transform:translate(-50%,0) scale(1)}.plyr .plyr__control:hover .plyr__tooltip{z-index:3}.plyr__controls>.plyr__control:first-child .plyr__tooltip,.plyr__controls>.plyr__control:first-child+.plyr__control .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>.plyr__control:first-child .plyr__tooltip::before,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip::before{left:16px}.plyr__controls>.plyr__control: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>.plyr__control:last-child .plyr__tooltip::before{left:auto;right:16px;-webkit-transform:translateX(50%);transform:translateX(50%)}.plyr__controls>.plyr__control:first-child .plyr__tooltip--visible,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip--visible,.plyr__controls>.plyr__control:first-child+.plyr__control.plyr__tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:first-child+.plyr__control:hover .plyr__tooltip,.plyr__controls>.plyr__control:first-child.plyr__tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:first-child:hover .plyr__tooltip,.plyr__controls>.plyr__control:last-child .plyr__tooltip--visible,.plyr__controls>.plyr__control:last-child.plyr__tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:last-child:hover .plyr__tooltip{-webkit-transform:translate(0,0) scale(1);transform:translate(0,0) scale(1)}.plyr--video{overflow:hidden}.plyr__video-wrapper{position:relative;background:#000;border-radius:inherit;z-index:0;overflow:hidden}.plyr__volume{-webkit-box-flex:1;flex:1;position:relative}.plyr__volume input[type=range]{position:relative;z-index:2}@media (min-width:480px){.plyr__volume{display:block;max-width:60px}}@media (min-width:768px){.plyr__volume{max-width:100px}}.plyr--is-ios .plyr__volume,.plyr--is-ios [data-plyr=mute]{display:none!important}.plyr:-webkit-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-moz-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-ms-fullscreen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:fullscreen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-webkit-full-screen video{height:100%}.plyr:-moz-full-screen video{height:100%}.plyr:-ms-fullscreen video{height:100%}.plyr:fullscreen video{height:100%}.plyr:-webkit-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-moz-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-ms-fullscreen .plyr__video-wrapper{height:100%;width:100%}.plyr:fullscreen .plyr__video-wrapper{height:100%;width:100%}.plyr:-webkit-full-screen .plyr__video-embed{overflow:visible}.plyr:-moz-full-screen .plyr__video-embed{overflow:visible}.plyr:-ms-fullscreen .plyr__video-embed{overflow:visible}.plyr:fullscreen .plyr__video-embed{overflow:visible}.plyr:-webkit-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr:-moz-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:-ms-fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-webkit-full-screen .plyr__captions{font-size:24px}.plyr:-moz-full-screen .plyr__captions{font-size:24px}.plyr:-ms-fullscreen .plyr__captions{font-size:24px}.plyr:fullscreen .plyr__captions{font-size:24px}}.plyr:-webkit-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-webkit-full-screen video{height:100%}.plyr:-webkit-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-webkit-full-screen .plyr__video-embed{overflow:visible}.plyr:-webkit-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-webkit-full-screen .plyr__captions{font-size:24px}}.plyr:-moz-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-moz-full-screen video{height:100%}.plyr:-moz-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-moz-full-screen .plyr__video-embed{overflow:visible}.plyr:-moz-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-moz-full-screen .plyr__captions{font-size:24px}}.plyr:-ms-fullscreen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-ms-fullscreen video{height:100%}.plyr:-ms-fullscreen .plyr__video-wrapper{height:100%;width:100%}.plyr:-ms-fullscreen .plyr__video-embed{overflow:visible}.plyr:-ms-fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-ms-fullscreen .plyr__captions{font-size:24px}}.plyr--fullscreen-fallback{height:100%;width:100%;background:#000;border-radius:0!important;position:fixed;top:0;left:0;right:0;bottom:0;z-index:10000000}.plyr--fullscreen-fallback video{height:100%}.plyr--fullscreen-fallback .plyr__video-wrapper{height:100%;width:100%}.plyr--fullscreen-fallback .plyr__video-embed{overflow:visible}.plyr--fullscreen-fallback.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr--fullscreen-fallback .plyr__control .icon--exit-fullscreen{display:block}.plyr--fullscreen-fallback .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr--fullscreen-fallback .plyr__captions{font-size:24px}}.plyr--full-ui [hidden]{display:none}.plyr--full-ui [aria-hidden=true]{display:none}.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}
\ No newline at end of file +@-webkit-keyframes plyr-progress{to{background-position:25px 0}}@keyframes plyr-progress{to{background-position:25px 0}}@-webkit-keyframes plyr-popup{from{-webkit-transform:translateY(10px);transform:translateY(10px);opacity:.5}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes plyr-popup{from{-webkit-transform:translateY(10px);transform:translateY(10px);opacity:.5}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}.plyr{position:relative;max-width:100%;min-width:200px;font-family:Avenir,'Avenir Next','Helvetica Neue','Segoe UI',Helvetica,Arial,sans-serif;font-weight:500;line-height:1.7;direction:ltr;text-shadow:none;transition:box-shadow .3s ease;-moz-osx-font-smoothing:auto;-webkit-font-smoothing:subpixel-antialiased}.plyr audio,.plyr video{width:100%;height:auto;vertical-align:middle;border-radius:inherit}.plyr:focus{outline:0;box-shadow:0 0 0 3px rgba(0,0,0,.1)}.plyr--full-ui,.plyr--full-ui *,.plyr--full-ui ::after,.plyr--full-ui ::before{box-sizing:border-box}.plyr--full-ui a,.plyr--full-ui button,.plyr--full-ui input,.plyr--full-ui label{touch-action:manipulation}.plyr__badge{padding:3px 4px;border-radius:2px;background:#565d64;color:rgba(255,255,255,.9);font-size:10px;line-height:1;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}.plyr__control{position:relative;display:inline-block;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__control svg{width:18px;height:18px;display:block;fill:currentColor;pointer-events:none}.plyr__control .icon--pressed{display:none}.plyr__control:focus{outline:0}.plyr__control[aria-pressed=true] .icon--pressed{display:block}.plyr__control[aria-pressed=true] .icon--not-pressed{display:none}.plyr--audio .plyr__control.plyr__tab-focus,.plyr--audio .plyr__control:hover,.plyr--audio .plyr__control[aria-expanded=true]{background:#1aafff;color:#fff}.plyr__play-large{display:none;position:absolute;z-index:3;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);padding:15px;background:rgba(26,175,255,.8);border:0;border-radius:100%;box-shadow:0 1px 1px rgba(0,0,0,.15);color:#fff;transition:all .3s ease}.plyr__play-large svg{position:relative;left:2px;width:20px;height:20px;display:block;fill:currentColor;pointer-events:none}.plyr__play-large:focus,.plyr__play-large:hover{background:#1aafff}.plyr__play-large:focus{outline:0}.plyr__play-large.plyr__tab-focus{outline:0;box-shadow:0 0 0 3px rgba(255,255,255,.5)}.plyr--full-ui.plyr--video .plyr__play-large{display:inline-block}.plyr--playing .plyr__play-large{opacity:0;visibility:hidden}.plyr--full-ui video::-webkit-media-text-track-container{display:none}.plyr__captions{display:none;position:absolute;bottom:0;left:0;width:100%;padding:10px;-webkit-transform:translateY(-40px);transform:translateY(-40px);transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out;color:#fff;font-size:14px;text-align:center;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}.plyr__captions span{border-radius:2px;padding:.2em .5em;background:rgba(0,0,0,.8);-webkit-box-decoration-break:clone;box-decoration-break:clone;line-height:170%;white-space:pre-wrap}.plyr__captions span div{display:inline}.plyr__captions span:empty{display:none}@media (min-width:480px){.plyr__captions{padding:20px;font-size:16px}}@media (min-width:768px){.plyr__captions{font-size:20px}}.plyr--captions-active .plyr__captions{display:block}.plyr--hide-controls .plyr__captions{-webkit-transform:translateY(-15px);transform:translateY(-15px)}.plyr ::-webkit-media-controls{display:none}.plyr__controls{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;text-align:center}.plyr__controls .plyr__menu,.plyr__controls .plyr__progress,.plyr__controls .plyr__time,.plyr__controls>.plyr__control{margin-left:5px}.plyr__controls .plyr__menu:first-child,.plyr__controls .plyr__menu:first-child+[data-plyr=pause],.plyr__controls .plyr__progress:first-child,.plyr__controls .plyr__progress:first-child+[data-plyr=pause],.plyr__controls .plyr__time:first-child,.plyr__controls .plyr__time:first-child+[data-plyr=pause],.plyr__controls>.plyr__control:first-child,.plyr__controls>.plyr__control:first-child+[data-plyr=pause]{margin-left:0}.plyr__controls .plyr__volume{margin-left:5px}@media (min-width:480px){.plyr__controls .plyr__menu,.plyr__controls .plyr__progress,.plyr__controls .plyr__time,.plyr__controls>.plyr__control{margin-left:10px}.plyr__controls .plyr__menu+.plyr__control,.plyr__controls>.plyr__control+.plyr__control,.plyr__controls>.plyr__control+.plyr__menu{margin-left:5px}}.plyr--video .plyr__controls{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:35px 10px 10px;background:linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.7));border-bottom-left-radius:inherit;border-bottom-right-radius:inherit;color:#fff;transition:opacity .4s ease-in-out,-webkit-transform .4s ease-in-out;transition:opacity .4s ease-in-out,transform .4s ease-in-out;transition:opacity .4s ease-in-out,transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.plyr--video .plyr__controls .plyr__control svg{-webkit-filter:drop-shadow(0 1px 1px rgba(0, 0, 0, .15));filter:drop-shadow(0 1px 1px rgba(0, 0, 0, .15))}.plyr--video .plyr__controls .plyr__control.plyr__tab-focus,.plyr--video .plyr__controls .plyr__control:hover,.plyr--video .plyr__controls .plyr__control[aria-expanded=true]{background:#1aafff;color:#fff}.plyr--video.plyr--hide-controls .plyr__controls{opacity:0;-webkit-transform:translateY(100%);transform:translateY(100%);pointer-events:none}.plyr--audio .plyr__controls{padding:10px;border-radius:inherit;background:#fff;border:1px solid #dbe3e8;color:#565d64}.plyr__controls [data-plyr=pause]{display:none}.plyr--playing .plyr__controls [data-plyr=play]{display:none}.plyr--playing .plyr__controls [data-plyr=pause]{display:inline-block}.plyr [data-plyr=airplay],.plyr [data-plyr=captions],.plyr [data-plyr=fullscreen],.plyr [data-plyr=pip]{display:none}.plyr--airplay-supported [data-plyr=airplay],.plyr--captions-enabled [data-plyr=captions],.plyr--fullscreen-enabled [data-plyr=fullscreen],.plyr--pip-supported [data-plyr=pip]{display:inline-block}.plyr__video-embed{padding-bottom:56.25%;height: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.9375%);transform:translateY(-35.9375%)}.plyr--full-ui .plyr__video-embed iframe{pointer-events:none}.plyr__menu{position:relative}.plyr__menu .plyr__control svg{transition:-webkit-transform .3s ease;transition:transform .3s ease;transition:transform .3s ease,-webkit-transform .3s ease}.plyr__menu .plyr__control[aria-expanded=true] svg{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.plyr__menu .plyr__control[aria-expanded=true] .plyr__tooltip{display:none}.plyr__menu__container{position:absolute;z-index:1;bottom:100%;right:-3px;margin-bottom:10px;-webkit-animation:plyr-popup .2s ease;animation:plyr-popup .2s ease;background:rgba(255,255,255,.9);border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.15);white-space:nowrap;text-align:left;color:#565d64;font-size:14px}.plyr__menu__container>div{overflow:hidden;transition:height .35s cubic-bezier(.4,0,.2,1),width .35s cubic-bezier(.4,0,.2,1)}.plyr__menu__container::after{content:'';position:absolute;top:100%;right:15px;height:0;width:0;border:4px solid transparent;border-top-color:rgba(255,255,255,.9)}.plyr__menu__container ul{margin:0;padding:7px;list-style:none;overflow:hidden}.plyr__menu__container .plyr__control{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;width:100%;padding:4px 14px;color:#565d64;font-weight:600;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.plyr__menu__container .plyr__control::after{content:'';position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);border:4px solid transparent;transition:border-color .2s ease}.plyr__menu__container .plyr__control--forward{padding-right:28px}.plyr__menu__container .plyr__control--forward::after{right:5px;border-left-color:rgba(86,93,100,.8)}.plyr__menu__container .plyr__control--forward.plyr__tab-focus::after,.plyr__menu__container .plyr__control--forward:hover::after{border-left-color:currentColor}.plyr__menu__container .plyr__control--back{position:relative;width:calc(100% - 14px);margin:7px;margin-bottom:3px;padding-left:28px;font-weight:500}.plyr__menu__container .plyr__control--back::after{left:7px;border-right-color:rgba(86,93,100,.8)}.plyr__menu__container .plyr__control--back::before{content:'';position:absolute;top:100%;left:0;right:0;height:1px;overflow:hidden;margin-top:4px;background:#b6c5cd;box-shadow:0 1px 0 #fff}.plyr__menu__container .plyr__control--back.plyr__tab-focus::after,.plyr__menu__container .plyr__control--back:hover::after{border-right-color:currentColor}.plyr__menu__container label.plyr__control{padding-left:7px}.plyr__menu__container label.plyr__control input[type=radio]+span{position:relative;display:block;height:14px;width:14px;border-radius:100%;background:rgba(0,0,0,.1);margin-right:10px;box-shadow:inset 0 1px 1px rgba(0,0,0,.15)}.plyr__menu__container label.plyr__control input[type=radio]+span::after{content:'';position:absolute;height:6px;width:6px;top:4px;left:4px;-webkit-transform:scale(0);transform:scale(0);opacity:0;background:#fff;border-radius:100%;transition:opacity .3s ease,-webkit-transform .3s ease;transition:transform .3s ease,opacity .3s ease;transition:transform .3s ease,opacity .3s ease,-webkit-transform .3s ease}.plyr__menu__container label.plyr__control input[type=radio]:checked+span{background:#1aafff}.plyr__menu__container label.plyr__control input[type=radio]:checked+span::after{-webkit-transform:scale(1);transform:scale(1);opacity:1}.plyr__menu__container .plyr__menu__value{display:-webkit-box;display:flex;-webkit-box-align:center;align-items:center;margin-left:auto;padding-left:25px;pointer-events:none;overflow:hidden;font-weight:500}.plyr__menu__container .plyr__menu__value .plyr__badge{font-weight:600}.plyr__progress{position:relative;display:none;-webkit-box-flex:1;flex:1}.plyr__progress input[type=range]{position:relative;z-index:2}.plyr__progress .plyr__tooltip{left:0}.plyr .plyr__progress{display:inline-block}.plyr__progress--buffer{position:absolute;left:0;top:50%;width:100%;height:8px;margin:-4px 0 0;padding:0;background:0 0;border:none;border-radius:100px;-webkit-appearance:none}.plyr__progress--buffer::-webkit-progress-bar{background:0 0}.plyr__progress--buffer::-webkit-progress-value{background:currentColor;border-radius:100px;min-width:8px}.plyr__progress--buffer::-moz-progress-bar{background:currentColor;border-radius:100px;min-width:8px}.plyr__progress--buffer::-ms-fill{border-radius:100px}.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{box-shadow:0 1px 1px rgba(0,0,0,.15);color:rgba(255,255,255,.25)}.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(52,63,74,.2) 25%,transparent 25%,transparent 50%,rgba(52,63,74,.2) 50%,rgba(52,63,74,.2) 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--full-ui input[type=range]{display:block;height:20px;width:100%;margin:0;padding:0;cursor:pointer;border:none;background:0 0;transition:box-shadow .3s ease;border-radius:32px;color:#1aafff;-webkit-appearance:none}.plyr--full-ui 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--full-ui 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,-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(52,63,74,.2);box-sizing:border-box}.plyr--full-ui input[type=range]::-moz-range-track{height:8px;background:0 0;border:0;border-radius:4px;-moz-user-select:none;user-select:none}.plyr--full-ui 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,-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(52,63,74,.2);box-sizing:border-box}.plyr--full-ui input[type=range]::-moz-range-progress{height:8px;background:currentColor;border-radius:4px}.plyr--full-ui input[type=range]::-ms-track{color:transparent;height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-ms-fill-upper{height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none}.plyr--full-ui input[type=range]::-ms-fill-lower{height:8px;background:0 0;border:0;border-radius:4px;-ms-user-select:none;user-select:none;background:currentColor}.plyr--full-ui 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,-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(52,63,74,.2);box-sizing:border-box;margin-top:0}.plyr--full-ui input[type=range]::-ms-tooltip{display:none}.plyr--full-ui input[type=range]:focus{outline:0}.plyr--full-ui input[type=range]::-moz-focus-outer{border:0}.plyr--full-ui input[type=range]:active::-webkit-slider-thumb{background:#1aafff;border-color:#fff;-webkit-transform:scale(1.25);transform:scale(1.25)}.plyr--full-ui input[type=range]:active::-moz-range-thumb{background:#1aafff;border-color:#fff;transform:scale(1.25)}.plyr--full-ui input[type=range]:active::-ms-thumb{background:#1aafff;border-color:#fff;transform:scale(1.25)}.plyr--full-ui.plyr--video input[type=range]::-webkit-slider-runnable-track{background:rgba(255,255,255,.25)}.plyr--full-ui.plyr--video input[type=range]::-moz-range-track{background:rgba(255,255,255,.25)}.plyr--full-ui.plyr--video input[type=range]::-ms-track{background:rgba(255,255,255,.25)}.plyr--full-ui.plyr--video input[type=range].plyr__tab-focus{box-shadow:0 0 0 3px rgba(255,255,255,.5)}.plyr--full-ui.plyr--audio input[type=range]::-webkit-slider-runnable-track{background:rgba(198,214,219,.66)}.plyr--full-ui.plyr--audio input[type=range]::-moz-range-track{background:rgba(198,214,219,.66)}.plyr--full-ui.plyr--audio input[type=range]::-ms-track{background:rgba(198,214,219,.66)}.plyr--full-ui.plyr--audio input[type=range].plyr__tab-focus{box-shadow:0 0 0 3px rgba(86,93,100,.5)}.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--video .plyr__time{text-shadow:0 1px 1px rgba(0,0,0,.15)}.plyr__tooltip{position:absolute;z-index:2;bottom:100%;margin-bottom:10px;padding:5px 7.5px;pointer-events:none;opacity:0;background:rgba(255,255,255,.9);border-radius:3px;box-shadow:0 1px 2px rgba(0,0,0,.15);color:#565d64;font-size:14px;font-weight:500;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%;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(255,255,255,.9);border-left:4px solid transparent;z-index:2}.plyr .plyr__control.plyr__tab-focus .plyr__tooltip,.plyr .plyr__control:hover .plyr__tooltip,.plyr__tooltip--visible{opacity:1;-webkit-transform:translate(-50%,0) scale(1);transform:translate(-50%,0) scale(1)}.plyr .plyr__control:hover .plyr__tooltip{z-index:3}.plyr__controls>.plyr__control:first-child .plyr__tooltip,.plyr__controls>.plyr__control:first-child+.plyr__control .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>.plyr__control:first-child .plyr__tooltip::before,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip::before{left:16px}.plyr__controls>.plyr__control: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>.plyr__control:last-child .plyr__tooltip::before{left:auto;right:16px;-webkit-transform:translateX(50%);transform:translateX(50%)}.plyr__controls>.plyr__control:first-child .plyr__tooltip--visible,.plyr__controls>.plyr__control:first-child+.plyr__control .plyr__tooltip--visible,.plyr__controls>.plyr__control:first-child+.plyr__control.plyr__tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:first-child+.plyr__control:hover .plyr__tooltip,.plyr__controls>.plyr__control:first-child.plyr__tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:first-child:hover .plyr__tooltip,.plyr__controls>.plyr__control:last-child .plyr__tooltip--visible,.plyr__controls>.plyr__control:last-child.plyr__tab-focus .plyr__tooltip,.plyr__controls>.plyr__control:last-child:hover .plyr__tooltip{-webkit-transform:translate(0,0) scale(1);transform:translate(0,0) scale(1)}.plyr--video{overflow:hidden}.plyr__video-wrapper{position:relative;background:#000;border-radius:inherit;z-index:0;overflow:hidden}.plyr__volume{-webkit-box-flex:1;flex:1;position:relative}.plyr__volume input[type=range]{position:relative;z-index:2}@media (min-width:480px){.plyr__volume{display:block;max-width:60px}}@media (min-width:768px){.plyr__volume{max-width:100px}}.plyr--is-ios .plyr__volume,.plyr--is-ios [data-plyr=mute]{display:none!important}.plyr:-webkit-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-moz-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-ms-fullscreen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:fullscreen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-webkit-full-screen video{height:100%}.plyr:-moz-full-screen video{height:100%}.plyr:-ms-fullscreen video{height:100%}.plyr:fullscreen video{height:100%}.plyr:-webkit-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-moz-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-ms-fullscreen .plyr__video-wrapper{height:100%;width:100%}.plyr:fullscreen .plyr__video-wrapper{height:100%;width:100%}.plyr:-webkit-full-screen .plyr__video-embed{overflow:visible}.plyr:-moz-full-screen .plyr__video-embed{overflow:visible}.plyr:-ms-fullscreen .plyr__video-embed{overflow:visible}.plyr:fullscreen .plyr__video-embed{overflow:visible}.plyr:-webkit-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr:-moz-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:-ms-fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}.plyr:fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-webkit-full-screen .plyr__captions{font-size:24px}.plyr:-moz-full-screen .plyr__captions{font-size:24px}.plyr:-ms-fullscreen .plyr__captions{font-size:24px}.plyr:fullscreen .plyr__captions{font-size:24px}}.plyr:-webkit-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-webkit-full-screen video{height:100%}.plyr:-webkit-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-webkit-full-screen .plyr__video-embed{overflow:visible}.plyr:-webkit-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-webkit-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-webkit-full-screen .plyr__captions{font-size:24px}}.plyr:-moz-full-screen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-moz-full-screen video{height:100%}.plyr:-moz-full-screen .plyr__video-wrapper{height:100%;width:100%}.plyr:-moz-full-screen .plyr__video-embed{overflow:visible}.plyr:-moz-full-screen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-moz-full-screen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-moz-full-screen .plyr__captions{font-size:24px}}.plyr:-ms-fullscreen{height:100%;width:100%;background:#000;border-radius:0!important}.plyr:-ms-fullscreen video{height:100%}.plyr:-ms-fullscreen .plyr__video-wrapper{height:100%;width:100%}.plyr:-ms-fullscreen .plyr__video-embed{overflow:visible}.plyr:-ms-fullscreen.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;transform:translateY(-50%)}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen{display:block}.plyr:-ms-fullscreen .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr:-ms-fullscreen .plyr__captions{font-size:24px}}.plyr--fullscreen-fallback{height:100%;width:100%;background:#000;border-radius:0!important;position:fixed;top:0;left:0;right:0;bottom:0;z-index:10000000}.plyr--fullscreen-fallback video{height:100%}.plyr--fullscreen-fallback .plyr__video-wrapper{height:100%;width:100%}.plyr--fullscreen-fallback .plyr__video-embed{overflow:visible}.plyr--fullscreen-fallback.plyr--vimeo .plyr__video-wrapper{height:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.plyr--fullscreen-fallback .plyr__control .icon--exit-fullscreen{display:block}.plyr--fullscreen-fallback .plyr__control .icon--exit-fullscreen+svg{display:none}@media (min-width:1024px){.plyr--fullscreen-fallback .plyr__captions{font-size:24px}}.plyr--no-transition{transition:none!important}.plyr--full-ui [hidden]{display:none}.plyr--full-ui [aria-hidden=true]{display:none}.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}
\ No newline at end of file diff --git a/dist/plyr.js b/dist/plyr.js index 37518b97..0812a58b 100644 --- a/dist/plyr.js +++ b/dist/plyr.js @@ -1,3 +1,3 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define("Plyr",t):e.Plyr=t()}(this,function(){"use strict";function e(){var e=window.localStorage.getItem(this.config.storage.key);return s.is.empty(e)?{}:JSON.parse(e)}function t(t){if(a.storage&&this.config.storage.enabled&&s.is.object(t)){var i=e.call(this);s.extend(i,t),window.localStorage.setItem(this.config.storage.key,JSON.stringify(i))}}var i={enabled:!0,title:"",debug:!1,autoplay:!1,seekTime:10,volume:1,muted:!1,duration:null,displayDuration:!0,ratio:"16:9",clickToPlay:!0,hideControls:!0,showPosterOnEnd:!1,disableContextMenu:!0,loadSprite:!0,iconPrefix:"plyr",iconUrl:"https://cdn.plyr.io/2.0.10/plyr.svg",blankVideo:"https://cdn.plyr.io/static/blank.mp4",quality:{default:"default",options:["hd2160","hd1440","hd1080","hd720","large","medium","small","tiny","default"]},loop:{active:!1},speed:{selected:1,options:[.5,.75,1,1.25,1.5,1.75,2]},keyboard:{focused:!0,global:!1},tooltips:{controls:!1,seek:!0},captions:{active:!1,language:window.navigator.language.split("-")[0]},fullscreen:{enabled:!0,fallback:!0},storage:{enabled:!0,key:"plyr"},controls:["play-large","play","progress","current-time","mute","volume","captions","settings","pip","airplay","fullscreen"],settings:["captions","quality","speed","loop"],i18n:{restart:"Restart",rewind:"Rewind {seektime} secs",play:"Play",pause:"Pause",forward:"Forward {seektime} secs",seek:"Seek",played:"Played",buffered:"Buffered",currentTime:"Current time",duration:"Duration",volume:"Volume",toggleMute:"Toggle Mute",toggleCaptions:"Toggle Captions",toggleFullscreen:"Toggle Fullscreen",frameTitle:"Player for {title}",captions:"Captions",settings:"Settings",speed:"Speed",quality:"Quality",loop:"Loop",start:"Start",end:"End",all:"All",reset:"Reset",none:"None",disabled:"Disabled"},urls:{vimeo:{api:"https://player.vimeo.com/api/player.js"},youtube:{api:"https://www.youtube.com/iframe_api"}},listeners:{seek:null,play:null,pause:null,restart:null,rewind:null,forward:null,mute:null,volume:null,captions:null,fullscreen:null,pip:null,airplay:null,speed:null,quality:null,loop:null,language:null},events:["ended","progress","stalled","playing","waiting","canplay","canplaythrough","loadstart","loadeddata","loadedmetadata","timeupdate","volumechange","play","pause","error","seeking","seeked","emptied","ratechange","cuechange","enterfullscreen","exitfullscreen","captionsenabled","captionsdisabled","languagechange","controlshidden","controlsshown","ready","statechange","qualitychange","qualityrequested"],selectors:{editable:"input, textarea, select, [contenteditable]",container:".plyr",controls:{container:null,wrapper:".plyr__controls"},labels:"[data-plyr]",buttons:{play:'[data-plyr="play"]',pause:'[data-plyr="pause"]',restart:'[data-plyr="restart"]',rewind:'[data-plyr="rewind"]',forward:'[data-plyr="fast-forward"]',mute:'[data-plyr="mute"]',captions:'[data-plyr="captions"]',fullscreen:'[data-plyr="fullscreen"]',pip:'[data-plyr="pip"]',airplay:'[data-plyr="airplay"]',settings:'[data-plyr="settings"]',loop:'[data-plyr="loop"]'},inputs:{seek:'[data-plyr="seek"]',volume:'[data-plyr="volume"]',speed:'[data-plyr="speed"]',language:'[data-plyr="language"]',quality:'[data-plyr="quality"]'},display:{currentTime:".plyr__time--current",duration:".plyr__time--duration",buffer:".plyr__progress--buffer",played:".plyr__progress--played",loop:".plyr__progress--loop",volume:".plyr__volume--display"},progress:".plyr__progress",captions:".plyr__captions",menu:{quality:".js-plyr__menu__list--quality"}},classNames:{video:"plyr__video-wrapper",embed:"plyr__video-embed",control:"plyr__control",type:"plyr--{0}",stopped:"plyr--stopped",playing:"plyr--playing",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",uiSupported:"plyr--full-ui",menu:{value:"plyr__menu__value",badge:"plyr__badge"},captions:{enabled:"plyr--captions-enabled",active:"plyr--captions-active"},fullscreen:{enabled:"plyr--fullscreen-enabled",fallback:"plyr--fullscreen-fallback"},pip:{supported:"plyr--pip-supported",active:"plyr--pip-active"},airplay:{supported:"plyr--airplay-supported",active:"plyr--airplay-active"},tabFocus:"plyr__tab-focus"}},n={embed:["youtube","vimeo"],html5:["video","audio"]},s={is:{object:function(e){return this.getConstructor(e)===Object},number:function(e){return this.getConstructor(e)===Number&&!Number.isNaN(e)},string:function(e){return this.getConstructor(e)===String},boolean:function(e){return this.getConstructor(e)===Boolean},function:function(e){return this.getConstructor(e)===Function},array:function(e){return!this.undefined(e)&&Array.isArray(e)},nodeList:function(e){return!this.undefined(e)&&e instanceof NodeList},htmlElement:function(e){return!this.undefined(e)&&e instanceof HTMLElement},event:function(e){return!this.undefined(e)&&e instanceof Event},cue:function(e){return this.instanceOf(e,window.TextTrackCue)||this.instanceOf(e,window.VTTCue)},track:function(e){return!this.undefined(e)&&(this.instanceOf(e,window.TextTrack)||"string"==typeof e.kind)},undefined:function(e){return null!==e&&void 0===e},empty:function(e){return null===e||void 0===e||(this.string(e)||this.array(e)||this.nodeList(e))&&0===e.length||this.object(e)&&0===Object.keys(e).length},getConstructor:function(e){return null===e||void 0===e?null:e.constructor},instanceOf:function(e,t){return Boolean(e&&t&&e instanceof t)}},getBrowser:function(){return{isIE:!!document.documentMode,isWebkit:"WebkitAppearance"in document.documentElement.style&&!/Edge/.test(navigator.userAgent),isIPhone:/(iPhone|iPod)/gi.test(navigator.platform),isIos:/(iPad|iPhone|iPod)/gi.test(navigator.platform)}},loadScript:function(e,t){if(!document.querySelectorAll('script[src="'+e+'"]').length){var i=document.createElement("script");i.src=e;var n=document.getElementsByTagName("script")[0];s.is.function(t)&&i.addEventListener("load",function(e){return t.call(null,e)},!1),n.parentNode.insertBefore(i,n)}},loadSprite:function(e,t){function i(e){this.innerHTML=e,document.body.insertBefore(this,document.body.childNodes[0])}if(s.is.string(e)){var n=s.is.string(t);if(!n||!document.querySelectorAll("#"+t).length){var l=document.createElement("div");if(l.setAttribute("hidden",""),n&&l.setAttribute("id",t),a.storage){var o=window.localStorage.getItem("cache-"+t);if(null!==o){var r=JSON.parse(o);return void i.call(l,r.content)}}fetch(e).then(function(e){return e.text()}).then(function(e){a.storage&&window.localStorage.setItem("cache-"+t,JSON.stringify({content:e})),i.call(l,e)})}}},generateId:function(e){return e+"-"+Math.floor(1e4*Math.random())},inFrame:function(){try{return window.self!==window.top}catch(e){return!0}},wrap:function(e,t){var i=e.length?e:[e];Array.from(i).reverse().forEach(function(e,i){var n=i>0?t.cloneNode(!0):t,s=e.parentNode,a=e.nextSibling;n.appendChild(e),a?s.insertBefore(n,a):s.appendChild(n)})},removeElement:function(e){return s.is.htmlElement(e)&&s.is.htmlElement(e.parentNode)?(e.parentNode.removeChild(e),e):null},insertAfter:function(e,t){t.parentNode.insertBefore(e,t.nextSibling)},createElement:function(e,t,i){var n=document.createElement(e);return s.is.object(t)&&s.setAttributes(n,t),s.is.string(i)&&(n.textContent=i),n},insertElement:function(e,t,i,n){t.appendChild(s.createElement(e,i,n))},emptyElement:function(e){for(var t=e.childNodes.length;t>0;)e.removeChild(e.lastChild),t-=1},setAttributes:function(e,t){Object.keys(t).forEach(function(i){e.setAttribute(i,t[i])})},getAttributesFromSelector:function(e,t){if(!s.is.string(e)||s.is.empty(e))return{};var i={},n=t;return e.split(",").forEach(function(e){var t=e.trim(),a=t.replace(".",""),l=t.replace(/[[\]]/g,"").split("="),o=l[0],r=l.length>1?l[1].replace(/["']/g,""):"";switch(t.charAt(0)){case".":s.is.object(n)&&s.is.string(n.class)&&(n.class+=" "+a),i.class=a;break;case"#":i.id=t.replace("#","");break;case"[":i[o]=r}}),i},toggleClass:function(e,t,i){if(s.is.htmlElement(e)){var n=e.classList.contains(t);return e.classList[i?"add":"remove"](t),i&&!n||!i&&n}return null},hasClass:function(e,t){return s.is.htmlElement(e)&&e.classList.contains(t)},matches:function(e,t){var i={Element:Element},n=i.matches||i.webkitMatchesSelector||i.mozMatchesSelector||i.msMatchesSelector||function(){return Array.from(document.querySelectorAll(t)).includes(this)};return n.call(e,t)},getElements:function(e){return this.elements.container.querySelectorAll(e)},getElement:function(e){return this.elements.container.querySelector(e)},findElements:function(){try{return this.elements.controls=s.getElement.call(this,this.config.selectors.controls.wrapper),this.elements.buttons={play:s.getElements.call(this,this.config.selectors.buttons.play),pause:s.getElement.call(this,this.config.selectors.buttons.pause),restart:s.getElement.call(this,this.config.selectors.buttons.restart),rewind:s.getElement.call(this,this.config.selectors.buttons.rewind),forward:s.getElement.call(this,this.config.selectors.buttons.forward),mute:s.getElement.call(this,this.config.selectors.buttons.mute),pip:s.getElement.call(this,this.config.selectors.buttons.pip),airplay:s.getElement.call(this,this.config.selectors.buttons.airplay),settings:s.getElement.call(this,this.config.selectors.buttons.settings),captions:s.getElement.call(this,this.config.selectors.buttons.captions),fullscreen:s.getElement.call(this,this.config.selectors.buttons.fullscreen)},this.elements.progress=s.getElement.call(this,this.config.selectors.progress),this.elements.inputs={seek:s.getElement.call(this,this.config.selectors.inputs.seek),volume:s.getElement.call(this,this.config.selectors.inputs.volume)},this.elements.display={buffer:s.getElement.call(this,this.config.selectors.display.buffer),duration:s.getElement.call(this,this.config.selectors.display.duration),currentTime:s.getElement.call(this,this.config.selectors.display.currentTime)},s.is.htmlElement(this.elements.progress)&&(this.elements.display.seekTooltip=this.elements.progress.querySelector("."+this.config.classNames.tooltip)),!0}catch(e){return this.console.warn("It looks like there is a problem with your custom controls HTML",e),this.toggleNativeControls(!0),!1}},getFocusElement:function(){var e=document.activeElement;return e=e&&e!==document.body?document.querySelector(":focus"):null},trapFocus:function(){var e=this,t=s.getElements.call(this,"button:not(:disabled), input:not(:disabled), [tabindex]"),i=t[0],n=t[t.length-1];s.on(this.elements.container,"keydown",function(t){if("Tab"===t.key&&9===t.keyCode&&e.fullscreen.active){var a=s.getFocusElement();a!==n||t.shiftKey?a===i&&t.shiftKey&&(n.focus(),t.preventDefault()):(i.focus(),t.preventDefault())}},!1)},toggleListener:function(e,t,i,n,l,o){if(null!==e&&!s.is.undefined(e))if(s.is.nodeList(e))Array.from(e).forEach(function(e){e instanceof Node&&s.toggleListener.call(null,e,t,i,n,l,o)});else{var r=t.split(" "),c=!!s.is.boolean(o)&&o;a.passiveListeners&&(c={passive:!s.is.boolean(l)||l,capture:!!s.is.boolean(o)&&o}),r.forEach(function(t){e[n?"addEventListener":"removeEventListener"](t,i,c)})}},on:function(e,t,i,n,a){s.toggleListener(e,t,i,!0,n,a)},off:function(e,t,i,n,a){s.toggleListener(e,t,i,!1,n,a)},dispatchEvent:function(e,t,i,n){if(e&&t){var a=new CustomEvent(t,{bubbles:!!s.is.boolean(i)&&i,detail:Object.assign({},n,{plyr:this instanceof Plyr?this:null})});e.dispatchEvent(a)}},toggleState:function(e,t){if(s.is.htmlElement(e)){var i=s.is.boolean(t)?t:!e.getAttribute("aria-pressed");e.setAttribute("aria-pressed",i)}},getPercentage:function(e,t){return 0===e||0===t||Number.isNaN(e)||Number.isNaN(t)?0:(e/t*100).toFixed(2)},extend:function(){for(var e=arguments.length,t=Array(e),i=0;i<e;i++)t[i]=arguments[i];var n=t.length;if(!n)return null;if(1===n)return t[0];var a=Array.prototype.shift.call(t);return s.is.object(a)||(a={}),t.forEach(function(e){s.is.object(e)&&Object.keys(e).forEach(function(t){e[t]&&e[t].constructor&&e[t].constructor===Object?(a[t]=a[t]||{},s.extend(a[t],e[t])):a[t]=e[t]})}),a},parseYouTubeId:function(e){return e.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/)?RegExp.$2:e},parseVimeoId:function(e){if(s.is.number(Number(e)))return e;return e.match(/^.*(vimeo.com\/|video\/)(\d+).*/)?RegExp.$2:e},buildUrlParameters:function(e){return s.is.object(e)?Object.keys(e).map(function(t){return encodeURIComponent(t)+"="+encodeURIComponent(e[t])}).join("&"):""},stripHTML:function(e){var t=document.createDocumentFragment(),i=document.createElement("div");return t.appendChild(i),i.innerHTML=e,t.firstChild.innerText},getAspectRatio:function(e,t){var i=function e(t,i){return 0===i?t:e(i,t%i)}(e,t);return e/i+":"+t/i},transitionEnd:function(){var e=document.createElement("span"),t=Object.keys({WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"}).find(function(t){return void 0!==e.style[t]});return"string"==typeof t&&t}()},a={audio:"canPlayType"in document.createElement("audio"),video:"canPlayType"in document.createElement("video"),check:function(e,t){var i=!1,n=!1,l=s.getBrowser(),o=l.isIPhone&&t&&a.inline;switch(e){case"video":n=(i=a.video)&&a.rangeInput&&(!l.isIPhone||o);break;case"audio":n=(i=a.audio)&&a.rangeInput;break;case"youtube":i=!0,n=a.rangeInput&&(!l.isIPhone||o);break;case"vimeo":i=!0,n=a.rangeInput&&!l.isIPhone;break;default:n=(i=a.audio&&a.video)&&a.rangeInput}return{api:i,ui:n}},storage:function(){if(!("localStorage"in window))return!1;try{return window.localStorage.setItem("___test","___test"),window.localStorage.removeItem("___test"),!0}catch(e){return!1}}(),pip:!s.getBrowser().isIPhone&&s.is.function(s.createElement("video").webkitSetPresentationMode),airplay:s.is.function(window.WebKitPlaybackTargetAvailabilityEvent),inline:"playsInline"in document.createElement("video"),mime:function(e){var t=this.media;try{if(!s.is.function(t.canPlayType))return!1;if("video"===this.type)switch(e){case"video/webm":return t.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/,"");case"video/mp4":return t.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/,"");case"video/ogg":return t.canPlayType('video/ogg; codecs="theora"').replace(/no/,"");default:return!1}else if("audio"===this.type)switch(e){case"audio/mpeg":return t.canPlayType("audio/mpeg;").replace(/no/,"");case"audio/ogg":return t.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/,"");case"audio/wav":return t.canPlayType('audio/wav; codecs="1"').replace(/no/,"");default:return!1}}catch(e){return!1}return!1},textTracks:"textTracks"in document.createElement("video"),passiveListeners:function(){var e=!1;try{var t=Object.defineProperty({},"passive",{get:function(){return e=!0,null}});window.addEventListener("test",null,t)}catch(e){}return e}(),rangeInput:function(){var e=document.createElement("input");return e.type="range","range"===e.type}(),touch:"ontouchstart"in document.documentElement,transitions:!1!==s.transitionEnd,reducedMotion:"matchMedia"in window&&window.matchMedia("(prefers-reduced-motion)").matches},l=function(){var e=!1;return s.is.function(document.cancelFullScreen)?e="":["webkit","o","moz","ms","khtml"].some(function(t){return s.is.function(document[t+"CancelFullScreen"])?(e=t,!0):!(!s.is.function(document.msExitFullscreen)||!document.msFullscreenEnabled)&&(e="ms",!0)}),e}(),o={prefix:l,enabled:document.fullscreenEnabled||document.webkitFullscreenEnabled||document.mozFullScreenEnabled||document.msFullscreenEnabled,eventType:"ms"===l?"MSFullscreenChange":l+"fullscreenchange",isFullScreen:function(e){if(!o.enabled)return!1;var t=s.is.undefined(e)?document.body:e;switch(l){case"":return document.fullscreenElement===t;case"moz":return document.mozFullScreenElement===t;default:return document[l+"FullscreenElement"]===t}},requestFullScreen:function(e){if(!o.enabled)return!1;var t=s.is.undefined(e)?document.body:e;return l.length?t[l+("ms"===l?"RequestFullscreen":"RequestFullScreen")]():t.requestFullScreen()},cancelFullScreen:function(){return!!o.enabled&&(l.length?document[l+("ms"===l?"ExitFullscreen":"CancelFullScreen")]():document.cancelFullScreen())},element:function(){return o.enabled?l.length?document[l+"FullscreenElement"]:document.fullscreenElement:null},setup:function(){if(this.supported.ui&&"audio"!==this.type&&this.config.fullscreen.enabled){var e=o.enabled;e||this.config.fullscreen.fallback&&!s.inFrame()?(this.console.log((e?"Native":"Fallback")+" fullscreen enabled"),s.toggleClass(this.elements.container,this.config.classNames.fullscreen.enabled,!0)):this.console.log("Fullscreen not supported and fallback disabled"),this.elements.buttons&&this.elements.buttons.fullscreen&&s.toggleState(this.elements.buttons.fullscreen,!1),s.trapFocus.call(this)}}},r={setup:function(){var e=null,i={};return a.storage&&this.config.storage.enabled?(window.localStorage.removeItem("plyr-volume"),(e=window.localStorage.getItem(this.config.storage.key))&&(/^\d+(\.\d+)?$/.test(e)?t({volume:parseFloat(e)}):i=JSON.parse(e)),i):i},set:t,get:e},c=s.getBrowser(),u={global:function(){var e=this,t=null,i=function(e){return e.keyCode?e.keyCode:e.which},n=function(n){var a=i(n),l="keydown"===n.type,r=l&&a===t;if(s.is.number(a)){if(l){var c=[48,49,50,51,52,53,54,56,57,32,75,38,40,77,39,37,70,67,73,76,79],u=s.getFocusElement();if(s.is.htmlElement(u)&&s.matches(u,e.config.selectors.editable))return;switch(c.includes(a)&&(n.preventDefault(),n.stopPropagation()),a){case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:r||(e.currentTime=e.duration/10*(a-48));break;case 32:case 75:r||e.togglePlay();break;case 38:e.increaseVolume(.1);break;case 40:e.decreaseVolume(.1);break;case 77:r||(e.muted=!e.muted);break;case 39:e.forward();break;case 37:e.rewind();break;case 70:e.toggleFullscreen();break;case 67:r||e.toggleCaptions();break;case 76:e.loop=!e.loop}!o.enabled&&e.fullscreen.active&&27===a&&e.toggleFullscreen(),t=a}else t=null}};this.config.keyboard.global?s.on(window,"keydown keyup",n,!1):this.config.keyboard.focused&&s.on(this.elements.container,"keydown keyup",n,!1),s.on(this.elements.container,"focusout",function(t){s.toggleClass(t.target,e.config.classNames.tabFocus,!1)}),s.on(this.elements.container,"keydown",function(t){9===t.keyCode&&window.setTimeout(function(){s.toggleClass(s.getFocusElement(),e.config.classNames.tabFocus,!0)},0)}),this.config.hideControls&&s.on(this.elements.container,"mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen",function(t){e.toggleControls(t)}),o.enabled&&s.on(document,o.eventType,function(t){e.toggleFullscreen(t)})},media:function(){var e=this;if(s.on(this.media,"timeupdate seeking",function(t){return d.timeUpdate.call(e,t)}),s.on(this.media,"durationchange loadedmetadata",function(t){return d.displayDuration.call(e,t)}),s.on(this.media,"ended",function(){"video"===e.type&&e.config.showPosterOnEnd&&(e.restart(),e.media.load())}),s.on(this.media,"progress playing",function(t){return d.updateProgress.call(e,t)}),s.on(this.media,"volumechange",function(t){return d.updateVolume.call(e,t)}),s.on(this.media,"play pause ended",function(t){return d.checkPlaying.call(e,t)}),s.on(this.media,"waiting canplay seeked",function(t){return d.checkLoading.call(e,t)}),this.supported.ui&&this.config.clickToPlay&&"audio"!==this.type){var t=s.getElement.call(this,"."+this.config.classNames.video);if(!t)return;t.style.cursor="pointer",s.on(t,"click",function(){e.config.hideControls&&a.touch&&!e.media.paused||(e.media.paused?e.play():e.media.ended?(e.restart(),e.play()):e.pause())})}this.config.disableContextMenu&&s.on(this.media,"contextmenu",function(e){e.preventDefault()},!1),s.on(this.media,"ratechange",function(){h.updateSetting.call(e,"speed"),r.set.call(e,{speed:e.speed})}),s.on(this.media,"qualitychange",function(){h.updateSetting.call(e,"quality"),r.set.call(e,{quality:e.quality})}),s.on(this.media,"languagechange",function(){r.set.call(e,{language:e.language})}),s.on(this.media,"volumechange",function(){r.set.call(e,{volume:e.volume,muted:e.muted})}),s.on(this.media,"captionsenabled captionsdisabled",function(){h.updateSetting.call(e,"captions"),r.set.call(e,{captions:e.captions.enabled})}),s.on(this.media,this.config.events.concat(["keyup","keydown"]).join(" "),function(t){var i={};"error"===t.type&&(i=e.media.error),s.dispatchEvent.call(e,e.elements.container,t.type,!0,i)})},controls:function(){var e=this,t=c.isIE?"change":"input",i=function(t,i,n){var a=e.config.listeners[i];s.is.function(a)&&a.call(e,t),!t.defaultPrevented&&s.is.function(n)&&n.call(e,t)},n=function(){var t=e.togglePlay(),i=e.elements.buttons[t?"pause":"play"];s.is.htmlElement(i)&&i.focus()};s.on(this.elements.buttons.play,"click",function(e){return i(e,"play",n)}),s.on(this.elements.buttons.pause,"click",function(e){return i(e,"pause",n)}),s.on(this.elements.buttons.restart,"click",function(t){return i(t,"restart",function(){e.restart()})}),s.on(this.elements.buttons.rewind,"click",function(t){return i(t,"rewind",function(){e.rewind()})}),s.on(this.elements.buttons.forward,"click",function(t){return i(t,"forward",function(){e.forward()})}),s.on(this.elements.buttons.mute,"click",function(t){return i(t,"mute",function(){e.muted=!e.muted})}),s.on(this.elements.buttons.captions,"click",function(t){return i(t,"captions",function(){e.toggleCaptions()})}),s.on(this.elements.buttons.fullscreen,"click",function(t){return i(t,"fullscreen",function(){e.toggleFullscreen()})}),s.on(this.elements.buttons.pip,"click",function(t){return i(t,"pip",function(){e.pip="toggle"})}),s.on(this.elements.buttons.airplay,"click",function(t){return i(t,"airplay",function(){e.airPlay()})}),s.on(this.elements.buttons.settings,"click",function(t){h.toggleMenu.call(e,t)}),s.on(document.documentElement,"click",function(t){h.toggleMenu.call(e,t)}),s.on(this.elements.settings.form,"click",function(t){h.showTab.call(e,t),s.matches(t.target,e.config.selectors.inputs.language)?i(t,"language",function(){e.toggleCaptions(!0),e.language=t.target.value.toLowerCase()}):s.matches(t.target,e.config.selectors.inputs.quality)?i(t,"quality",function(){e.quality=t.target.value}):s.matches(t.target,e.config.selectors.inputs.speed)?i(t,"speed",function(){e.speed=parseFloat(t.target.value)}):s.matches(t.target,e.config.selectors.buttons.loop)&&i(t,"loop",function(){e.console.warn("Set loop")})}),s.on(this.elements.inputs.seek,t,function(t){return i(t,"seek",function(){e.currentTime=t.target.value/t.target.max*e.duration})}),s.on(this.elements.inputs.volume,t,function(t){return i(t,"volume",function(){e.volume=t.target.value})}),c.isWebkit&&s.on(s.getElements.call(this,'input[type="range"]'),"input",function(t){h.updateRangeFill.call(e,t.target)}),s.on(this.elements.progress,"mouseenter mouseleave mousemove",function(t){return h.updateSeekTooltip.call(e,t)}),this.config.hideControls&&(s.on(this.elements.controls,"mouseenter mouseleave",function(t){e.elements.controls.hover="mouseenter"===t.type}),s.on(this.elements.controls,"mousedown mouseup touchstart touchend touchcancel",function(t){e.elements.controls.pressed=["mousedown","touchstart"].includes(t.type)}),s.on(this.elements.controls,"focus blur",function(t){e.toggleControls(t)},!0)),s.on(this.elements.inputs.volume,"wheel",function(t){return i(t,"volume",function(){var i=t.webkitDirectionInvertedFromDevice,n=0;(t.deltaY<0||t.deltaX>0)&&(i?(e.decreaseVolume(.02),n=-1):(e.increaseVolume(.02),n=1)),(t.deltaY>0||t.deltaX<0)&&(i?(e.increaseVolume(.02),n=1):(e.decreaseVolume(.02),n=-1)),(1===n&&e.media.volume<1||-1===n&&e.media.volume>0)&&t.preventDefault()})},!1)}},d={addStyleHook:function(){s.toggleClass(this.elements.container,this.config.selectors.container.replace(".",""),!0),s.toggleClass(this.elements.container,this.config.classNames.uiSupported,this.supported.ui)},toggleNativeControls:function(e){e&&this.isHTML5?this.media.setAttribute("controls",""):this.media.removeAttribute("controls")},build:function(){if(u.media.call(this),!this.supported.ui)return this.console.warn("Basic support only for "+this.type),s.removeElement.call(this,"controls"),s.removeElement.call(this,"buttons.play"),void d.toggleNativeControls.call(this,!0);s.is.htmlElement(this.elements.controls)||(h.inject.call(this),u.controls.call(this)),s.is.htmlElement(this.elements.controls)&&(d.toggleNativeControls.call(this),o.setup.call(this),m.setup.call(this),this.volume=null,this.muted=null,this.speed=null,this.loop=null,this.options.quality=[],d.timeUpdate.call(this),d.checkPlaying.call(this),this.ready=!0,s.dispatchEvent.call(this,this.media,"ready"),d.setTitle.call(this))},displayDuration:function(){this.supported.ui&&(!this.elements.display.duration&&this.config.displayDuration&&this.paused&&d.updateTimeDisplay.call(this,this.duration,this.elements.display.currentTime),this.elements.display.duration&&d.updateTimeDisplay.call(this,this.duration,this.elements.display.duration),h.updateSeekTooltip.call(this))},setTitle:function(){var e=this.config.i18n.play;if(s.is.string(this.config.title)&&!s.is.empty(this.config.title)&&(e+=", "+this.config.title,this.elements.container.setAttribute("aria-label",this.config.title)),s.is.nodeList(this.elements.buttons.play)&&Array.from(this.elements.buttons.play).forEach(function(t){t.setAttribute("aria-label",e)}),this.isEmbed){var t=s.getElement.call(this,"iframe");if(!s.is.htmlElement(t))return;var i=s.is.empty(this.config.title)?"video":this.config.title;t.setAttribute("title",this.config.i18n.frameTitle.replace("{title}",i))}},checkPlaying:function(){s.toggleClass(this.elements.container,this.config.classNames.playing,!this.paused),s.toggleClass(this.elements.container,this.config.classNames.stopped,this.paused),this.toggleControls(this.paused)},updateVolume:function(){this.supported.ui&&(s.is.htmlElement(this.elements.inputs.volume)&&d.setRange.call(this,this.elements.inputs.volume,this.muted?0:this.volume),s.is.htmlElement(this.elements.buttons.mute)&&s.toggleState(this.elements.buttons.mute,this.muted||0===this.volume))},checkLoading:function(e){var t=this;this.loading="waiting"===e.type,clearTimeout(this.timers.loading),this.timers.loading=setTimeout(function(){s.toggleClass(t.elements.container,t.config.classNames.loading,t.loading),t.toggleControls(t.loading)},this.loading?250:0)},setRange:function(e,t){s.is.htmlElement(e)&&(e.value=t,h.updateRangeFill.call(this,e))},setProgress:function(e,t){var i=s.is.undefined(t)?0:t,n=s.is.undefined(e)?this.elements.display.buffer:e;if(s.is.htmlElement(n)){n.value=i;var a=n.getElementsByTagName("span")[0];s.is.htmlElement(a)&&(a.childNodes[0].nodeValue=i)}},updateProgress:function(e){var t=this;if(this.supported.ui){var i=0;if(e)switch(e.type){case"timeupdate":case"seeking":i=s.getPercentage(this.currentTime,this.duration),"timeupdate"===e.type&&d.setRange.call(this,this.elements.inputs.seek,i);break;case"playing":case"progress":i=function(){var e=t.media.buffered;return e&&e.length?s.getPercentage(e.end(0),t.duration):s.is.number(e)?100*e:0}(),d.setProgress.call(this,this.elements.display.buffer,i)}}},updateTimeDisplay:function(e,t){if(!s.is.htmlElement(t))return null;var i=Number.isNaN(e)?0:e,n=parseInt(i%60,10),a=parseInt(i/60%60,10),l=parseInt(i/60/60%60,10),o=parseInt(this.duration/60/60%60,10)>0;n=("0"+n).slice(-2),a=("0"+a).slice(-2);var r=(o?l+":":"")+a+":"+n;return t.textContent=r,r},timeUpdate:function(e){d.updateTimeDisplay.call(this,this.currentTime,this.elements.display.currentTime),e&&"timeupdate"===e.type&&this.media.seeking||d.updateProgress.call(this,e)}},p=s.getBrowser(),h={updateRangeFill:function(e){if(p.isWebkit){var t=s.is.event(e)?e.target:e;if(s.is.htmlElement(t)&&"range"===t.getAttribute("type")){s.is.htmlElement(this.elements.styleSheet)||(this.elements.styleSheet=s.createElement("style"),this.elements.container.appendChild(this.elements.styleSheet));var i=this.elements.styleSheet.sheet,n=t.value/t.max*100,a="#"+t.id+"::-webkit-slider-runnable-track",l="{ background-image: linear-gradient(to right, currentColor "+n+"%, transparent "+n+"%) }",o=Array.from(i.rules).findIndex(function(e){return e.selectorText===a});-1!==o&&i.deleteRule(o),i.insertRule([a,l].join(" "))}}},getIconUrl:function(){return{url:this.config.iconUrl,absolute:0===this.config.iconUrl.indexOf("http")||p.isIE&&!window.svg4everybody}},createIcon:function(e,t){var i=h.getIconUrl.call(this),n=(i.absolute?"":i.url)+"#"+this.config.iconPrefix,a=document.createElementNS("http://www.w3.org/2000/svg","svg");s.setAttributes(a,s.extend(t,{role:"presentation"}));var l=document.createElementNS("http://www.w3.org/2000/svg","use"),o=n+"-"+e;return l.setAttributeNS("http://www.w3.org/1999/xlink","href",o),l.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",o),a.appendChild(l),a},createLabel:function(e){var t=this.config.i18n[e];switch(e){case"pip":t="PIP";break;case"airplay":t="AirPlay"}return s.createElement("span",{class:this.config.classNames.hidden},t)},createBadge:function(e){var t=s.createElement("span",{class:this.config.classNames.menu.value});return t.appendChild(s.createElement("span",{class:this.config.classNames.menu.badge},e)),t},createButton:function(e,t){var i=s.createElement("button"),n=Object.assign({},t),a=e,l=void 0,o=void 0,r=void 0;switch("type"in n||(n.type="button"),"class"in n?-1===n.class.indexOf(this.config.classNames.control)&&(n.class+=" "+this.config.classNames.control):n.class=this.config.classNames.control,a){case"mute":r="toggleMute",l="volume",o="muted";break;case"captions":r="toggleCaptions",l="captions-off",o="captions-on";break;case"fullscreen":r="toggleFullscreen",l="enter-fullscreen",o="exit-fullscreen";break;case"play-large":n.class="plyr__play-large",a="play",r="play",l="play";break;default:r=a,l=a}return s.extend(n,s.getAttributesFromSelector(this.config.selectors.buttons[a],n)),s.is.string(o)?(i.appendChild(h.createIcon.call(this,o,{class:"icon--pressed"})),i.appendChild(h.createIcon.call(this,l,{class:"icon--not-pressed"}))):i.appendChild(h.createIcon.call(this,l)),i.appendChild(h.createLabel.call(this,r)),s.setAttributes(i,n),this.elements.buttons[a]=i,i},createRange:function(e,t){var i=s.createElement("label",{for:t.id,class:this.config.classNames.hidden},this.config.i18n[e]),n=s.createElement("input",s.extend(s.getAttributesFromSelector(this.config.selectors.inputs[e]),{type:"range",min:0,max:100,step:.01,value:0,autocomplete:"off"},t));return this.elements.inputs[e]=n,h.updateRangeFill.call(this,n),{label:i,input:n}},createProgress:function(e,t){var i=s.createElement("progress",s.extend(s.getAttributesFromSelector(this.config.selectors.display[e]),{min:0,max:100,value:0},t));if("volume"!==e){i.appendChild(s.createElement("span",null,"0"));var n="";switch(e){case"played":n=this.config.i18n.played;break;case"buffer":n=this.config.i18n.buffered}i.textContent="% "+n.toLowerCase()}return this.elements.display[e]=i,i},createTime:function(e){var t=s.createElement("span",{class:"plyr__time"});return t.appendChild(s.createElement("span",{class:this.config.classNames.hidden},this.config.i18n[e])),t.appendChild(s.createElement("span",s.getAttributesFromSelector(this.config.selectors.display[e]),"00:00")),this.elements.display[e]=t,t},updateSeekTooltip:function(e){if(this.config.tooltips.seek&&s.is.htmlElement(this.elements.inputs.seek)&&s.is.htmlElement(this.elements.display.seekTooltip)&&0!==this.duration){var t=0,i=this.elements.inputs.seek.getBoundingClientRect(),n=this.config.classNames.tooltip+"--visible";if(s.is.event(e))t=100/i.width*(e.pageX-i.left);else{if(!s.hasClass(this.elements.display.seekTooltip,n))return;t=this.elements.display.seekTooltip.style.left.replace("%","")}t<0?t=0:t>100&&(t=100),d.updateTimeDisplay.call(this,this.duration/100*t,this.elements.display.seekTooltip),this.elements.display.seekTooltip.style.left=t+"%",s.is.event(e)&&["mouseenter","mouseleave"].includes(e.type)&&s.toggleClass(this.elements.display.seekTooltip,n,"mouseenter"===e.type)}},toggleTab:function(e,t){var i=this.elements.settings.tabs[e],n=this.elements.settings.panes[e];s.is.htmlElement(i)&&(t?i.removeAttribute("hidden"):i.setAttribute("hidden","")),s.is.htmlElement(n)&&(t?n.removeAttribute("hidden"):n.setAttribute("hidden",""))},setQualityMenu:function(e){var t=this,i=this.elements.settings.panes.quality.querySelector("ul");s.is.array(e)?this.options.quality=e.filter(function(e){return t.config.quality.options.includes(e)}):this.options.quality=this.config.quality.options;var n=!s.is.empty(this.options.quality)&&"youtube"===this.type;if(h.toggleTab.call(this,"quality",n),n){s.emptyElement(i);var a=function(e){var i="";switch(e){case"hd2160":i="4K";break;case"hd1440":i="WQHD";break;case"hd1080":case"hd720":i="HD"}return i.length?h.createBadge.call(t,i):null};this.options.quality.forEach(function(e){var n=s.createElement("li"),l=s.createElement("label",{class:t.config.classNames.control}),o=s.createElement("input",s.extend(s.getAttributesFromSelector(t.config.selectors.inputs.quality),{type:"radio",name:"plyr-quality",value:e}));l.appendChild(o),l.appendChild(document.createTextNode(h.getLabel.call(t,"quality",e)));var r=a(e);s.is.htmlElement(r)&&l.appendChild(r),n.appendChild(l),i.appendChild(n)}),h.updateSetting.call(this,"quality",i)}},getLabel:function(e,t){switch(e){case"speed":return 1===t?"Normal":t+"×";case"quality":switch(t){case"hd2160":return"2160P";case"hd1440":return"1440P";case"hd1080":return"1080P";case"hd720":return"720P";case"large":return"480P";case"medium":return"360P";case"small":return"240P";case"tiny":return"Tiny";case"default":return"Auto";default:return t}case"captions":return h.getLanguage.call(this);default:return null}},updateSetting:function(e,t){var i=this.elements.settings.panes[e],n=null,a=t;switch(e){case"captions":n=this.captions.language,this.captions.enabled||(n="");break;default:if(n=this[e],s.is.empty(n)&&(n=this.config[e].default),!this.options[e].includes(n))return void this.console.warn("Unsupported value of '"+n+"' for "+e);if(!this.config[e].options.includes(n))return void this.console.warn("Disabled value of '"+n+"' for "+e)}s.is.htmlElement(a)||(a=i&&i.querySelector("ul"));var l=a&&a.querySelector('input[value="'+n+'"]');s.is.htmlElement(l)&&(l.checked=!0,this.elements.settings.tabs[e].querySelector("."+this.config.classNames.menu.value).innerHTML=h.getLabel.call(this,e,n))},setLoopMenu:function(){var e=this,t=this.elements.settings.panes.loop.querySelector("ul");this.elements.settings.tabs.loop.removeAttribute("hidden"),this.elements.settings.panes.loop.removeAttribute("hidden");var i=!s.is.empty(this.loop.options);h.toggleTab.call(this,"loop",i),s.emptyElement(t),["start","end","all","reset"].forEach(function(i){var n=s.createElement("li"),a=s.createElement("button",s.extend(s.getAttributesFromSelector(e.config.selectors.buttons.loop),{type:"button",class:e.config.classNames.control,"data-plyr-loop-action":i}),e.config.i18n[i]);if(["start","end"].includes(i)){var l=h.createBadge.call(e,"00:00");a.appendChild(l)}n.appendChild(a),t.appendChild(n)})},getLanguage:function(){return this.supported.ui?!a.textTracks||s.is.empty(this.captions.tracks)?this.config.i18n.none:this.captions.enabled?this.captions.currentTrack.label:this.config.i18n.disabled:null},setCaptionsMenu:function(){var e=this,t=this.elements.settings.panes.captions.querySelector("ul"),i=!s.is.empty(this.captions.tracks);if(h.toggleTab.call(this,"captions",i),s.emptyElement(t),!s.is.empty(this.captions.tracks)){var n=Array.from(this.captions.tracks).map(function(e){return{language:e.language,badge:!0,label:s.is.empty(e.label)?e.language.toUpperCase():e.label}});n.unshift({language:"",label:this.config.i18n.none}),n.forEach(function(i){var n=s.createElement("li"),a=s.createElement("label",{class:e.config.classNames.control}),l=s.createElement("input",s.extend(s.getAttributesFromSelector(e.config.selectors.inputs.language),{type:"radio",name:"plyr-language",value:i.language}));i.language.toLowerCase()===e.captions.language.toLowerCase()&&(l.checked=!0),a.appendChild(l),a.appendChild(document.createTextNode(i.label||i.language)),i.badge&&a.appendChild(h.createBadge.call(e,i.language.toUpperCase())),n.appendChild(a),t.appendChild(n)}),h.updateSetting.call(this,"captions",t)}},setSpeedMenu:function(e){var t=this;s.is.array(e)?this.options.speed=e.filter(function(e){return t.config.speed.options.includes(e)}):this.options.speed=this.config.speed.options;var i=!s.is.empty(this.options.speed);if(h.toggleTab.call(this,"speed",i),i){var n=this.elements.settings.panes.speed.querySelector("ul");this.elements.settings.tabs.speed.removeAttribute("hidden"),this.elements.settings.panes.speed.removeAttribute("hidden"),s.emptyElement(n),this.options.speed.forEach(function(e){var i=s.createElement("li"),a=s.createElement("label",{class:t.config.classNames.control}),l=s.createElement("input",s.extend(s.getAttributesFromSelector(t.config.selectors.inputs.speed),{type:"radio",name:"plyr-speed",value:e}));a.appendChild(l),a.insertAdjacentHTML("beforeend",h.getLabel.call(t,"speed",e)),i.appendChild(a),n.appendChild(i)}),h.updateSetting.call(this,"speed",n)}},toggleMenu:function(e){var t=this.elements.settings.form,i=this.elements.buttons.settings,n=s.is.boolean(e)?e:t&&"true"===t.getAttribute("aria-hidden");if(s.is.event(e)){var a=t&&t.contains(e.target),l=e.target===this.elements.buttons.settings;if(a||!a&&!l&&n)return;l&&e.stopPropagation()}i&&i.setAttribute("aria-expanded",n),t&&(t.setAttribute("aria-hidden",!n),n?t.removeAttribute("tabindex"):t.setAttribute("tabindex",-1))},getTabSize:function(e){var t=e.cloneNode(!0);t.style.position="absolute",t.style.opacity=0,t.setAttribute("aria-hidden",!1),Array.from(t.querySelectorAll("input[name]")).forEach(function(e){var t=e.getAttribute("name");e.setAttribute("name",t+"-clone")}),e.parentNode.appendChild(t);var i=t.scrollWidth,n=t.scrollHeight;return s.removeElement(t),{width:i,height:n}},showTab:function(e){var t=this.elements.settings.menu,i=e.target,n="false"===i.getAttribute("aria-expanded"),l=document.getElementById(i.getAttribute("aria-controls"));if(s.is.htmlElement(l)&&"tabpanel"===l.getAttribute("role")){var o=t.querySelector('[role="tabpanel"][aria-hidden="false"]'),r=o.parentNode;if(Array.from(t.querySelectorAll('[aria-controls="'+o.getAttribute("id")+'"]')).forEach(function(e){e.setAttribute("aria-expanded",!1)}),a.transitions&&!a.reducedMotion){r.style.width=o.scrollWidth+"px",r.style.height=o.scrollHeight+"px";var c=h.getTabSize.call(this,l),u=function e(t){t.target===r&&["width","height"].includes(t.propertyName)&&(r.style.width="",r.style.height="",s.off(r,s.transitionEnd,e))};s.on(r,s.transitionEnd,u),r.style.width=c.width+"px",r.style.height=c.height+"px"}o.setAttribute("aria-hidden",!0),o.setAttribute("tabindex",-1),l.setAttribute("aria-hidden",!n),i.setAttribute("aria-expanded",n),l.removeAttribute("tabindex")}},create:function(e){var t=this;if(s.is.empty(this.config.controls))return null;var i=s.createElement("div",s.getAttributesFromSelector(this.config.selectors.controls.wrapper));if(this.config.controls.includes("restart")&&i.appendChild(h.createButton.call(this,"restart")),this.config.controls.includes("rewind")&&i.appendChild(h.createButton.call(this,"rewind")),this.config.controls.includes("play")&&(i.appendChild(h.createButton.call(this,"play")),i.appendChild(h.createButton.call(this,"pause"))),this.config.controls.includes("fast-forward")&&i.appendChild(h.createButton.call(this,"fast-forward")),this.config.controls.includes("progress")){var n=s.createElement("span",s.getAttributesFromSelector(this.config.selectors.progress)),l=h.createRange.call(this,"seek",{id:"plyr-seek-"+e.id});if(n.appendChild(l.label),n.appendChild(l.input),n.appendChild(h.createProgress.call(this,"buffer")),this.config.tooltips.seek){var o=s.createElement("span",{role:"tooltip",class:this.config.classNames.tooltip},"00:00");n.appendChild(o),this.elements.display.seekTooltip=o}this.elements.progress=n,i.appendChild(this.elements.progress)}if(this.config.controls.includes("current-time")&&i.appendChild(h.createTime.call(this,"currentTime")),this.config.controls.includes("duration")&&i.appendChild(h.createTime.call(this,"duration")),this.config.controls.includes("mute")&&i.appendChild(h.createButton.call(this,"mute")),this.config.controls.includes("volume")){var r=s.createElement("span",{class:"plyr__volume"}),c={max:1,step:.05,value:this.config.volume},u=h.createRange.call(this,"volume",s.extend(c,{id:"plyr-volume-"+e.id}));r.appendChild(u.label),r.appendChild(u.input),i.appendChild(r)}if(this.config.controls.includes("captions")&&i.appendChild(h.createButton.call(this,"captions")),this.config.controls.includes("settings")&&!s.is.empty(this.config.settings)){var d=s.createElement("div",{class:"plyr__menu"});d.appendChild(h.createButton.call(this,"settings",{id:"plyr-settings-toggle-"+e.id,"aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id,"aria-expanded":!1}));var p=s.createElement("form",{class:"plyr__menu__container",id:"plyr-settings-"+e.id,"aria-hidden":!0,"aria-labelled-by":"plyr-settings-toggle-"+e.id,role:"tablist",tabindex:-1}),m=s.createElement("div"),g=s.createElement("div",{id:"plyr-settings-"+e.id+"-home","aria-hidden":!1,"aria-labelled-by":"plyr-settings-toggle-"+e.id,role:"tabpanel"}),f=s.createElement("ul",{role:"tablist"});this.config.settings.forEach(function(i){var n=s.createElement("li",{role:"tab",hidden:""}),a=s.createElement("button",s.extend(s.getAttributesFromSelector(t.config.selectors.buttons.settings),{type:"button",class:t.config.classNames.control+" "+t.config.classNames.control+"--forward",id:"plyr-settings-"+e.id+"-"+i+"-tab","aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id+"-"+i,"aria-expanded":!1}),t.config.i18n[i]),l=s.createElement("span",{class:t.config.classNames.menu.value});l.innerHTML=e[i],a.appendChild(l),n.appendChild(a),f.appendChild(n),t.elements.settings.tabs[i]=n}),g.appendChild(f),m.appendChild(g),this.config.settings.forEach(function(i){var n=s.createElement("div",{id:"plyr-settings-"+e.id+"-"+i,"aria-hidden":!0,"aria-labelled-by":"plyr-settings-"+e.id+"-"+i+"-tab",role:"tabpanel",tabindex:-1,hidden:""}),a=s.createElement("button",{type:"button",class:t.config.classNames.control+" "+t.config.classNames.control+"--back","aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id+"-home","aria-expanded":!1},t.config.i18n[i]);n.appendChild(a);var l=s.createElement("ul");n.appendChild(l),m.appendChild(n),t.elements.settings.panes[i]=n}),p.appendChild(m),d.appendChild(p),i.appendChild(d),this.elements.settings.form=p,this.elements.settings.menu=d}return this.config.controls.includes("pip")&&a.pip&&i.appendChild(h.createButton.call(this,"pip")),this.config.controls.includes("airplay")&&a.airplay&&i.appendChild(h.createButton.call(this,"airplay")),this.config.controls.includes("fullscreen")&&i.appendChild(h.createButton.call(this,"fullscreen")),this.config.controls.includes("play-large")&&this.elements.container.appendChild(h.createButton.call(this,"play-large")),this.elements.controls=i,this.config.controls.includes("settings")&&this.config.settings.includes("speed")&&h.setSpeedMenu.call(this),i},inject:function(){var e=this;if(this.config.loadSprite){var t=h.getIconUrl.call(this);t.absolute&&s.loadSprite(t.url,"sprite-plyr")}this.id=Math.floor(1e4*Math.random());var i=null;i=s.is.string(this.config.controls)?this.config.controls:s.is.function(this.config.controls)?this.config.controls({id:this.id,seektime:this.config.seekTime,title:this.config.title}):h.create.call(this,{id:this.id,seektime:this.config.seekTime,speed:this.speed,quality:this.quality,captions:h.getLanguage.call(this)});var n=void 0;if(s.is.string(this.config.selectors.controls.container)&&(n=document.querySelector(this.config.selectors.controls.container)),s.is.htmlElement(n)||(n=this.elements.container),s.is.htmlElement(i)?n.appendChild(i):n.insertAdjacentHTML("beforeend",i),s.is.htmlElement(this.elements.controls)&&s.findElements.call(this),this.config.tooltips.controls){var a=s.getElements.call(this,[this.config.selectors.controls.wrapper," ",this.config.selectors.labels," .",this.config.classNames.hidden].join(""));Array.from(a).forEach(function(t){s.toggleClass(t,e.config.classNames.hidden,!1),s.toggleClass(t,e.config.classNames.tooltip,!0)})}}},m={setup:function(){var e=this;if(this.supported.ui){if(s.is.empty(r.get.call(this).language)?s.is.empty(this.captions.language)&&(this.captions.language=this.config.captions.language.toLowerCase()):this.captions.language=r.get.call(this).language,s.is.boolean(this.captions.enabled)||(s.is.empty(r.get.call(this).language)?this.captions.enabled=this.config.captions.active:this.captions.enabled=r.get.call(this).captions),!["video","vimeo"].includes(this.type)||"video"===this.type&&!a.textTracks)return this.captions.tracks=null,void(this.config.controls.includes("settings")&&this.config.settings.includes("captions")&&h.setCaptionsMenu.call(this));if(s.is.htmlElement(this.elements.captions)||(this.elements.captions=s.createElement("div",s.getAttributesFromSelector(this.config.selectors.captions)),s.insertAfter(this.elements.captions,this.elements.wrapper)),"video"===this.type&&(this.captions.tracks=this.media.textTracks),s.toggleClass(this.elements.container,this.config.classNames.captions.enabled,!s.is.empty(this.captions.tracks)),!s.is.empty(this.captions.tracks)){m.show.call(this);var t=function(){e.captions.currentTrack=null,Array.from(e.captions.tracks).forEach(function(t){t.language===e.captions.language.toLowerCase()&&(e.captions.currentTrack=t)})};if(t(),!s.is.track(this.captions.currentTrack)){var i=this.config.captions.language;this.captions.language=i,t(),s.is.track(this.captions.currentTrack)||this.toggleCaptions(!1),h.updateSetting.call(this,"captions")}if("video"===this.type){Array.from(this.captions.tracks).forEach(function(t){s.off(t,"cuechange",function(t){return m.setCue.call(e,t)}),t.mode="hidden"});var n=this.captions.currentTrack&&["captions","subtitles"].includes(this.captions.currentTrack.kind);s.is.track(this.captions.currentTrack)&&n&&(s.on(this.captions.currentTrack,"cuechange",function(t){return m.setCue.call(e,t)}),this.captions.currentTrack.activeCues&&this.captions.currentTrack.activeCues.length>0&&m.setCue.call(this,this.captions.currentTrack))}else"vimeo"===this.type&&this.captions.active&&this.embed.enableTextTrack(this.captions.language);this.config.controls.includes("settings")&&this.config.settings.includes("captions")&&h.setCaptionsMenu.call(this)}}},setCue:function(e){var t=(s.is.event(e)?e.target:e).activeCues[0];s.is.cue(t)?m.set.call(this,t.getCueAsHTML()):m.set.call(this),s.dispatchEvent.call(this,this.media,"cuechange")},set:function(e){if(this.supported.ui)if(s.is.htmlElement(this.elements.captions)){var t=s.createElement("span");s.emptyElement(this.elements.captions);var i=s.is.undefined(e)?"":e;s.is.string(i)?t.textContent=i.trim():t.appendChild(i),this.elements.captions.appendChild(t)}else this.console.warn("No captions element to render to")},show:function(){if(s.is.htmlElement(this.elements.buttons.captions)){var e=r.get.call(this).captions;s.is.boolean(e)?this.captions.active=e:e=this.config.captions.active,e&&(s.toggleClass(this.elements.container,this.config.classNames.captions.active,!0),s.toggleState(this.elements.buttons.captions,!0))}}},g={setup:function(){var e=this,t=s.parseYouTubeId(this.embedId),i=s.getElements.call(this,'[id^="'+this.type+'-"]');Array.from(i).forEach(s.removeElement),s.toggleClass(this.elements.wrapper,this.config.classNames.embed,!0),g.setAspectRatio.call(this),this.media.setAttribute("id",s.generateId(this.type));var n="https://www.googleapis.com/youtube/v3/videos?id="+t+"&fields=items(snippet(title))&part=snippet&key=AIzaSyDrNwtN3nLH_8rjCmu5Wq3ZCm4MNAVdc0c";fetch(n).then(function(e){return e.json()}).then(function(t){s.is.object(t)&&(e.config.title=t.items[0].snippet.title,d.setTitle.call(e))}).catch(function(){}),s.is.object(window.YT)?g.ready.call(this,t):(s.loadScript(this.config.urls.youtube.api),window.onYouTubeReadyCallbacks=window.onYouTubeReadyCallbacks||[],window.onYouTubeReadyCallbacks.push(function(){g.ready.call(e,t)}),window.onYouTubeIframeAPIReady=function(){window.onYouTubeReadyCallbacks.forEach(function(e){e()})})},setAspectRatio:function(){var e=this.config.ratio.split(":");this.elements.wrapper.style.paddingBottom=100/e[0]*e[1]+"%"},ready:function(e){var t=this;t.embed=new window.YT.Player(t.media.id,{videoId:e,playerVars:{autoplay:t.config.autoplay?1:0,controls:t.supported.ui?0:1,rel:0,showinfo:0,iv_load_policy:3,modestbranding:1,disablekb:1,playsinline:1,origin:window&&window.location.hostname,widget_referrer:window&&window.location.href,cc_load_policy:this.captions.active?1:0,cc_lang_pref:this.config.captions.language},events:{onError:function(e){if(!s.is.object(t.media.error)){var i={code:e.data};switch(e.data){case 2:i.message="The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.";break;case 5:i.message="The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.";break;case 100:i.message="The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.";break;case 101:case 150:i.message="The owner of the requested video does not allow it to be played in embedded players.";break;default:i.message="An unknown error occured"}t.media.error=i,s.dispatchEvent.call(t,t.media,"error")}},onPlaybackQualityChange:function(e){var i=e.target;t.media.quality=i.getPlaybackQuality(),s.dispatchEvent.call(t,t.media,"qualitychange")},onPlaybackRateChange:function(e){var i=e.target;t.media.playbackRate=i.getPlaybackRate(),s.dispatchEvent.call(t,t.media,"ratechange")},onReady:function(e){var i=e.target;t.media.play=function(){i.playVideo(),t.media.paused=!1},t.media.pause=function(){i.pauseVideo(),t.media.paused=!0},t.media.stop=function(){i.stopVideo(),t.media.paused=!0},t.media.duration=i.getDuration(),t.media.paused=!0,t.media.currentTime=0,Object.defineProperty(t.media,"currentTime",{get:function(){return Number(i.getCurrentTime())},set:function(e){t.media.seeking=!0,s.dispatchEvent.call(t,t.media,"seeking"),i.seekTo(e)}}),Object.defineProperty(t.media,"playbackRate",{get:function(){return i.getPlaybackRate()},set:function(e){i.setPlaybackRate(e)}}),Object.defineProperty(t.media,"quality",{get:function(){return i.getPlaybackQuality()},set:function(e){s.dispatchEvent.call(t,t.media,"qualityrequested",!1,{quality:e}),i.setPlaybackQuality(e)}});var n=t.config.volume;Object.defineProperty(t.media,"volume",{get:function(){return n},set:function(e){n=e,i.setVolume(100*n),s.dispatchEvent.call(t,t.media,"volumechange")}});var a=t.config.muted;Object.defineProperty(t.media,"muted",{get:function(){return a},set:function(e){var n=s.is.boolean(e)?e:a;a=n,i[n?"mute":"unMute"](),s.dispatchEvent.call(t,t.media,"volumechange")}}),Object.defineProperty(t.media,"currentSrc",{get:function(){return i.getVideoUrl()}}),t.config.controls.includes("settings")&&t.config.settings.includes("speed")&&h.setSpeedMenu.call(t,i.getAvailablePlaybackRates()),s.is.function(i.getVideoData)&&(t.config.title=i.getVideoData().title),t.supported.ui&&t.media.setAttribute("tabindex",-1),s.dispatchEvent.call(t,t.media,"timeupdate"),s.dispatchEvent.call(t,t.media,"durationchange"),window.clearInterval(t.timers.buffering),t.timers.buffering=window.setInterval(function(){t.media.buffered=i.getVideoLoadedFraction(),(null===t.media.lastBuffered||t.media.lastBuffered<t.media.buffered)&&s.dispatchEvent.call(t,t.media,"progress"),t.media.lastBuffered=t.media.buffered,1===t.media.buffered&&(window.clearInterval(t.timers.buffering),s.dispatchEvent.call(t,t.media,"canplaythrough"))},200),window.setTimeout(function(){return d.build.call(t)},50)},onStateChange:function(e){var i=e.target;switch(window.clearInterval(t.timers.playing),e.data){case 0:t.media.loop?(i.stopVideo(),i.playVideo()):(s.dispatchEvent.call(t,t.media,"ended"),t.media.paused=!0);break;case 1:t.media.paused=!1,t.media.seeking&&s.dispatchEvent.call(t,t.media,"seeked"),t.media.seeking=!1,s.dispatchEvent.call(t,t.media,"play"),s.dispatchEvent.call(t,t.media,"playing"),t.timers.playing=window.setInterval(function(){s.dispatchEvent.call(t,t.media,"timeupdate")},50),t.media.duration!==i.getDuration()&&(t.media.duration=i.getDuration(),s.dispatchEvent.call(t,t.media,"durationchange")),h.setQualityMenu.call(t,i.getAvailableQualityLevels());break;case 2:t.media.paused=!0,s.dispatchEvent.call(t,t.media,"pause")}s.dispatchEvent.call(t,t.elements.container,"statechange",!1,{code:e.data})}}})}},f={setup:function(){var e=this,t=s.getElements.call(this,'[id^="'+this.type+'-"]');Array.from(t).forEach(s.removeElement),s.toggleClass(this.elements.wrapper,this.config.classNames.embed,!0),f.setAspectRatio.call(this),this.media.setAttribute("id",s.generateId(this.type)),s.is.object(window.Vimeo)?f.ready.call(this):s.loadScript(this.config.urls.vimeo.api,function(){f.ready.call(e)})},setAspectRatio:function(e){var t=s.is.string(e)?e.split(":"):this.config.ratio.split(":"),i=100/t[0]*t[1],n=(200-i)/4;this.elements.wrapper.style.paddingBottom=i+"%",this.media.style.transform="translateY(-"+n+"%)"},ready:function(){var e=this,t=this,i={loop:t.config.loop.active,autoplay:t.autoplay,byline:!1,portrait:!1,title:!1,speed:!0,transparent:0,gesture:"media"},n=s.buildUrlParameters(i),a=s.parseVimeoId(t.embedId),l=s.createElement("iframe"),o="https://player.vimeo.com/video/"+a+"?"+n;l.setAttribute("src",o),l.setAttribute("allowfullscreen",""),t.media.appendChild(l),t.embed=new window.Vimeo.Player(l),t.media.paused=!0,t.media.currentTime=0,t.media.play=function(){t.embed.play().then(function(){t.media.paused=!1})},t.media.pause=function(){t.embed.pause().then(function(){t.media.paused=!0})},t.media.stop=function(){t.embed.stop().then(function(){t.media.paused=!0,t.currentTime=0})};var r=t.media.currentTime;Object.defineProperty(t.media,"currentTime",{get:function(){return r},set:function(e){var i=t.media.paused;t.media.seeking=!0,s.dispatchEvent.call(t,t.media,"seeking"),t.embed.setCurrentTime(e),i&&t.pause()}});var c=t.config.speed.selected;Object.defineProperty(t.media,"playbackRate",{get:function(){return c},set:function(e){t.embed.setPlaybackRate(e).then(function(){c=e,s.dispatchEvent.call(t,t.media,"ratechange")})}});var u=t.config.volume;Object.defineProperty(t.media,"volume",{get:function(){return u},set:function(e){t.embed.setVolume(e).then(function(){u=e,s.dispatchEvent.call(t,t.media,"volumechange")})}});var p=t.config.muted;Object.defineProperty(t.media,"muted",{get:function(){return p},set:function(e){var i=!!s.is.boolean(e)&&e;t.embed.setVolume(i?0:t.config.volume).then(function(){p=i,s.dispatchEvent.call(t,t.media,"volumechange")})}});var g=t.config.loop;Object.defineProperty(t.media,"loop",{get:function(){return g},set:function(e){var i=s.is.boolean(e)?e:t.config.loop.active;t.embed.setLoop(i).then(function(){g=i})}});var y=void 0;t.embed.getVideoUrl().then(function(e){y=e}),Object.defineProperty(t.media,"currentSrc",{get:function(){return y}}),Promise.all([t.embed.getVideoWidth(),t.embed.getVideoHeight()]).then(function(t){var i=s.getAspectRatio(t[0],t[1]);f.setAspectRatio.call(e,i)}),t.config.controls.includes("settings")&&t.config.settings.includes("speed")&&h.setSpeedMenu.call(t),t.embed.getVideoTitle().then(function(i){t.config.title=i,d.setTitle.call(e)}),t.embed.getCurrentTime().then(function(e){r=e,s.dispatchEvent.call(t,t.media,"timeupdate")}),t.embed.getDuration().then(function(e){t.media.duration=e,s.dispatchEvent.call(t,t.media,"durationchange")}),t.embed.getTextTracks().then(function(e){t.captions.tracks=e,m.setup.call(t)}),t.embed.on("cuechange",function(e){var i=null;e.cues.length&&(i=s.stripHTML(e.cues[0].text)),m.set.call(t,i)}),t.embed.on("loaded",function(){s.is.htmlElement(t.embed.element)&&t.supported.ui&&t.embed.element.setAttribute("tabindex",-1)}),t.embed.on("play",function(){t.media.paused=!1,s.dispatchEvent.call(t,t.media,"play"),s.dispatchEvent.call(t,t.media,"playing")}),t.embed.on("pause",function(){t.media.paused=!0,s.dispatchEvent.call(t,t.media,"pause")}),t.embed.on("timeupdate",function(e){t.media.seeking=!1,r=e.seconds,s.dispatchEvent.call(t,t.media,"timeupdate")}),t.embed.on("progress",function(e){t.media.buffered=e.percent,s.dispatchEvent.call(t,t.media,"progress"),1===parseInt(e.percent,10)&&s.dispatchEvent.call(t,t.media,"canplaythrough")}),t.embed.on("seeked",function(){t.media.seeking=!1,s.dispatchEvent.call(t,t.media,"seeked"),s.dispatchEvent.call(t,t.media,"play")}),t.embed.on("ended",function(){t.media.paused=!0,s.dispatchEvent.call(t,t.media,"ended")}),t.embed.on("error",function(e){t.media.error=e,s.dispatchEvent.call(t,t.media,"error")}),window.setTimeout(function(){return d.build.call(t)},0)}},y=s.getBrowser(),b={setup:function(){if(this.media)if(s.toggleClass(this.elements.container,this.config.classNames.type.replace("{0}",this.type),!0),this.isEmbed&&s.toggleClass(this.elements.container,this.config.classNames.type.replace("{0}","video"),!0),this.supported.ui&&(s.toggleClass(this.elements.container,this.config.classNames.pip.supported,a.pip&&"video"===this.type),s.toggleClass(this.elements.container,this.config.classNames.airplay.supported,a.airplay&&this.isHTML5),s.toggleClass(this.elements.container,this.config.classNames.stopped,this.config.autoplay),s.toggleClass(this.elements.container,this.config.classNames.isIos,y.isIos),s.toggleClass(this.elements.container,this.config.classNames.isTouch,a.touch)),["video","youtube","vimeo"].includes(this.type)&&(this.elements.wrapper=s.createElement("div",{class:this.config.classNames.video}),s.wrap(this.media,this.elements.wrapper)),this.isEmbed)switch(this.type){case"youtube":g.setup.call(this);break;case"vimeo":f.setup.call(this)}else d.setTitle.call(this);else this.console.warn("No media element found!")},cancelRequests:function(){this.isHTML5&&(Array.from(this.media.querySelectorAll("source")).forEach(s.removeElement),this.media.setAttribute("src",this.config.blankVideo),this.media.load(),this.console.log("Cancelled network requests"))}},v={insertElements:function(e,t){var i=this;s.is.string(t)?s.insertElement(e,this.media,{src:t}):s.is.array(t)&&t.forEach(function(t){s.insertElement(e,i.media,t)})},change:function(e){var t=this;s.is.object(e)&&"sources"in e&&e.sources.length?(b.cancelRequests.call(this),this.destroy.call(this,function(){if(s.removeElement(t.media),t.media=null,s.is.htmlElement(t.elements.container)&&t.elements.container.removeAttribute("class"),"type"in e&&(t.type=e.type,"video"===t.type)){var i=e.sources[0];"type"in i&&n.embed.includes(i.type)&&(t.type=i.type)}switch(t.supported=a.check(t.type,t.config.inline),t.type){case"video":t.media=s.createElement("video");break;case"audio":t.media=s.createElement("audio");break;case"youtube":case"vimeo":t.media=s.createElement("div"),t.embedId=e.sources[0].src}t.elements.container.appendChild(t.media),s.is.boolean(e.autoplay)&&(t.config.autoplay=e.autoplay),t.isHTML5&&(t.config.crossorigin&&t.media.setAttribute("crossorigin",""),t.config.autoplay&&t.media.setAttribute("autoplay",""),"poster"in e&&t.media.setAttribute("poster",e.poster),t.config.loop.active&&t.media.setAttribute("loop",""),t.config.muted&&t.media.setAttribute("muted",""),t.config.inline&&t.media.setAttribute("playsinline","")),s.toggleClass(t.elements.container,t.config.classNames.captions.active,t.supported.ui&&t.captions.enabled),d.addStyleHook.call(t),t.isHTML5&&v.insertElements.call(t,"source",e.sources),t.config.title=e.title,b.setup.call(t),t.isHTML5&&("tracks"in e&&v.insertElements.call(t,"track",e.tracks),t.media.load()),(t.isHTML5||t.isEmbed&&!t.supported.ui)&&d.build.call(t)},!0)):this.console.warn("Invalid source format")}},k=(function(){function e(e){this.value=e}function t(t){function i(s,a){try{var l=t[s](a),o=l.value;o instanceof e?Promise.resolve(o.value).then(function(e){i("next",e)},function(e){i("throw",e)}):n(l.done?"return":"normal",l.value)}catch(e){n("throw",e)}}function n(e,t){switch(e){case"return":s.resolve({value:t,done:!0});break;case"throw":s.reject(t);break;default:s.resolve({value:t,done:!1})}(s=s.next)?i(s.key,s.arg):a=null}var s,a;this._invoke=function(e,t){return new Promise(function(n,l){var o={key:e,arg:t,resolve:n,reject:l,next:null};a?a=a.next=o:(s=a=o,i(e,t))})},"function"!=typeof t.return&&(this.return=void 0)}"function"==typeof Symbol&&Symbol.asyncIterator&&(t.prototype[Symbol.asyncIterator]=function(){return this}),t.prototype.next=function(e){return this._invoke("next",e)},t.prototype.throw=function(e){return this._invoke("throw",e)},t.prototype.return=function(e){return this._invoke("return",e)}}(),function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}),w=function(){function e(e,t){for(var i=0;i<t.length;i++){var n=t[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,i,n){return i&&e(t.prototype,i),n&&e(t,n),t}}(),E={x:0,y:0};return function(){function e(t,n){var l=this;if(k(this,e),this.timers={},this.ready=!1,this.media=t,s.is.string(this.media)&&(this.media=document.querySelectorAll(this.media)),(window.jQuery&&this.media instanceof jQuery||s.is.nodeList(this.media)||s.is.array(this.media))&&(this.media=this.media[0]),this.config=s.extend({},i,n,function(){try{return JSON.parse(l.media.getAttribute("data-plyr"))}catch(e){return null}}()),this.elements={container:null,buttons:{},display:{},progress:{},inputs:{},settings:{menu:null,panes:{},tabs:{}},captions:null},this.captions={enabled:null,tracks:null,currentTrack:null},this.fullscreen={active:!1},this.options={speed:[],quality:[]},this.console={log:function(){},warn:function(){},error:function(){}},this.config.debug&&"console"in window&&(this.console={log:console.log,warn:console.warn,error:console.error},this.console.log("Debugging enabled")),this.console.log("Config",this.config),this.console.log("Support",a),null!==this.media&&!s.is.undefined(this.media)&&s.is.htmlElement(this.media))if(this.media.plyr)this.console.warn("Target already setup");else if(this.config.enabled)if(a.check().api){this.elements.original=this.media.cloneNode(!0);var o=this.media.tagName.toLowerCase();switch(o){case"div":if(this.type=this.media.getAttribute("data-type"),this.embedId=this.media.getAttribute("data-video-id"),s.is.empty(this.type))return void this.console.error("Setup failed: embed type missing");if(s.is.empty(this.embedId))return void this.console.error("Setup failed: video id missing");this.media.removeAttribute("data-type"),this.media.removeAttribute("data-video-id");break;case"video":case"audio":this.type=o,this.media.hasAttribute("crossorigin")&&(this.config.crossorigin=!0),this.media.hasAttribute("autoplay")&&(this.config.autoplay=!0),this.media.hasAttribute("playsinline")&&(this.config.inline=!0),this.media.hasAttribute("muted")&&(this.config.muted=!0),this.media.hasAttribute("loop")&&(this.config.loop.active=!0);break;default:return void this.console.error("Setup failed: unsupported type")}r.setup.call(this),this.supported=a.check(this.type,this.config.inline),this.supported.api?(this.media.plyr=this,this.elements.container=s.createElement("div"),s.wrap(this.media,this.elements.container),this.elements.container.setAttribute("tabindex",0),u.global.call(this),d.addStyleHook.call(this),b.setup.call(this),this.config.debug&&s.on(this.elements.container,this.config.events.join(" "),function(e){l.console.log("event: "+e.type)}),(this.isHTML5||this.isEmbed&&!this.supported.ui)&&d.build.call(this)):this.console.error("Setup failed: no support")}else this.console.error("Setup failed: no support");else this.console.error("Setup failed: disabled by config");else this.console.error("Setup failed: no suitable element passed")}return w(e,[{key:"play",value:function(){return"play"in this.media&&this.media.play(),this}},{key:"pause",value:function(){return"pause"in this.media&&this.media.pause(),this}},{key:"togglePlay",value:function(e){return!s.is.boolean(e)&&this.media.paused||e?this.play():this.pause()}},{key:"stop",value:function(){return this.restart().pause()}},{key:"restart",value:function(){return this.currentTime=0,this}},{key:"rewind",value:function(e){return this.currentTime=this.currentTime-(s.is.number(e)?e:this.config.seekTime),this}},{key:"forward",value:function(e){return this.currentTime=this.currentTime+(s.is.number(e)?e:this.config.seekTime),this}},{key:"increaseVolume",value:function(e){var t=this.media.muted?0:this.volume;return this.volume=t+s.is.number(e)?e:1,this}},{key:"decreaseVolume",value:function(e){var t=this.media.muted?0:this.volume;return this.volume=t-s.is.number(e)?e:1,this}},{key:"toggleCaptions",value:function(e){if(!this.supported.ui||!s.is.htmlElement(this.elements.buttons.captions))return this;var t=s.is.boolean(e)?e:-1===this.elements.container.className.indexOf(this.config.classNames.captions.active);return this.captions.enabled===t?this:(this.captions.enabled=t,s.toggleState(this.elements.buttons.captions,this.captions.enabled),s.toggleClass(this.elements.container,this.config.classNames.captions.active,this.captions.enabled),s.dispatchEvent.call(this,this.media,this.captions.enabled?"captionsenabled":"captionsdisabled"),this)}},{key:"toggleFullscreen",value:function(e){if(o.enabled){if(!s.is.event(e)||e.type!==o.eventType)return this.fullscreen.active?o.cancelFullScreen():o.requestFullScreen(this.elements.container),this.fullscreen.active=o.isFullScreen(this.elements.container),this;this.fullscreen.active=o.isFullScreen(this.elements.container)}else this.fullscreen.active=!this.fullscreen.active,s.toggleClass(this.elements.container,this.config.classNames.fullscreen.fallback,this.fullscreen.active),this.fullscreen.active?E={x:window.pageXOffset||0,y:window.pageYOffset||0}:window.scrollTo(E.x,E.y),document.body.style.overflow=this.fullscreen.active?"hidden":"";return this.elements.buttons&&this.elements.buttons.fullscreen&&s.toggleState(this.elements.buttons.fullscreen,this.fullscreen.active),s.dispatchEvent.call(this,this.media,this.fullscreen.active?"enterfullscreen":"exitfullscreen"),this}},{key:"airplay",value:function(){return a.airplay?(this.media.webkitShowPlaybackTargetPicker(),this):this}},{key:"toggleControls",value:function(e){var t=this,i=this;if(!s.is.htmlElement(this.elements.controls))return i;if(!this.supported.ui||!this.config.hideControls||"audio"===this.type)return i;var n=0,l=e,o=!1,r=s.hasClass(this.elements.container,this.config.classNames.loading);if(s.is.boolean(e)||(s.is.event(e)?(o="enterfullscreen"===e.type,l=["mousemove","touchstart","mouseenter","focus"].includes(e.type),["mousemove","touchmove"].includes(e.type)&&(n=2e3),"focus"===e.type&&(n=3e3)):l=s.hasClass(this.elements.container,this.config.classNames.hideControls)),window.clearTimeout(this.timers.hover),l||this.media.paused||r){if(s.toggleClass(this.elements.container,this.config.classNames.hideControls,!1)&&s.dispatchEvent.call(this,this.media,"controlsshown"),this.media.paused||r)return i;a.touch&&(n=3e3)}return l&&this.media.paused||(this.timers.hover=window.setTimeout(function(){(!t.elements.controls.pressed&&!t.elements.controls.hover||o)&&s.toggleClass(t.elements.container,t.config.classNames.hideControls,!0)&&(s.dispatchEvent.call(t,t.media,"controlshidden"),t.config.controls.includes("settings")&&!s.is.empty(t.config.settings)&&h.toggleMenu.call(t,!1))},n)),this}},{key:"on",value:function(e,t){return s.on(this.elements.container,e,t),this}},{key:"off",value:function(e,t){return s.off(this.elements.container,e,t),this}},{key:"supports",value:function(e){return a.mime.call(this,e)}},{key:"destroy",value:function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=function(){if(document.body.style.overflow="",t.embed=null,t.embedId=null,i)Object.keys(t.elements).length&&(t.elements.buttons&&t.elements.buttons.play&&Array.from(t.elements.buttons.play).forEach(function(e){return s.removeElement(e)}),s.removeElement(t.elements.captions),s.removeElement(t.elements.controls),s.removeElement(t.elements.wrapper),t.elements.buttons.play=null,t.elements.captions=null,t.elements.controls=null,t.elements.wrapper=null),s.is.function(e)&&e();else{var n=t.elements.container.parentNode;s.is.htmlElement(n)&&n.replaceChild(t.elements.original,t.elements.container),s.dispatchEvent.call(t,t.elements.original,"destroyed",!0),s.is.function(e)&&e.call(t.elements.original),t.elements=null}};switch(this.type){case"youtube":window.clearInterval(this.timers.buffering),window.clearInterval(this.timers.playing),this.embed.destroy(),n();break;case"vimeo":this.embed.unload().then(n),window.setTimeout(n,200);break;case"video":case"audio":d.toggleNativeControls.call(this,!0),n()}}},{key:"isHTML5",get:function(){return n.html5.includes(this.type)}},{key:"isEmbed",get:function(){return n.embed.includes(this.type)}},{key:"paused",get:function(){return this.media.paused}},{key:"currentTime",set:function(e){var t=0;s.is.number(e)&&(t=e),t<0?t=0:t>this.duration&&(t=this.duration),this.media.currentTime=t.toFixed(4),this.console.log("Seeking to "+this.currentTime+" seconds")},get:function(){return Number(this.media.currentTime)}},{key:"seeking",get:function(){return this.media.seeking}},{key:"duration",get:function(){var e=parseInt(this.config.duration,10),t=Number(this.media.duration);return Number.isNaN(e)?t:e}},{key:"volume",set:function(e){var t=e;s.is.string(t)&&(t=Number(t)),s.is.number(t)||(t=r.get.call(this).volume),s.is.number(t)||(t=this.config.volume),t>1&&(t=1),t<0&&(t=0),this.config.volume=t,this.media.volume=t,this.muted&&t>0&&(this.muted=!1)},get:function(){return this.media.volume}},{key:"muted",set:function(e){var t=e;s.is.boolean(t)||(t=r.get.call(this).muted),s.is.boolean(t)||(t=this.config.muted),this.config.muted=t,this.media.muted=t},get:function(){return this.media.muted}},{key:"speed",set:function(e){var t=null;(t=s.is.number(e)?e:s.is.number(r.get.call(this).speed)?r.get.call(this).speed:this.config.speed.selected)<.1&&(t=.1),t>2&&(t=2),this.config.speed.options.includes(t)?(this.config.speed.selected=t,this.media.playbackRate=t):this.console.warn("Unsupported speed ("+t+")")},get:function(){return this.media.playbackRate}},{key:"quality",set:function(e){var t=null;t=s.is.string(e)?e:s.is.number(r.get.call(this).speed)?r.get.call(this).quality:this.config.quality.selected,this.options.quality.includes(t)?(this.config.quality.selected=t,this.media.quality=t):this.console.warn("Unsupported quality option ("+t+")")},get:function(){return this.media.quality}},{key:"loop",set:function(e){var t=s.is.boolean(e)?e:this.config.loop.active;this.config.loop.active=t,this.media.loop=t},get:function(){return this.media.loop}},{key:"source",set:function(e){v.change.call(this,e)},get:function(){return this.media.currentSrc}},{key:"poster",set:function(e){"video"===this.type?s.is.string(e)&&this.media.setAttribute("poster",e):this.console.warn("Poster can only be set on HTML5 video")},get:function(){return"video"!==this.type?null:this.media.getAttribute("poster")}},{key:"autoplay",get:function(){return this.config.autoplay},set:function(e){var t=s.is.boolean(e)?e:this.config.autoplay;this.config.autoplay=t}},{key:"language",set:function(e){if(s.is.string(e)){var t=e.toLowerCase();this.captions.language!==t&&(this.toggleCaptions(!0),this.captions.language=t,s.dispatchEvent.call(this,this.media,"languagechange"),m.set.call(this),m.setup.call(this))}},get:function(){return this.captions.language}},{key:"pip",set:function(e){var t={pip:"picture-in-picture",inline:"inline"};if(a.pip){var i=s.is.boolean(e)?e:this.pip===t.inline;this.media.webkitSetPresentationMode(i?t.pip:t.inline)}},get:function(){return a.pip?this.media.webkitPresentationMode:null}}]),e}()}); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define("Plyr",t):e.Plyr=t()}(this,function(){"use strict";function e(){var e=window.localStorage.getItem(this.config.storage.key);return s.is.empty(e)?{}:JSON.parse(e)}function t(t){if(a.storage&&this.config.storage.enabled&&s.is.object(t)){var i=e.call(this);s.extend(i,t),window.localStorage.setItem(this.config.storage.key,JSON.stringify(i))}}var i={enabled:!0,title:"",debug:!1,autoplay:!1,seekTime:10,volume:1,muted:!1,duration:null,displayDuration:!0,invertTime:!0,toggleInvert:!0,ratio:"16:9",clickToPlay:!0,hideControls:!0,showPosterOnEnd:!1,disableContextMenu:!0,loadSprite:!0,iconPrefix:"plyr",iconUrl:"https://cdn.plyr.io/2.0.10/plyr.svg",blankVideo:"https://cdn.plyr.io/static/blank.mp4",quality:{default:"default",options:["hd2160","hd1440","hd1080","hd720","large","medium","small","tiny","default"]},loop:{active:!1},speed:{selected:1,options:[.5,.75,1,1.25,1.5,1.75,2]},keyboard:{focused:!0,global:!1},tooltips:{controls:!1,seek:!0},captions:{active:!1,language:window.navigator.language.split("-")[0]},fullscreen:{enabled:!0,fallback:!0},storage:{enabled:!0,key:"plyr"},controls:["play-large","play","progress","current-time","mute","volume","captions","settings","pip","airplay","fullscreen"],settings:["captions","quality","speed","loop"],i18n:{restart:"Restart",rewind:"Rewind {seektime} secs",play:"Play",pause:"Pause",forward:"Forward {seektime} secs",seek:"Seek",played:"Played",buffered:"Buffered",currentTime:"Current time",duration:"Duration",volume:"Volume",toggleMute:"Toggle Mute",toggleCaptions:"Toggle Captions",toggleFullscreen:"Toggle Fullscreen",frameTitle:"Player for {title}",captions:"Captions",settings:"Settings",speed:"Speed",quality:"Quality",loop:"Loop",start:"Start",end:"End",all:"All",reset:"Reset",none:"None",disabled:"Disabled"},urls:{vimeo:{api:"https://player.vimeo.com/api/player.js"},youtube:{api:"https://www.youtube.com/iframe_api"}},listeners:{seek:null,play:null,pause:null,restart:null,rewind:null,forward:null,mute:null,volume:null,captions:null,fullscreen:null,pip:null,airplay:null,speed:null,quality:null,loop:null,language:null},events:["ended","progress","stalled","playing","waiting","canplay","canplaythrough","loadstart","loadeddata","loadedmetadata","timeupdate","volumechange","play","pause","error","seeking","seeked","emptied","ratechange","cuechange","enterfullscreen","exitfullscreen","captionsenabled","captionsdisabled","languagechange","controlshidden","controlsshown","ready","statechange","qualitychange","qualityrequested"],selectors:{editable:"input, textarea, select, [contenteditable]",container:".plyr",controls:{container:null,wrapper:".plyr__controls"},labels:"[data-plyr]",buttons:{play:'[data-plyr="play"]',pause:'[data-plyr="pause"]',restart:'[data-plyr="restart"]',rewind:'[data-plyr="rewind"]',forward:'[data-plyr="fast-forward"]',mute:'[data-plyr="mute"]',captions:'[data-plyr="captions"]',fullscreen:'[data-plyr="fullscreen"]',pip:'[data-plyr="pip"]',airplay:'[data-plyr="airplay"]',settings:'[data-plyr="settings"]',loop:'[data-plyr="loop"]'},inputs:{seek:'[data-plyr="seek"]',volume:'[data-plyr="volume"]',speed:'[data-plyr="speed"]',language:'[data-plyr="language"]',quality:'[data-plyr="quality"]'},display:{currentTime:".plyr__time--current",duration:".plyr__time--duration",buffer:".plyr__progress--buffer",played:".plyr__progress--played",loop:".plyr__progress--loop",volume:".plyr__volume--display"},progress:".plyr__progress",captions:".plyr__captions",menu:{quality:".js-plyr__menu__list--quality"}},classNames:{video:"plyr__video-wrapper",embed:"plyr__video-embed",control:"plyr__control",type:"plyr--{0}",stopped:"plyr--stopped",playing:"plyr--playing",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",uiSupported:"plyr--full-ui",noTransition:"plyr--no-transition",menu:{value:"plyr__menu__value",badge:"plyr__badge"},captions:{enabled:"plyr--captions-enabled",active:"plyr--captions-active"},fullscreen:{enabled:"plyr--fullscreen-enabled",fallback:"plyr--fullscreen-fallback"},pip:{supported:"plyr--pip-supported",active:"plyr--pip-active"},airplay:{supported:"plyr--airplay-supported",active:"plyr--airplay-active"},tabFocus:"plyr__tab-focus"},keys:{google:null}},n={embed:["youtube","vimeo"],html5:["video","audio"]},s={is:{object:function(e){return this.getConstructor(e)===Object},number:function(e){return this.getConstructor(e)===Number&&!Number.isNaN(e)},string:function(e){return this.getConstructor(e)===String},boolean:function(e){return this.getConstructor(e)===Boolean},function:function(e){return this.getConstructor(e)===Function},array:function(e){return!this.undefined(e)&&Array.isArray(e)},nodeList:function(e){return!this.undefined(e)&&e instanceof NodeList},htmlElement:function(e){return!this.undefined(e)&&e instanceof HTMLElement},textNode:function(e){return this.getConstructor(e)===Text},event:function(e){return!this.undefined(e)&&e instanceof Event},cue:function(e){return this.instanceOf(e,window.TextTrackCue)||this.instanceOf(e,window.VTTCue)},track:function(e){return!this.undefined(e)&&(this.instanceOf(e,window.TextTrack)||"string"==typeof e.kind)},undefined:function(e){return null!==e&&void 0===e},empty:function(e){return null===e||void 0===e||(this.string(e)||this.array(e)||this.nodeList(e))&&!e.length||this.object(e)&&!Object.keys(e).length},getConstructor:function(e){return null===e||void 0===e?null:e.constructor},instanceOf:function(e,t){return Boolean(e&&t&&e instanceof t)}},getBrowser:function(){return{isIE:!!document.documentMode,isWebkit:"WebkitAppearance"in document.documentElement.style&&!/Edge/.test(navigator.userAgent),isIPhone:/(iPhone|iPod)/gi.test(navigator.platform),isIos:/(iPad|iPhone|iPod)/gi.test(navigator.platform)}},loadScript:function(e,t){if(!document.querySelectorAll('script[src="'+e+'"]').length){var i=document.createElement("script");i.src=e;var n=document.getElementsByTagName("script")[0];s.is.function(t)&&i.addEventListener("load",function(e){return t.call(null,e)},!1),n.parentNode.insertBefore(i,n)}},loadSprite:function(e,t){function i(e){this.innerHTML=e,document.body.insertBefore(this,document.body.childNodes[0])}if(s.is.string(e)){var n=s.is.string(t);if(!n||!document.querySelectorAll("#"+t).length){var l=document.createElement("div");if(l.setAttribute("hidden",""),n&&l.setAttribute("id",t),a.storage){var o=window.localStorage.getItem("cache-"+t);if(null!==o){var r=JSON.parse(o);return void i.call(l,r.content)}}fetch(e).then(function(e){return e.ok?e.text():null}).then(function(e){null!==e&&(a.storage&&window.localStorage.setItem("cache-"+t,JSON.stringify({content:e})),i.call(l,e))}).catch(function(){})}}},generateId:function(e){return e+"-"+Math.floor(1e4*Math.random())},inFrame:function(){try{return window.self!==window.top}catch(e){return!0}},wrap:function(e,t){var i=e.length?e:[e];Array.from(i).reverse().forEach(function(e,i){var n=i>0?t.cloneNode(!0):t,s=e.parentNode,a=e.nextSibling;n.appendChild(e),a?s.insertBefore(n,a):s.appendChild(n)})},createElement:function(e,t,i){var n=document.createElement(e);return s.is.object(t)&&s.setAttributes(n,t),s.is.string(i)&&(n.textContent=i),n},insertAfter:function(e,t){t.parentNode.insertBefore(e,t.nextSibling)},insertElement:function(e,t,i,n){t.appendChild(s.createElement(e,i,n))},removeElement:function(e){return s.is.htmlElement(e)&&s.is.htmlElement(e.parentNode)?(e.parentNode.removeChild(e),e):null},emptyElement:function(e){for(var t=e.childNodes.length;t>0;)e.removeChild(e.lastChild),t-=1},setAttributes:function(e,t){Object.keys(t).forEach(function(i){e.setAttribute(i,t[i])})},getAttributesFromSelector:function(e,t){if(!s.is.string(e)||s.is.empty(e))return{};var i={},n=t;return e.split(",").forEach(function(e){var t=e.trim(),a=t.replace(".",""),l=t.replace(/[[\]]/g,"").split("="),o=l[0],r=l.length>1?l[1].replace(/["']/g,""):"";switch(t.charAt(0)){case".":s.is.object(n)&&s.is.string(n.class)&&(n.class+=" "+a),i.class=a;break;case"#":i.id=t.replace("#","");break;case"[":i[o]=r}}),i},toggleClass:function(e,t,i){if(s.is.htmlElement(e)){var n=e.classList.contains(t);return e.classList[i?"add":"remove"](t),i&&!n||!i&&n}return null},hasClass:function(e,t){return s.is.htmlElement(e)&&e.classList.contains(t)},matches:function(e,t){var i={Element:Element},n=i.matches||i.webkitMatchesSelector||i.mozMatchesSelector||i.msMatchesSelector||function(){return Array.from(document.querySelectorAll(t)).includes(this)};return n.call(e,t)},getElements:function(e){return this.elements.container.querySelectorAll(e)},getElement:function(e){return this.elements.container.querySelector(e)},findElements:function(){try{return this.elements.controls=s.getElement.call(this,this.config.selectors.controls.wrapper),this.elements.buttons={play:s.getElements.call(this,this.config.selectors.buttons.play),pause:s.getElement.call(this,this.config.selectors.buttons.pause),restart:s.getElement.call(this,this.config.selectors.buttons.restart),rewind:s.getElement.call(this,this.config.selectors.buttons.rewind),forward:s.getElement.call(this,this.config.selectors.buttons.forward),mute:s.getElement.call(this,this.config.selectors.buttons.mute),pip:s.getElement.call(this,this.config.selectors.buttons.pip),airplay:s.getElement.call(this,this.config.selectors.buttons.airplay),settings:s.getElement.call(this,this.config.selectors.buttons.settings),captions:s.getElement.call(this,this.config.selectors.buttons.captions),fullscreen:s.getElement.call(this,this.config.selectors.buttons.fullscreen)},this.elements.progress=s.getElement.call(this,this.config.selectors.progress),this.elements.inputs={seek:s.getElement.call(this,this.config.selectors.inputs.seek),volume:s.getElement.call(this,this.config.selectors.inputs.volume)},this.elements.display={buffer:s.getElement.call(this,this.config.selectors.display.buffer),duration:s.getElement.call(this,this.config.selectors.display.duration),currentTime:s.getElement.call(this,this.config.selectors.display.currentTime)},s.is.htmlElement(this.elements.progress)&&(this.elements.display.seekTooltip=this.elements.progress.querySelector("."+this.config.classNames.tooltip)),!0}catch(e){return this.console.warn("It looks like there is a problem with your custom controls HTML",e),this.toggleNativeControls(!0),!1}},getFocusElement:function(){var e=document.activeElement;return e=e&&e!==document.body?document.querySelector(":focus"):null},trapFocus:function(){var e=this,t=s.getElements.call(this,"button:not(:disabled), input:not(:disabled), [tabindex]"),i=t[0],n=t[t.length-1];s.on(this.elements.container,"keydown",function(t){if("Tab"===t.key&&9===t.keyCode&&e.fullscreen.active){var a=s.getFocusElement();a!==n||t.shiftKey?a===i&&t.shiftKey&&(n.focus(),t.preventDefault()):(i.focus(),t.preventDefault())}},!1)},toggleListener:function(e,t,i,n,l,o){if(null!==e&&!s.is.undefined(e))if(s.is.nodeList(e))Array.from(e).forEach(function(e){e instanceof Node&&s.toggleListener.call(null,e,t,i,n,l,o)});else{var r=t.split(" "),c=!!s.is.boolean(o)&&o;a.passiveListeners&&(c={passive:!s.is.boolean(l)||l,capture:!!s.is.boolean(o)&&o}),r.forEach(function(t){e[n?"addEventListener":"removeEventListener"](t,i,c)})}},on:function(e,t,i,n,a){s.toggleListener(e,t,i,!0,n,a)},off:function(e,t,i,n,a){s.toggleListener(e,t,i,!1,n,a)},dispatchEvent:function(e,t,i,n){if(e&&t){var a=new CustomEvent(t,{bubbles:!!s.is.boolean(i)&&i,detail:Object.assign({},n,{plyr:this instanceof Plyr?this:null})});e.dispatchEvent(a)}},toggleState:function(e,t){if(s.is.htmlElement(e)){var i=s.is.boolean(t)?t:!e.getAttribute("aria-pressed");e.setAttribute("aria-pressed",i)}},getPercentage:function(e,t){return 0===e||0===t||Number.isNaN(e)||Number.isNaN(t)?0:(e/t*100).toFixed(2)},extend:function(){for(var e=arguments.length,t=Array(e),i=0;i<e;i++)t[i]=arguments[i];var n=t.length;if(!n)return null;if(1===n)return t[0];var a=Array.prototype.shift.call(t);return s.is.object(a)||(a={}),t.forEach(function(e){s.is.object(e)&&Object.keys(e).forEach(function(t){e[t]&&e[t].constructor&&e[t].constructor===Object?(a[t]=a[t]||{},s.extend(a[t],e[t])):a[t]=e[t]})}),a},parseYouTubeId:function(e){return e.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/)?RegExp.$2:e},parseVimeoId:function(e){if(s.is.number(Number(e)))return e;return e.match(/^.*(vimeo.com\/|video\/)(\d+).*/)?RegExp.$2:e},buildUrlParameters:function(e){return s.is.object(e)?Object.keys(e).map(function(t){return encodeURIComponent(t)+"="+encodeURIComponent(e[t])}).join("&"):""},stripHTML:function(e){var t=document.createDocumentFragment(),i=document.createElement("div");return t.appendChild(i),i.innerHTML=e,t.firstChild.innerText},getAspectRatio:function(e,t){var i=function e(t,i){return 0===i?t:e(i,t%i)}(e,t);return e/i+":"+t/i},transitionEnd:function(){var e=document.createElement("span"),t=Object.keys({WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"}).find(function(t){return void 0!==e.style[t]});return"string"==typeof t&&t}()},a={audio:"canPlayType"in document.createElement("audio"),video:"canPlayType"in document.createElement("video"),check:function(e,t){var i=!1,n=!1,l=s.getBrowser(),o=l.isIPhone&&t&&a.inline;switch(e){case"video":n=(i=a.video)&&a.rangeInput&&(!l.isIPhone||o);break;case"audio":n=(i=a.audio)&&a.rangeInput;break;case"youtube":i=!0,n=a.rangeInput&&(!l.isIPhone||o);break;case"vimeo":i=!0,n=a.rangeInput&&!l.isIPhone;break;default:n=(i=a.audio&&a.video)&&a.rangeInput}return{api:i,ui:n}},storage:function(){if(!("localStorage"in window))return!1;try{return window.localStorage.setItem("___test","___test"),window.localStorage.removeItem("___test"),!0}catch(e){return!1}}(),pip:!s.getBrowser().isIPhone&&s.is.function(s.createElement("video").webkitSetPresentationMode),airplay:s.is.function(window.WebKitPlaybackTargetAvailabilityEvent),inline:"playsInline"in document.createElement("video"),mime:function(e){var t=this.media;try{if(!s.is.function(t.canPlayType))return!1;if("video"===this.type)switch(e){case"video/webm":return t.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/,"");case"video/mp4":return t.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/,"");case"video/ogg":return t.canPlayType('video/ogg; codecs="theora"').replace(/no/,"");default:return!1}else if("audio"===this.type)switch(e){case"audio/mpeg":return t.canPlayType("audio/mpeg;").replace(/no/,"");case"audio/ogg":return t.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/,"");case"audio/wav":return t.canPlayType('audio/wav; codecs="1"').replace(/no/,"");default:return!1}}catch(e){return!1}return!1},textTracks:"textTracks"in document.createElement("video"),passiveListeners:function(){var e=!1;try{var t=Object.defineProperty({},"passive",{get:function(){return e=!0,null}});window.addEventListener("test",null,t)}catch(e){}return e}(),rangeInput:function(){var e=document.createElement("input");return e.type="range","range"===e.type}(),touch:"ontouchstart"in document.documentElement,transitions:!1!==s.transitionEnd,reducedMotion:"matchMedia"in window&&window.matchMedia("(prefers-reduced-motion)").matches},l=function(){var e=!1;return s.is.function(document.cancelFullScreen)?e="":["webkit","o","moz","ms","khtml"].some(function(t){return s.is.function(document[t+"CancelFullScreen"])?(e=t,!0):!(!s.is.function(document.msExitFullscreen)||!document.msFullscreenEnabled)&&(e="ms",!0)}),e}(),o={prefix:l,enabled:document.fullscreenEnabled||document.webkitFullscreenEnabled||document.mozFullScreenEnabled||document.msFullscreenEnabled,eventType:"ms"===l?"MSFullscreenChange":l+"fullscreenchange",isFullScreen:function(e){if(!o.enabled)return!1;var t=s.is.undefined(e)?document.body:e;switch(l){case"":return document.fullscreenElement===t;case"moz":return document.mozFullScreenElement===t;default:return document[l+"FullscreenElement"]===t}},requestFullScreen:function(e){if(!o.enabled)return!1;var t=s.is.undefined(e)?document.body:e;return l.length?t[l+("ms"===l?"RequestFullscreen":"RequestFullScreen")]():t.requestFullScreen()},cancelFullScreen:function(){return!!o.enabled&&(l.length?document[l+("ms"===l?"ExitFullscreen":"CancelFullScreen")]():document.cancelFullScreen())},element:function(){return o.enabled?l.length?document[l+"FullscreenElement"]:document.fullscreenElement:null},setup:function(){if(this.supported.ui&&"audio"!==this.type&&this.config.fullscreen.enabled){var e=o.enabled;e||this.config.fullscreen.fallback&&!s.inFrame()?(this.console.log((e?"Native":"Fallback")+" fullscreen enabled"),s.toggleClass(this.elements.container,this.config.classNames.fullscreen.enabled,!0)):this.console.log("Fullscreen not supported and fallback disabled"),this.elements.buttons&&this.elements.buttons.fullscreen&&s.toggleState(this.elements.buttons.fullscreen,!1),s.trapFocus.call(this)}}},r={setup:function(){var e=null,i={};return a.storage&&this.config.storage.enabled?(window.localStorage.removeItem("plyr-volume"),(e=window.localStorage.getItem(this.config.storage.key))&&(/^\d+(\.\d+)?$/.test(e)?t({volume:parseFloat(e)}):i=JSON.parse(e)),i):i},set:t,get:e},c=s.getBrowser(),u={global:function(){var e=this,t=null,i=function(e){return e.keyCode?e.keyCode:e.which},n=function(n){var a=i(n),l="keydown"===n.type,r=l&&a===t;if(s.is.number(a)){if(l){var c=[48,49,50,51,52,53,54,56,57,32,75,38,40,77,39,37,70,67,73,76,79],u=s.getFocusElement();if(s.is.htmlElement(u)&&s.matches(u,e.config.selectors.editable))return;switch(c.includes(a)&&(n.preventDefault(),n.stopPropagation()),a){case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:r||(e.currentTime=e.duration/10*(a-48));break;case 32:case 75:r||e.togglePlay();break;case 38:e.increaseVolume(.1);break;case 40:e.decreaseVolume(.1);break;case 77:r||(e.muted=!e.muted);break;case 39:e.forward();break;case 37:e.rewind();break;case 70:e.toggleFullscreen();break;case 67:r||e.toggleCaptions();break;case 76:e.loop=!e.loop}!o.enabled&&e.fullscreen.active&&27===a&&e.toggleFullscreen(),t=a}else t=null}};this.config.keyboard.global?s.on(window,"keydown keyup",n,!1):this.config.keyboard.focused&&s.on(this.elements.container,"keydown keyup",n,!1),s.on(this.elements.container,"focusout",function(t){s.toggleClass(t.target,e.config.classNames.tabFocus,!1)}),s.on(this.elements.container,"keydown",function(t){9===t.keyCode&&window.setTimeout(function(){s.toggleClass(s.getFocusElement(),e.config.classNames.tabFocus,!0)},0)}),this.config.hideControls&&s.on(this.elements.container,"click mouseenter mouseleave mousemove touchmove enterfullscreen exitfullscreen",function(t){e.toggleControls(t)})},media:function(){var e=this;if(s.on(this.media,"timeupdate seeking",function(t){return d.timeUpdate.call(e,t)}),s.on(this.media,"durationchange loadedmetadata",function(t){return d.durationUpdate.call(e,t)}),s.on(this.media,"ended",function(){"video"===e.type&&e.config.showPosterOnEnd&&(e.restart(),e.media.load())}),s.on(this.media,"progress playing",function(t){return d.updateProgress.call(e,t)}),s.on(this.media,"volumechange",function(t){return d.updateVolume.call(e,t)}),s.on(this.media,"play pause ended",function(t){return d.checkPlaying.call(e,t)}),s.on(this.media,"waiting canplay seeked",function(t){return d.checkLoading.call(e,t)}),this.supported.ui&&this.config.clickToPlay&&"audio"!==this.type){var t=s.getElement.call(this,"."+this.config.classNames.video);if(!t)return;t.style.cursor="pointer",s.on(t,"click",function(){e.config.hideControls&&a.touch&&!e.media.paused||(e.media.paused?e.play():e.media.ended?(e.restart(),e.play()):e.pause())})}this.config.disableContextMenu&&s.on(this.media,"contextmenu",function(e){e.preventDefault()},!1),s.on(this.media,"ratechange",function(){h.updateSetting.call(e,"speed"),r.set.call(e,{speed:e.speed})}),s.on(this.media,"qualitychange",function(){h.updateSetting.call(e,"quality"),r.set.call(e,{quality:e.quality})}),s.on(this.media,"languagechange",function(){r.set.call(e,{language:e.language})}),s.on(this.media,"volumechange",function(){r.set.call(e,{volume:e.volume,muted:e.muted})}),s.on(this.media,"captionsenabled captionsdisabled",function(){h.updateSetting.call(e,"captions"),r.set.call(e,{captions:e.captions.enabled})}),s.on(this.media,this.config.events.concat(["keyup","keydown"]).join(" "),function(t){var i={};"error"===t.type&&(i=e.media.error),s.dispatchEvent.call(e,e.elements.container,t.type,!0,i)})},controls:function(){var e=this,t=c.isIE?"change":"input",i=function(t,i,n){var a=e.config.listeners[i];s.is.function(a)&&a.call(e,t),!t.defaultPrevented&&s.is.function(n)&&n.call(e,t)},n=function(){var t=e.togglePlay(),i=e.elements.buttons[t?"pause":"play"];s.is.htmlElement(i)&&i.focus()};s.on(this.elements.buttons.play,"click",function(e){return i(e,"play",n)}),s.on(this.elements.buttons.pause,"click",function(e){return i(e,"pause",n)}),s.on(this.elements.buttons.restart,"click",function(t){return i(t,"restart",function(){e.restart()})}),s.on(this.elements.buttons.rewind,"click",function(t){return i(t,"rewind",function(){e.rewind()})}),s.on(this.elements.buttons.forward,"click",function(t){return i(t,"forward",function(){e.forward()})}),s.on(this.elements.buttons.mute,"click",function(t){return i(t,"mute",function(){e.muted=!e.muted})}),s.on(this.elements.buttons.captions,"click",function(t){return i(t,"captions",function(){e.toggleCaptions()})}),s.on(this.elements.buttons.fullscreen,"click",function(t){return i(t,"fullscreen",function(){e.toggleFullscreen()})}),s.on(this.elements.buttons.pip,"click",function(t){return i(t,"pip",function(){e.pip="toggle"})}),s.on(this.elements.buttons.airplay,"click",function(t){return i(t,"airplay",function(){e.airPlay()})}),s.on(this.elements.buttons.settings,"click",function(t){h.toggleMenu.call(e,t)}),s.on(document.documentElement,"click",function(t){h.toggleMenu.call(e,t)}),s.on(this.elements.settings.form,"click",function(t){h.showTab.call(e,t),s.matches(t.target,e.config.selectors.inputs.language)?i(t,"language",function(){var i=t.target.value;e.toggleCaptions(!s.is.empty(i)),s.is.empty(i)||(e.language=t.target.value.toLowerCase())}):s.matches(t.target,e.config.selectors.inputs.quality)?i(t,"quality",function(){e.quality=t.target.value}):s.matches(t.target,e.config.selectors.inputs.speed)&&i(t,"speed",function(){e.speed=parseFloat(t.target.value)})}),s.on(this.elements.inputs.seek,t,function(t){return i(t,"seek",function(){e.currentTime=t.target.value/t.target.max*e.duration})}),this.config.toggleInvert&&!s.is.htmlElement(this.elements.display.duration)&&s.on(this.elements.display.currentTime,"click",function(){0!==e.currentTime&&(e.config.invertTime=!e.config.invertTime,d.timeUpdate.call(e))}),s.on(this.elements.inputs.volume,t,function(t){return i(t,"volume",function(){e.volume=t.target.value})}),c.isWebkit&&s.on(s.getElements.call(this,'input[type="range"]'),"input",function(t){h.updateRangeFill.call(e,t.target)}),s.on(this.elements.progress,"mouseenter mouseleave mousemove",function(t){return h.updateSeekTooltip.call(e,t)}),this.config.hideControls&&(s.on(this.elements.controls,"mouseenter mouseleave",function(t){e.elements.controls.hover="mouseenter"===t.type}),s.on(this.elements.controls,"mousedown mouseup touchstart touchend touchcancel",function(t){e.elements.controls.pressed=["mousedown","touchstart"].includes(t.type)}),s.on(this.elements.controls,"focusin focusout",function(t){e.toggleControls(t)},!0)),s.on(this.elements.inputs.volume,"wheel",function(t){return i(t,"volume",function(){var i=t.webkitDirectionInvertedFromDevice,n=0;(t.deltaY<0||t.deltaX>0)&&(i?(e.decreaseVolume(.02),n=-1):(e.increaseVolume(.02),n=1)),(t.deltaY>0||t.deltaX<0)&&(i?(e.increaseVolume(.02),n=1):(e.decreaseVolume(.02),n=-1)),(1===n&&e.media.volume<1||-1===n&&e.media.volume>0)&&t.preventDefault()})},!1)}},d={addStyleHook:function(){s.toggleClass(this.elements.container,this.config.selectors.container.replace(".",""),!0),s.toggleClass(this.elements.container,this.config.classNames.uiSupported,this.supported.ui)},toggleNativeControls:function(){arguments.length>0&&void 0!==arguments[0]&&arguments[0]&&this.isHTML5?this.media.setAttribute("controls",""):this.media.removeAttribute("controls")},build:function(){if(u.media.call(this),!this.supported.ui)return this.console.warn("Basic support only for "+this.type),s.removeElement.call(this,"controls"),s.removeElement.call(this,"buttons.play"),void d.toggleNativeControls.call(this,!0);s.is.htmlElement(this.elements.controls)||(h.inject.call(this),u.controls.call(this)),s.is.htmlElement(this.elements.controls)&&(d.toggleNativeControls.call(this),o.setup.call(this),m.setup.call(this),this.volume=null,this.muted=null,this.speed=null,this.loop=null,this.options.quality=[],d.timeUpdate.call(this),d.checkPlaying.call(this),this.ready=!0,s.dispatchEvent.call(this,this.media,"ready"),d.setTitle.call(this))},setTitle:function(){var e=this.config.i18n.play;if(s.is.string(this.config.title)&&!s.is.empty(this.config.title)&&(e+=", "+this.config.title,this.elements.container.setAttribute("aria-label",this.config.title)),s.is.nodeList(this.elements.buttons.play)&&Array.from(this.elements.buttons.play).forEach(function(t){t.setAttribute("aria-label",e)}),this.isEmbed){var t=s.getElement.call(this,"iframe");if(!s.is.htmlElement(t))return;var i=s.is.empty(this.config.title)?"video":this.config.title;t.setAttribute("title",this.config.i18n.frameTitle.replace("{title}",i))}},checkPlaying:function(){s.toggleClass(this.elements.container,this.config.classNames.playing,!this.paused),s.toggleClass(this.elements.container,this.config.classNames.stopped,this.paused),this.toggleControls(this.paused)},checkLoading:function(e){var t=this;this.loading="waiting"===e.type,clearTimeout(this.timers.loading),this.timers.loading=setTimeout(function(){s.toggleClass(t.elements.container,t.config.classNames.loading,t.loading),t.toggleControls(t.loading)},this.loading?250:0)},updateVolume:function(){this.supported.ui&&(s.is.htmlElement(this.elements.inputs.volume)&&d.setRange.call(this,this.elements.inputs.volume,this.muted?0:this.volume),s.is.htmlElement(this.elements.buttons.mute)&&s.toggleState(this.elements.buttons.mute,this.muted||0===this.volume))},setRange:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;s.is.htmlElement(e)&&(e.value=t,h.updateRangeFill.call(this,e))},setProgress:function(e,t){var i=s.is.number(t)?t:0,n=s.is.htmlElement(e)?e:this.elements.display.buffer;if(s.is.htmlElement(n)){n.value=i;var a=n.getElementsByTagName("span")[0];s.is.htmlElement(a)&&(a.childNodes[0].nodeValue=i)}},updateProgress:function(e){var t=this;if(this.supported.ui&&s.is.event(e)){var i=0;if(e)switch(e.type){case"timeupdate":case"seeking":i=s.getPercentage(this.currentTime,this.duration),"timeupdate"===e.type&&d.setRange.call(this,this.elements.inputs.seek,i);break;case"playing":case"progress":i=function(){var e=t.media.buffered;return e&&e.length?s.getPercentage(e.end(0),t.duration):s.is.number(e)?100*e:0}(),d.setProgress.call(this,this.elements.display.buffer,i)}}},updateTimeDisplay:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,i=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if(s.is.htmlElement(e)&&s.is.number(t)){var n=function(e){return("0"+e).slice(-2)},a=function(e){return parseInt(e/60/60%60,10)},l=a(t),o=function(e){return parseInt(e/60%60,10)}(t),r=function(e){return parseInt(e%60,10)}(t);a(this.duration)>0?l+=":":l="",e.textContent=(i?"-":"")+l+n(o)+":"+n(r)}},timeUpdate:function(e){var t=!s.is.htmlElement(this.elements.display.duration)&&this.config.invertTime;d.updateTimeDisplay.call(this,this.elements.display.currentTime,t?this.duration-this.currentTime:this.currentTime,t),e&&"timeupdate"===e.type&&this.media.seeking||d.updateProgress.call(this,e)},durationUpdate:function(){this.supported.ui&&(!s.is.htmlElement(this.elements.display.duration)&&this.config.displayDuration&&this.paused&&d.updateTimeDisplay.call(this,this.elements.display.currentTime,this.duration),s.is.htmlElement(this.elements.display.duration)&&d.updateTimeDisplay.call(this,this.elements.display.duration,this.duration),h.updateSeekTooltip.call(this))}},p=s.getBrowser(),h={updateRangeFill:function(e){if(p.isWebkit){var t=s.is.event(e)?e.target:e;if(s.is.htmlElement(t)&&"range"===t.getAttribute("type")){s.is.htmlElement(this.elements.styleSheet)||(this.elements.styleSheet=s.createElement("style"),this.elements.container.appendChild(this.elements.styleSheet));var i=this.elements.styleSheet.sheet,n=t.value/t.max*100,a="#"+t.id+"::-webkit-slider-runnable-track",l="{ background-image: linear-gradient(to right, currentColor "+n+"%, transparent "+n+"%) }",o=Array.from(i.rules).findIndex(function(e){return e.selectorText===a});-1!==o&&i.deleteRule(o),i.insertRule([a,l].join(" "))}}},getIconUrl:function(){return{url:this.config.iconUrl,absolute:0===this.config.iconUrl.indexOf("http")||p.isIE&&!window.svg4everybody}},createIcon:function(e,t){var i=h.getIconUrl.call(this),n=(i.absolute?"":i.url)+"#"+this.config.iconPrefix,a=document.createElementNS("http://www.w3.org/2000/svg","svg");s.setAttributes(a,s.extend(t,{role:"presentation"}));var l=document.createElementNS("http://www.w3.org/2000/svg","use"),o=n+"-"+e;return l.setAttributeNS("http://www.w3.org/1999/xlink","href",o),l.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",o),a.appendChild(l),a},createLabel:function(e){var t=this.config.i18n[e];switch(e){case"pip":t="PIP";break;case"airplay":t="AirPlay"}return s.createElement("span",{class:this.config.classNames.hidden},t)},createBadge:function(e){if(s.is.empty(e))return null;var t=s.createElement("span",{class:this.config.classNames.menu.value});return t.appendChild(s.createElement("span",{class:this.config.classNames.menu.badge},e)),t},createButton:function(e,t){var i=s.createElement("button"),n=Object.assign({},t),a=e,l=void 0,o=void 0,r=void 0;switch("type"in n||(n.type="button"),"class"in n?-1===n.class.indexOf(this.config.classNames.control)&&(n.class+=" "+this.config.classNames.control):n.class=this.config.classNames.control,a){case"mute":r="toggleMute",l="volume",o="muted";break;case"captions":r="toggleCaptions",l="captions-off",o="captions-on";break;case"fullscreen":r="toggleFullscreen",l="enter-fullscreen",o="exit-fullscreen";break;case"play-large":n.class="plyr__play-large",a="play",r="play",l="play";break;default:r=a,l=a}return s.extend(n,s.getAttributesFromSelector(this.config.selectors.buttons[a],n)),s.is.string(o)?(i.appendChild(h.createIcon.call(this,o,{class:"icon--pressed"})),i.appendChild(h.createIcon.call(this,l,{class:"icon--not-pressed"}))):i.appendChild(h.createIcon.call(this,l)),i.appendChild(h.createLabel.call(this,r)),s.setAttributes(i,n),this.elements.buttons[a]=i,i},createRange:function(e,t){var i=s.createElement("label",{for:t.id,class:this.config.classNames.hidden},this.config.i18n[e]),n=s.createElement("input",s.extend(s.getAttributesFromSelector(this.config.selectors.inputs[e]),{type:"range",min:0,max:100,step:.01,value:0,autocomplete:"off"},t));return this.elements.inputs[e]=n,h.updateRangeFill.call(this,n),{label:i,input:n}},createProgress:function(e,t){var i=s.createElement("progress",s.extend(s.getAttributesFromSelector(this.config.selectors.display[e]),{min:0,max:100,value:0},t));if("volume"!==e){i.appendChild(s.createElement("span",null,"0"));var n="";switch(e){case"played":n=this.config.i18n.played;break;case"buffer":n=this.config.i18n.buffered}i.textContent="% "+n.toLowerCase()}return this.elements.display[e]=i,i},createTime:function(e){var t=s.createElement("span",{class:"plyr__time"});return t.appendChild(s.createElement("span",{class:this.config.classNames.hidden},this.config.i18n[e])),t.appendChild(s.createElement("span",s.getAttributesFromSelector(this.config.selectors.display[e]),"00:00")),this.elements.display[e]=t,t},createMenuItem:function(e,t,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:null,l=arguments.length>5&&void 0!==arguments[5]&&arguments[5],o=s.createElement("li"),r=s.createElement("label",{class:this.config.classNames.control}),c=s.createElement("input",s.extend(s.getAttributesFromSelector(this.config.selectors.inputs[i]),{type:"radio",name:"plyr-"+i,value:e,checked:l,class:"plyr__sr-only"})),u=s.createElement("span",{"aria-hidden":!0});r.appendChild(c),r.appendChild(u),r.insertAdjacentHTML("beforeend",n),s.is.htmlElement(a)&&r.appendChild(a),o.appendChild(r),t.appendChild(o)},updateSeekTooltip:function(e){if(this.config.tooltips.seek&&s.is.htmlElement(this.elements.inputs.seek)&&s.is.htmlElement(this.elements.display.seekTooltip)&&0!==this.duration){var t=0,i=this.elements.inputs.seek.getBoundingClientRect(),n=this.config.classNames.tooltip+"--visible";if(s.is.event(e))t=100/i.width*(e.pageX-i.left);else{if(!s.hasClass(this.elements.display.seekTooltip,n))return;t=this.elements.display.seekTooltip.style.left.replace("%","")}t<0?t=0:t>100&&(t=100),d.updateTimeDisplay.call(this,this.elements.display.seekTooltip,this.duration/100*t),this.elements.display.seekTooltip.style.left=t+"%",s.is.event(e)&&["mouseenter","mouseleave"].includes(e.type)&&s.toggleClass(this.elements.display.seekTooltip,n,"mouseenter"===e.type)}},toggleTab:function(e,t){var i=this.elements.settings.tabs[e],n=this.elements.settings.panes[e];s.is.htmlElement(i)&&(t?i.removeAttribute("hidden"):i.setAttribute("hidden","")),s.is.htmlElement(n)&&(t?n.removeAttribute("hidden"):n.setAttribute("hidden",""))},setQualityMenu:function(e){var t=this,i=this.elements.settings.panes.quality.querySelector("ul");s.is.array(e)?this.options.quality=e.filter(function(e){return t.config.quality.options.includes(e)}):this.options.quality=this.config.quality.options;var n=!s.is.empty(this.options.quality)&&"youtube"===this.type;if(h.toggleTab.call(this,"quality",n),n){s.emptyElement(i);var a=function(e){var i="";switch(e){case"hd2160":i="4K";break;case"hd1440":i="WQHD";break;case"hd1080":case"hd720":i="HD"}return i.length?h.createBadge.call(t,i):null};this.options.quality.forEach(function(e){return h.createMenuItem.call(t,e,i,"quality",h.getLabel.call(t,"quality",e),a(e))}),h.updateSetting.call(this,"quality",i)}},getLabel:function(e,t){switch(e){case"speed":return 1===t?"Normal":t+"×";case"quality":switch(t){case"hd2160":return"2160P";case"hd1440":return"1440P";case"hd1080":return"1080P";case"hd720":return"720P";case"large":return"480P";case"medium":return"360P";case"small":return"240P";case"tiny":return"Tiny";case"default":return"Auto";default:return t}case"captions":return h.getLanguage.call(this);default:return null}},updateSetting:function(e,t){var i=this.elements.settings.panes[e],n=null,a=t;switch(e){case"captions":n=this.captions.language,this.captions.enabled||(n="");break;default:if(n=this[e],s.is.empty(n)&&(n=this.config[e].default),!this.options[e].includes(n))return void this.console.warn("Unsupported value of '"+n+"' for "+e);if(!this.config[e].options.includes(n))return void this.console.warn("Disabled value of '"+n+"' for "+e)}s.is.htmlElement(a)||(a=i&&i.querySelector("ul"));var l=a&&a.querySelector('input[value="'+n+'"]');s.is.htmlElement(l)&&(l.checked=!0,this.elements.settings.tabs[e].querySelector("."+this.config.classNames.menu.value).innerHTML=h.getLabel.call(this,e,n))},getLanguage:function(){return this.supported.ui?!a.textTracks||s.is.empty(this.captions.tracks)?this.config.i18n.none:this.captions.enabled?this.captions.currentTrack.label:this.config.i18n.disabled:null},setCaptionsMenu:function(){var e=this,t=this.elements.settings.panes.captions.querySelector("ul"),i=!s.is.empty(this.captions.tracks);if(h.toggleTab.call(this,"captions",i),s.emptyElement(t),!s.is.empty(this.captions.tracks)){var n=Array.from(this.captions.tracks).map(function(e){return{language:e.language,label:s.is.empty(e.label)?e.language.toUpperCase():e.label}});n.unshift({language:"",label:this.config.i18n.none}),n.forEach(function(i){h.createMenuItem.call(e,i.language,t,"language",i.label||i.language,h.createBadge.call(e,i.language.toUpperCase()),i.language.toLowerCase()===e.captions.language.toLowerCase())}),h.updateSetting.call(this,"captions",t)}},setSpeedMenu:function(e){var t=this;s.is.array(e)?this.options.speed=e.filter(function(e){return t.config.speed.options.includes(e)}):this.options.speed=this.config.speed.options;var i=!s.is.empty(this.options.speed);if(h.toggleTab.call(this,"speed",i),i){var n=this.elements.settings.panes.speed.querySelector("ul");this.elements.settings.tabs.speed.removeAttribute("hidden"),this.elements.settings.panes.speed.removeAttribute("hidden"),s.emptyElement(n),this.options.speed.forEach(function(e){return h.createMenuItem.call(t,e,n,"speed",h.getLabel.call(t,"speed",e))}),h.updateSetting.call(this,"speed",n)}},toggleMenu:function(e){var t=this.elements.settings.form,i=this.elements.buttons.settings,n=s.is.boolean(e)?e:s.is.htmlElement(t)&&"true"===t.getAttribute("aria-hidden");if(s.is.event(e)){var a=s.is.htmlElement(t)&&t.contains(e.target),l=e.target===this.elements.buttons.settings;if(a||!a&&!l&&n)return;l&&e.stopPropagation()}s.is.htmlElement(i)&&i.setAttribute("aria-expanded",n),s.is.htmlElement(t)&&(t.setAttribute("aria-hidden",!n),n?t.removeAttribute("tabindex"):t.setAttribute("tabindex",-1))},getTabSize:function(e){var t=e.cloneNode(!0);t.style.position="absolute",t.style.opacity=0,t.setAttribute("aria-hidden",!1),Array.from(t.querySelectorAll("input[name]")).forEach(function(e){var t=e.getAttribute("name");e.setAttribute("name",t+"-clone")}),e.parentNode.appendChild(t);var i=t.scrollWidth,n=t.scrollHeight;return s.removeElement(t),{width:i,height:n}},showTab:function(e){var t=this.elements.settings.menu,i=e.target,n="false"===i.getAttribute("aria-expanded"),l=document.getElementById(i.getAttribute("aria-controls"));if(s.is.htmlElement(l)&&"tabpanel"===l.getAttribute("role")){var o=t.querySelector('[role="tabpanel"][aria-hidden="false"]'),r=o.parentNode;if(Array.from(t.querySelectorAll('[aria-controls="'+o.getAttribute("id")+'"]')).forEach(function(e){e.setAttribute("aria-expanded",!1)}),a.transitions&&!a.reducedMotion){r.style.width=o.scrollWidth+"px",r.style.height=o.scrollHeight+"px";var c=h.getTabSize.call(this,l),u=function e(t){t.target===r&&["width","height"].includes(t.propertyName)&&(r.style.width="",r.style.height="",s.off(r,s.transitionEnd,e))};s.on(r,s.transitionEnd,u),r.style.width=c.width+"px",r.style.height=c.height+"px"}o.setAttribute("aria-hidden",!0),o.setAttribute("tabindex",-1),l.setAttribute("aria-hidden",!n),i.setAttribute("aria-expanded",n),l.removeAttribute("tabindex"),l.querySelectorAll("button:not(:disabled), input:not(:disabled), [tabindex]")[0].focus()}},create:function(e){var t=this;if(s.is.empty(this.config.controls))return null;var i=s.createElement("div",s.getAttributesFromSelector(this.config.selectors.controls.wrapper));if(this.config.controls.includes("restart")&&i.appendChild(h.createButton.call(this,"restart")),this.config.controls.includes("rewind")&&i.appendChild(h.createButton.call(this,"rewind")),this.config.controls.includes("play")&&(i.appendChild(h.createButton.call(this,"play")),i.appendChild(h.createButton.call(this,"pause"))),this.config.controls.includes("fast-forward")&&i.appendChild(h.createButton.call(this,"fast-forward")),this.config.controls.includes("progress")){var n=s.createElement("span",s.getAttributesFromSelector(this.config.selectors.progress)),l=h.createRange.call(this,"seek",{id:"plyr-seek-"+e.id});if(n.appendChild(l.label),n.appendChild(l.input),n.appendChild(h.createProgress.call(this,"buffer")),this.config.tooltips.seek){var o=s.createElement("span",{role:"tooltip",class:this.config.classNames.tooltip},"00:00");n.appendChild(o),this.elements.display.seekTooltip=o}this.elements.progress=n,i.appendChild(this.elements.progress)}if(this.config.controls.includes("current-time")&&i.appendChild(h.createTime.call(this,"currentTime")),this.config.controls.includes("duration")&&i.appendChild(h.createTime.call(this,"duration")),this.config.controls.includes("mute")&&i.appendChild(h.createButton.call(this,"mute")),this.config.controls.includes("volume")){var r=s.createElement("span",{class:"plyr__volume"}),c={max:1,step:.05,value:this.config.volume},u=h.createRange.call(this,"volume",s.extend(c,{id:"plyr-volume-"+e.id}));r.appendChild(u.label),r.appendChild(u.input),i.appendChild(r)}if(this.config.controls.includes("captions")&&i.appendChild(h.createButton.call(this,"captions")),this.config.controls.includes("settings")&&!s.is.empty(this.config.settings)){var d=s.createElement("div",{class:"plyr__menu"});d.appendChild(h.createButton.call(this,"settings",{id:"plyr-settings-toggle-"+e.id,"aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id,"aria-expanded":!1}));var p=s.createElement("form",{class:"plyr__menu__container",id:"plyr-settings-"+e.id,"aria-hidden":!0,"aria-labelled-by":"plyr-settings-toggle-"+e.id,role:"tablist",tabindex:-1}),m=s.createElement("div"),g=s.createElement("div",{id:"plyr-settings-"+e.id+"-home","aria-hidden":!1,"aria-labelled-by":"plyr-settings-toggle-"+e.id,role:"tabpanel"}),f=s.createElement("ul",{role:"tablist"});this.config.settings.forEach(function(i){var n=s.createElement("li",{role:"tab",hidden:""}),a=s.createElement("button",s.extend(s.getAttributesFromSelector(t.config.selectors.buttons.settings),{type:"button",class:t.config.classNames.control+" "+t.config.classNames.control+"--forward",id:"plyr-settings-"+e.id+"-"+i+"-tab","aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id+"-"+i,"aria-expanded":!1}),t.config.i18n[i]),l=s.createElement("span",{class:t.config.classNames.menu.value});l.innerHTML=e[i],a.appendChild(l),n.appendChild(a),f.appendChild(n),t.elements.settings.tabs[i]=n}),g.appendChild(f),m.appendChild(g),this.config.settings.forEach(function(i){var n=s.createElement("div",{id:"plyr-settings-"+e.id+"-"+i,"aria-hidden":!0,"aria-labelled-by":"plyr-settings-"+e.id+"-"+i+"-tab",role:"tabpanel",tabindex:-1,hidden:""}),a=s.createElement("button",{type:"button",class:t.config.classNames.control+" "+t.config.classNames.control+"--back","aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id+"-home","aria-expanded":!1},t.config.i18n[i]);n.appendChild(a);var l=s.createElement("ul");n.appendChild(l),m.appendChild(n),t.elements.settings.panes[i]=n}),p.appendChild(m),d.appendChild(p),i.appendChild(d),this.elements.settings.form=p,this.elements.settings.menu=d}return this.config.controls.includes("pip")&&a.pip&&i.appendChild(h.createButton.call(this,"pip")),this.config.controls.includes("airplay")&&a.airplay&&i.appendChild(h.createButton.call(this,"airplay")),this.config.controls.includes("fullscreen")&&i.appendChild(h.createButton.call(this,"fullscreen")),this.config.controls.includes("play-large")&&this.elements.container.appendChild(h.createButton.call(this,"play-large")),this.elements.controls=i,this.config.controls.includes("settings")&&this.config.settings.includes("speed")&&h.setSpeedMenu.call(this),i},inject:function(){var e=this;if(this.config.loadSprite){var t=h.getIconUrl.call(this);t.absolute&&s.loadSprite(t.url,"sprite-plyr")}this.id=Math.floor(1e4*Math.random());var i=null;i=s.is.string(this.config.controls)?this.config.controls:s.is.function(this.config.controls)?this.config.controls({id:this.id,seektime:this.config.seekTime,title:this.config.title}):h.create.call(this,{id:this.id,seektime:this.config.seekTime,speed:this.speed,quality:this.quality,captions:h.getLanguage.call(this)});var n=void 0;if(s.is.string(this.config.selectors.controls.container)&&(n=document.querySelector(this.config.selectors.controls.container)),s.is.htmlElement(n)||(n=this.elements.container),s.is.htmlElement(i)?n.appendChild(i):n.insertAdjacentHTML("beforeend",i),s.is.htmlElement(this.elements.controls)&&s.findElements.call(this),this.config.tooltips.controls){var a=s.getElements.call(this,[this.config.selectors.controls.wrapper," ",this.config.selectors.labels," .",this.config.classNames.hidden].join(""));Array.from(a).forEach(function(t){s.toggleClass(t,e.config.classNames.hidden,!1),s.toggleClass(t,e.config.classNames.tooltip,!0)})}}},m={setup:function(){var e=this;if(this.supported.ui){if(s.is.empty(r.get.call(this).language)?s.is.empty(this.captions.language)&&(this.captions.language=this.config.captions.language.toLowerCase()):this.captions.language=r.get.call(this).language,s.is.boolean(this.captions.enabled)||(s.is.empty(r.get.call(this).language)?this.captions.enabled=this.config.captions.active:this.captions.enabled=r.get.call(this).captions),!["video","vimeo"].includes(this.type)||"video"===this.type&&!a.textTracks)return this.captions.tracks=null,void(this.config.controls.includes("settings")&&this.config.settings.includes("captions")&&h.setCaptionsMenu.call(this));if(s.is.htmlElement(this.elements.captions)||(this.elements.captions=s.createElement("div",s.getAttributesFromSelector(this.config.selectors.captions)),s.insertAfter(this.elements.captions,this.elements.wrapper)),"video"===this.type&&(this.captions.tracks=this.media.textTracks),s.toggleClass(this.elements.container,this.config.classNames.captions.enabled,!s.is.empty(this.captions.tracks)),!s.is.empty(this.captions.tracks)){m.show.call(this);var t=function(){e.captions.currentTrack=null,Array.from(e.captions.tracks).forEach(function(t){t.language.toLowerCase()===e.language.toLowerCase()&&(e.captions.currentTrack=t,console.warn("Set current track to "+e.language))})};if(t(),!s.is.track(this.captions.currentTrack)){var i=this.config.captions.language;this.captions.language=i,t(),s.is.track(this.captions.currentTrack)||this.toggleCaptions(!1),h.updateSetting.call(this,"captions")}if("video"===this.type){Array.from(this.captions.tracks).forEach(function(t){s.off(t,"cuechange",function(t){return m.setCue.call(e,t)}),t.mode="hidden"});var n=this.captions.currentTrack&&["captions","subtitles"].includes(this.captions.currentTrack.kind);s.is.track(this.captions.currentTrack)&&n&&(s.on(this.captions.currentTrack,"cuechange",function(t){return m.setCue.call(e,t)}),this.captions.currentTrack.activeCues&&this.captions.currentTrack.activeCues.length>0&&m.setCue.call(this,this.captions.currentTrack))}else"vimeo"===this.type&&this.captions.active&&this.embed.enableTextTrack(this.captions.language);this.config.controls.includes("settings")&&this.config.settings.includes("captions")&&h.setCaptionsMenu.call(this)}}},setCue:function(e){var t=(s.is.event(e)?e.target:e).activeCues[0];s.is.cue(t)?m.set.call(this,t.getCueAsHTML()):m.set.call(this),s.dispatchEvent.call(this,this.media,"cuechange")},set:function(e){if(this.supported.ui)if(s.is.htmlElement(this.elements.captions)){var t=s.createElement("span");s.emptyElement(this.elements.captions);var i=s.is.undefined(e)?"":e;s.is.string(i)?t.textContent=i.trim():t.appendChild(i),this.elements.captions.appendChild(t)}else this.console.warn("No captions element to render to")},show:function(){if(s.is.htmlElement(this.elements.buttons.captions)){var e=r.get.call(this).captions;s.is.boolean(e)?this.captions.active=e:e=this.config.captions.active,e&&(s.toggleClass(this.elements.container,this.config.classNames.captions.active,!0),s.toggleState(this.elements.buttons.captions,!0))}}},g={setup:function(){var e=this,t=s.parseYouTubeId(this.embedId),i=s.getElements.call(this,'[id^="'+this.type+'-"]');Array.from(i).forEach(s.removeElement),s.toggleClass(this.elements.wrapper,this.config.classNames.embed,!0),g.setAspectRatio.call(this),this.media.setAttribute("id",s.generateId(this.type));var n=this.config.keys.google;if(s.is.string(n)&&!s.is.empty(n)){var a="https://www.googleapis.com/youtube/v3/videos?id="+t+"&key="+n+"&fields=items(snippet(title))&part=snippet";fetch(a).then(function(e){return e.ok?e.json():null}).then(function(t){null!==t&&s.is.object(t)&&(e.config.title=t.items[0].snippet.title,d.setTitle.call(e))}).catch(function(){})}s.is.object(window.YT)?g.ready.call(this,t):(s.loadScript(this.config.urls.youtube.api),window.onYouTubeReadyCallbacks=window.onYouTubeReadyCallbacks||[],window.onYouTubeReadyCallbacks.push(function(){g.ready.call(e,t)}),window.onYouTubeIframeAPIReady=function(){window.onYouTubeReadyCallbacks.forEach(function(e){e()})})},setAspectRatio:function(){var e=this.config.ratio.split(":");this.elements.wrapper.style.paddingBottom=100/e[0]*e[1]+"%"},ready:function(e){var t=this;t.embed=new window.YT.Player(t.media.id,{videoId:e,playerVars:{autoplay:t.config.autoplay?1:0,controls:t.supported.ui?0:1,rel:0,showinfo:0,iv_load_policy:3,modestbranding:1,disablekb:1,playsinline:1,origin:window&&window.location.hostname,widget_referrer:window&&window.location.href,cc_load_policy:this.captions.active?1:0,cc_lang_pref:this.config.captions.language},events:{onError:function(e){if(!s.is.object(t.media.error)){var i={code:e.data};switch(e.data){case 2:i.message="The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.";break;case 5:i.message="The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.";break;case 100:i.message="The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.";break;case 101:case 150:i.message="The owner of the requested video does not allow it to be played in embedded players.";break;default:i.message="An unknown error occured"}t.media.error=i,s.dispatchEvent.call(t,t.media,"error")}},onPlaybackQualityChange:function(e){var i=e.target;t.media.quality=i.getPlaybackQuality(),s.dispatchEvent.call(t,t.media,"qualitychange")},onPlaybackRateChange:function(e){var i=e.target;t.media.playbackRate=i.getPlaybackRate(),s.dispatchEvent.call(t,t.media,"ratechange")},onReady:function(e){var i=e.target;t.media.play=function(){i.playVideo(),t.media.paused=!1},t.media.pause=function(){i.pauseVideo(),t.media.paused=!0},t.media.stop=function(){i.stopVideo(),t.media.paused=!0},t.media.duration=i.getDuration(),t.media.paused=!0,t.media.currentTime=0,Object.defineProperty(t.media,"currentTime",{get:function(){return Number(i.getCurrentTime())},set:function(e){t.media.seeking=!0,s.dispatchEvent.call(t,t.media,"seeking"),i.seekTo(e)}}),Object.defineProperty(t.media,"playbackRate",{get:function(){return i.getPlaybackRate()},set:function(e){i.setPlaybackRate(e)}}),Object.defineProperty(t.media,"quality",{get:function(){return i.getPlaybackQuality()},set:function(e){s.dispatchEvent.call(t,t.media,"qualityrequested",!1,{quality:e}),i.setPlaybackQuality(e)}});var n=t.config.volume;Object.defineProperty(t.media,"volume",{get:function(){return n},set:function(e){n=e,i.setVolume(100*n),s.dispatchEvent.call(t,t.media,"volumechange")}});var a=t.config.muted;Object.defineProperty(t.media,"muted",{get:function(){return a},set:function(e){var n=s.is.boolean(e)?e:a;a=n,i[n?"mute":"unMute"](),s.dispatchEvent.call(t,t.media,"volumechange")}}),Object.defineProperty(t.media,"currentSrc",{get:function(){return i.getVideoUrl()}}),t.config.controls.includes("settings")&&t.config.settings.includes("speed")&&h.setSpeedMenu.call(t,i.getAvailablePlaybackRates()),s.is.function(i.getVideoData)&&(t.config.title=i.getVideoData().title),t.supported.ui&&t.media.setAttribute("tabindex",-1),s.dispatchEvent.call(t,t.media,"timeupdate"),s.dispatchEvent.call(t,t.media,"durationchange"),window.clearInterval(t.timers.buffering),t.timers.buffering=window.setInterval(function(){t.media.buffered=i.getVideoLoadedFraction(),(null===t.media.lastBuffered||t.media.lastBuffered<t.media.buffered)&&s.dispatchEvent.call(t,t.media,"progress"),t.media.lastBuffered=t.media.buffered,1===t.media.buffered&&(window.clearInterval(t.timers.buffering),s.dispatchEvent.call(t,t.media,"canplaythrough"))},200),window.setTimeout(function(){return d.build.call(t)},50)},onStateChange:function(e){var i=e.target;switch(window.clearInterval(t.timers.playing),e.data){case 0:t.media.loop?(i.stopVideo(),i.playVideo()):(s.dispatchEvent.call(t,t.media,"ended"),t.media.paused=!0);break;case 1:t.media.paused=!1,t.media.seeking&&s.dispatchEvent.call(t,t.media,"seeked"),t.media.seeking=!1,s.dispatchEvent.call(t,t.media,"play"),s.dispatchEvent.call(t,t.media,"playing"),t.timers.playing=window.setInterval(function(){s.dispatchEvent.call(t,t.media,"timeupdate")},50),t.media.duration!==i.getDuration()&&(t.media.duration=i.getDuration(),s.dispatchEvent.call(t,t.media,"durationchange")),h.setQualityMenu.call(t,i.getAvailableQualityLevels());break;case 2:t.media.paused=!0,s.dispatchEvent.call(t,t.media,"pause")}s.dispatchEvent.call(t,t.elements.container,"statechange",!1,{code:e.data})}}})}},f={setup:function(){var e=this,t=s.getElements.call(this,'[id^="'+this.type+'-"]');Array.from(t).forEach(s.removeElement),s.toggleClass(this.elements.wrapper,this.config.classNames.embed,!0),f.setAspectRatio.call(this),this.media.setAttribute("id",s.generateId(this.type)),s.is.object(window.Vimeo)?f.ready.call(this):s.loadScript(this.config.urls.vimeo.api,function(){f.ready.call(e)})},setAspectRatio:function(e){var t=s.is.string(e)?e.split(":"):this.config.ratio.split(":"),i=100/t[0]*t[1],n=(200-i)/4;this.elements.wrapper.style.paddingBottom=i+"%",this.media.style.transform="translateY(-"+n+"%)"},ready:function(){var e=this,t=this,i={loop:t.config.loop.active,autoplay:t.autoplay,byline:!1,portrait:!1,title:!1,speed:!0,transparent:0,gesture:"media"},n=s.buildUrlParameters(i),a=s.parseVimeoId(t.embedId),l=s.createElement("iframe"),o="https://player.vimeo.com/video/"+a+"?"+n;l.setAttribute("src",o),l.setAttribute("allowfullscreen",""),t.media.appendChild(l),t.embed=new window.Vimeo.Player(l),t.media.paused=!0,t.media.currentTime=0,t.media.play=function(){t.embed.play().then(function(){t.media.paused=!1})},t.media.pause=function(){t.embed.pause().then(function(){t.media.paused=!0})},t.media.stop=function(){t.embed.stop().then(function(){t.media.paused=!0,t.currentTime=0})};var r=t.media.currentTime;Object.defineProperty(t.media,"currentTime",{get:function(){return r},set:function(e){var i=t.media.paused;t.media.seeking=!0,s.dispatchEvent.call(t,t.media,"seeking"),t.embed.setCurrentTime(e),i&&t.pause()}});var c=t.config.speed.selected;Object.defineProperty(t.media,"playbackRate",{get:function(){return c},set:function(e){t.embed.setPlaybackRate(e).then(function(){c=e,s.dispatchEvent.call(t,t.media,"ratechange")})}});var u=t.config.volume;Object.defineProperty(t.media,"volume",{get:function(){return u},set:function(e){t.embed.setVolume(e).then(function(){u=e,s.dispatchEvent.call(t,t.media,"volumechange")})}});var p=t.config.muted;Object.defineProperty(t.media,"muted",{get:function(){return p},set:function(e){var i=!!s.is.boolean(e)&&e;t.embed.setVolume(i?0:t.config.volume).then(function(){p=i,s.dispatchEvent.call(t,t.media,"volumechange")})}});var g=t.config.loop;Object.defineProperty(t.media,"loop",{get:function(){return g},set:function(e){var i=s.is.boolean(e)?e:t.config.loop.active;t.embed.setLoop(i).then(function(){g=i})}});var y=void 0;t.embed.getVideoUrl().then(function(e){y=e}),Object.defineProperty(t.media,"currentSrc",{get:function(){return y}}),Promise.all([t.embed.getVideoWidth(),t.embed.getVideoHeight()]).then(function(t){var i=s.getAspectRatio(t[0],t[1]);f.setAspectRatio.call(e,i)}),t.config.controls.includes("settings")&&t.config.settings.includes("speed")&&h.setSpeedMenu.call(t),t.embed.getVideoTitle().then(function(i){t.config.title=i,d.setTitle.call(e)}),t.embed.getCurrentTime().then(function(e){r=e,s.dispatchEvent.call(t,t.media,"timeupdate")}),t.embed.getDuration().then(function(e){t.media.duration=e,s.dispatchEvent.call(t,t.media,"durationchange")}),t.embed.getTextTracks().then(function(e){t.captions.tracks=e,m.setup.call(t)}),t.embed.on("cuechange",function(e){var i=null;e.cues.length&&(i=s.stripHTML(e.cues[0].text)),m.set.call(t,i)}),t.embed.on("loaded",function(){s.is.htmlElement(t.embed.element)&&t.supported.ui&&t.embed.element.setAttribute("tabindex",-1)}),t.embed.on("play",function(){t.media.paused=!1,s.dispatchEvent.call(t,t.media,"play"),s.dispatchEvent.call(t,t.media,"playing")}),t.embed.on("pause",function(){t.media.paused=!0,s.dispatchEvent.call(t,t.media,"pause")}),t.embed.on("timeupdate",function(e){t.media.seeking=!1,r=e.seconds,s.dispatchEvent.call(t,t.media,"timeupdate")}),t.embed.on("progress",function(e){t.media.buffered=e.percent,s.dispatchEvent.call(t,t.media,"progress"),1===parseInt(e.percent,10)&&s.dispatchEvent.call(t,t.media,"canplaythrough")}),t.embed.on("seeked",function(){t.media.seeking=!1,s.dispatchEvent.call(t,t.media,"seeked"),s.dispatchEvent.call(t,t.media,"play")}),t.embed.on("ended",function(){t.media.paused=!0,s.dispatchEvent.call(t,t.media,"ended")}),t.embed.on("error",function(e){t.media.error=e,s.dispatchEvent.call(t,t.media,"error")}),window.setTimeout(function(){return d.build.call(t)},0)}},y=s.getBrowser(),v={setup:function(){if(this.media)if(s.toggleClass(this.elements.container,this.config.classNames.type.replace("{0}",this.type),!0),this.isEmbed&&s.toggleClass(this.elements.container,this.config.classNames.type.replace("{0}","video"),!0),this.supported.ui&&(s.toggleClass(this.elements.container,this.config.classNames.pip.supported,a.pip&&"video"===this.type),s.toggleClass(this.elements.container,this.config.classNames.airplay.supported,a.airplay&&this.isHTML5),s.toggleClass(this.elements.container,this.config.classNames.stopped,this.config.autoplay),s.toggleClass(this.elements.container,this.config.classNames.isIos,y.isIos),s.toggleClass(this.elements.container,this.config.classNames.isTouch,a.touch)),["video","youtube","vimeo"].includes(this.type)&&(this.elements.wrapper=s.createElement("div",{class:this.config.classNames.video}),s.wrap(this.media,this.elements.wrapper)),this.isEmbed)switch(this.type){case"youtube":g.setup.call(this);break;case"vimeo":f.setup.call(this)}else d.setTitle.call(this);else this.console.warn("No media element found!")},cancelRequests:function(){this.isHTML5&&(Array.from(this.media.querySelectorAll("source")).forEach(s.removeElement),this.media.setAttribute("src",this.config.blankVideo),this.media.load(),this.console.log("Cancelled network requests"))}},b={insertElements:function(e,t){var i=this;s.is.string(t)?s.insertElement(e,this.media,{src:t}):s.is.array(t)&&t.forEach(function(t){s.insertElement(e,i.media,t)})},change:function(e){var t=this;s.is.object(e)&&"sources"in e&&e.sources.length?(v.cancelRequests.call(this),this.destroy.call(this,function(){if(s.removeElement(t.media),t.media=null,s.is.htmlElement(t.elements.container)&&t.elements.container.removeAttribute("class"),"type"in e&&(t.type=e.type,"video"===t.type)){var i=e.sources[0];"type"in i&&n.embed.includes(i.type)&&(t.type=i.type)}switch(t.supported=a.check(t.type,t.config.inline),t.type){case"video":t.media=s.createElement("video");break;case"audio":t.media=s.createElement("audio");break;case"youtube":case"vimeo":t.media=s.createElement("div"),t.embedId=e.sources[0].src}t.elements.container.appendChild(t.media),s.is.boolean(e.autoplay)&&(t.config.autoplay=e.autoplay),t.isHTML5&&(t.config.crossorigin&&t.media.setAttribute("crossorigin",""),t.config.autoplay&&t.media.setAttribute("autoplay",""),"poster"in e&&t.media.setAttribute("poster",e.poster),t.config.loop.active&&t.media.setAttribute("loop",""),t.config.muted&&t.media.setAttribute("muted",""),t.config.inline&&t.media.setAttribute("playsinline","")),s.toggleClass(t.elements.container,t.config.classNames.captions.active,t.supported.ui&&t.captions.enabled),d.addStyleHook.call(t),t.isHTML5&&b.insertElements.call(t,"source",e.sources),t.config.title=e.title,v.setup.call(t),t.isHTML5&&("tracks"in e&&b.insertElements.call(t,"track",e.tracks),t.media.load()),(t.isHTML5||t.isEmbed&&!t.supported.ui)&&d.build.call(t)},!0)):this.console.warn("Invalid source format")}},k=(function(){function e(e){this.value=e}function t(t){function i(s,a){try{var l=t[s](a),o=l.value;o instanceof e?Promise.resolve(o.value).then(function(e){i("next",e)},function(e){i("throw",e)}):n(l.done?"return":"normal",l.value)}catch(e){n("throw",e)}}function n(e,t){switch(e){case"return":s.resolve({value:t,done:!0});break;case"throw":s.reject(t);break;default:s.resolve({value:t,done:!1})}(s=s.next)?i(s.key,s.arg):a=null}var s,a;this._invoke=function(e,t){return new Promise(function(n,l){var o={key:e,arg:t,resolve:n,reject:l,next:null};a?a=a.next=o:(s=a=o,i(e,t))})},"function"!=typeof t.return&&(this.return=void 0)}"function"==typeof Symbol&&Symbol.asyncIterator&&(t.prototype[Symbol.asyncIterator]=function(){return this}),t.prototype.next=function(e){return this._invoke("next",e)},t.prototype.throw=function(e){return this._invoke("throw",e)},t.prototype.return=function(e){return this._invoke("return",e)}}(),function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}),w=function(){function e(e,t){for(var i=0;i<t.length;i++){var n=t[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,i,n){return i&&e(t.prototype,i),n&&e(t,n),t}}(),E={x:0,y:0};return function(){function e(t,n){var l=this;if(k(this,e),this.timers={},this.ready=!1,this.media=t,s.is.string(this.media)&&(this.media=document.querySelectorAll(this.media)),(window.jQuery&&this.media instanceof jQuery||s.is.nodeList(this.media)||s.is.array(this.media))&&(this.media=this.media[0]),this.config=s.extend({},i,n,function(){try{return JSON.parse(l.media.getAttribute("data-plyr"))}catch(e){return null}}()),this.elements={container:null,buttons:{},display:{},progress:{},inputs:{},settings:{menu:null,panes:{},tabs:{}},captions:null},this.captions={enabled:null,tracks:null,currentTrack:null},this.fullscreen={active:!1},this.options={speed:[],quality:[]},this.console={log:function(){},warn:function(){},error:function(){}},this.config.debug&&"console"in window&&(this.console={log:console.log,warn:console.warn,error:console.error},this.console.log("Debugging enabled")),this.console.log("Config",this.config),this.console.log("Support",a),null!==this.media&&!s.is.undefined(this.media)&&s.is.htmlElement(this.media))if(this.media.plyr)this.console.warn("Target already setup");else if(this.config.enabled)if(a.check().api){this.elements.original=this.media.cloneNode(!0);var o=this.media.tagName.toLowerCase();switch(o){case"div":if(this.type=this.media.getAttribute("data-type"),this.embedId=this.media.getAttribute("data-video-id"),s.is.empty(this.type))return void this.console.error("Setup failed: embed type missing");if(s.is.empty(this.embedId))return void this.console.error("Setup failed: video id missing");this.media.removeAttribute("data-type"),this.media.removeAttribute("data-video-id");break;case"video":case"audio":this.type=o,this.media.hasAttribute("crossorigin")&&(this.config.crossorigin=!0),this.media.hasAttribute("autoplay")&&(this.config.autoplay=!0),this.media.hasAttribute("playsinline")&&(this.config.inline=!0),this.media.hasAttribute("muted")&&(this.config.muted=!0),this.media.hasAttribute("loop")&&(this.config.loop.active=!0);break;default:return void this.console.error("Setup failed: unsupported type")}r.setup.call(this),this.supported=a.check(this.type,this.config.inline),this.supported.api?(this.media.plyr=this,this.elements.container=s.createElement("div"),s.wrap(this.media,this.elements.container),this.elements.container.setAttribute("tabindex",0),u.global.call(this),d.addStyleHook.call(this),v.setup.call(this),this.config.debug&&s.on(this.elements.container,this.config.events.join(" "),function(e){l.console.log("event: "+e.type)}),(this.isHTML5||this.isEmbed&&!this.supported.ui)&&d.build.call(this)):this.console.error("Setup failed: no support")}else this.console.error("Setup failed: no support");else this.console.error("Setup failed: disabled by config");else this.console.error("Setup failed: no suitable element passed")}return w(e,[{key:"play",value:function(){return"play"in this.media&&this.media.play(),this}},{key:"pause",value:function(){return"pause"in this.media&&this.media.pause(),this}},{key:"togglePlay",value:function(e){return!s.is.boolean(e)&&this.media.paused||e?this.play():this.pause()}},{key:"stop",value:function(){return this.restart().pause()}},{key:"restart",value:function(){return this.currentTime=0,this}},{key:"rewind",value:function(e){return this.currentTime=this.currentTime-(s.is.number(e)?e:this.config.seekTime),this}},{key:"forward",value:function(e){return this.currentTime=this.currentTime+(s.is.number(e)?e:this.config.seekTime),this}},{key:"increaseVolume",value:function(e){var t=this.media.muted?0:this.volume;return this.volume=t+s.is.number(e)?e:1,this}},{key:"decreaseVolume",value:function(e){var t=this.media.muted?0:this.volume;return this.volume=t-s.is.number(e)?e:1,this}},{key:"toggleCaptions",value:function(e){if(!this.supported.ui||!s.is.htmlElement(this.elements.buttons.captions))return this;var t=s.is.boolean(e)?e:-1===this.elements.container.className.indexOf(this.config.classNames.captions.active);return this.captions.enabled===t?this:(this.captions.enabled=t,s.toggleState(this.elements.buttons.captions,this.captions.enabled),s.toggleClass(this.elements.container,this.config.classNames.captions.active,this.captions.enabled),s.dispatchEvent.call(this,this.media,this.captions.enabled?"captionsenabled":"captionsdisabled"),this)}},{key:"toggleFullscreen",value:function(e){if(o.enabled){if(!s.is.event(e)||e.type!==o.eventType)return this.fullscreen.active?o.cancelFullScreen():o.requestFullScreen(this.elements.container),this.fullscreen.active=o.isFullScreen(this.elements.container),this;this.fullscreen.active=o.isFullScreen(this.elements.container)}else this.fullscreen.active=!this.fullscreen.active,s.toggleClass(this.elements.container,this.config.classNames.fullscreen.fallback,this.fullscreen.active),this.fullscreen.active?E={x:window.pageXOffset||0,y:window.pageYOffset||0}:window.scrollTo(E.x,E.y),document.body.style.overflow=this.fullscreen.active?"hidden":"";return this.elements.buttons&&this.elements.buttons.fullscreen&&s.toggleState(this.elements.buttons.fullscreen,this.fullscreen.active),s.dispatchEvent.call(this,this.media,this.fullscreen.active?"enterfullscreen":"exitfullscreen"),this}},{key:"airplay",value:function(){return a.airplay?(this.media.webkitShowPlaybackTargetPicker(),this):this}},{key:"toggleControls",value:function(e){var t=this;if(!s.is.htmlElement(this.elements.controls))return this;if(!this.supported.ui||!this.config.hideControls||"audio"===this.type)return this;var i=0,n=e,l=!1;if(s.is.boolean(e)||(s.is.event(e)?(l="enterfullscreen"===e.type,n=["click","mousemove","touchmove","mouseenter","focusin"].includes(e.type),["mousemove","touchmove"].includes(e.type)&&(i=2e3),"focusin"===e.type&&(i=3e3,s.toggleClass(this.elements.controls,this.config.classNames.noTransition,!0))):n=s.hasClass(this.elements.container,this.config.classNames.hideControls)),window.clearTimeout(this.timers.hover),n||this.media.paused||this.loading){if(s.toggleClass(this.elements.container,this.config.classNames.hideControls,!1)&&s.dispatchEvent.call(this,this.media,"controlsshown"),this.media.paused||this.loading)return this;a.touch&&(i=3e3)}return n&&this.media.paused||(this.timers.hover=window.setTimeout(function(){(!t.elements.controls.pressed&&!t.elements.controls.hover||l)&&(s.hasClass(t.elements.container,t.config.classNames.hideControls)||s.toggleClass(t.elements.controls,t.config.classNames.noTransition,!1),s.toggleClass(t.elements.container,t.config.classNames.hideControls,!0)&&(s.dispatchEvent.call(t,t.media,"controlshidden"),t.config.controls.includes("settings")&&!s.is.empty(t.config.settings)&&h.toggleMenu.call(t,!1)))},i)),this}},{key:"on",value:function(e,t){return s.on(this.elements.container,e,t),this}},{key:"off",value:function(e,t){return s.off(this.elements.container,e,t),this}},{key:"supports",value:function(e){return a.mime.call(this,e)}},{key:"destroy",value:function(e){var t=this,i=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=function(){if(document.body.style.overflow="",t.embed=null,t.embedId=null,i)Object.keys(t.elements).length&&(t.elements.buttons&&t.elements.buttons.play&&Array.from(t.elements.buttons.play).forEach(function(e){return s.removeElement(e)}),s.removeElement(t.elements.captions),s.removeElement(t.elements.controls),s.removeElement(t.elements.wrapper),t.elements.buttons.play=null,t.elements.captions=null,t.elements.controls=null,t.elements.wrapper=null),s.is.function(e)&&e();else{var n=t.elements.container.parentNode;s.is.htmlElement(n)&&n.replaceChild(t.elements.original,t.elements.container),s.dispatchEvent.call(t,t.elements.original,"destroyed",!0),s.is.function(e)&&e.call(t.elements.original),t.elements=null}};switch(this.type){case"youtube":window.clearInterval(this.timers.buffering),window.clearInterval(this.timers.playing),this.embed.destroy(),n();break;case"vimeo":this.embed.unload().then(n),window.setTimeout(n,200);break;case"video":case"audio":d.toggleNativeControls.call(this,!0),n()}}},{key:"isHTML5",get:function(){return n.html5.includes(this.type)}},{key:"isEmbed",get:function(){return n.embed.includes(this.type)}},{key:"paused",get:function(){return this.media.paused}},{key:"currentTime",set:function(e){var t=0;s.is.number(e)&&(t=e),t<0?t=0:t>this.duration&&(t=this.duration),this.media.currentTime=t.toFixed(4),this.console.log("Seeking to "+this.currentTime+" seconds")},get:function(){return Number(this.media.currentTime)}},{key:"seeking",get:function(){return this.media.seeking}},{key:"duration",get:function(){var e=parseInt(this.config.duration,10),t=Number(this.media.duration);return Number.isNaN(e)?t:e}},{key:"volume",set:function(e){var t=e;s.is.string(t)&&(t=Number(t)),s.is.number(t)||(t=r.get.call(this).volume),s.is.number(t)||(t=this.config.volume),t>1&&(t=1),t<0&&(t=0),this.config.volume=t,this.media.volume=t,this.muted&&t>0&&(this.muted=!1)},get:function(){return this.media.volume}},{key:"muted",set:function(e){var t=e;s.is.boolean(t)||(t=r.get.call(this).muted),s.is.boolean(t)||(t=this.config.muted),this.config.muted=t,this.media.muted=t},get:function(){return this.media.muted}},{key:"speed",set:function(e){var t=null;(t=s.is.number(e)?e:s.is.number(r.get.call(this).speed)?r.get.call(this).speed:this.config.speed.selected)<.1&&(t=.1),t>2&&(t=2),this.config.speed.options.includes(t)?(this.config.speed.selected=t,this.media.playbackRate=t):this.console.warn("Unsupported speed ("+t+")")},get:function(){return this.media.playbackRate}},{key:"quality",set:function(e){var t=null;t=s.is.string(e)?e:s.is.number(r.get.call(this).speed)?r.get.call(this).quality:this.config.quality.selected,this.options.quality.includes(t)?(this.config.quality.selected=t,this.media.quality=t):this.console.warn("Unsupported quality option ("+t+")")},get:function(){return this.media.quality}},{key:"loop",set:function(e){var t=s.is.boolean(e)?e:this.config.loop.active;this.config.loop.active=t,this.media.loop=t},get:function(){return this.media.loop}},{key:"source",set:function(e){b.change.call(this,e)},get:function(){return this.media.currentSrc}},{key:"poster",set:function(e){"video"===this.type?s.is.string(e)&&this.media.setAttribute("poster",e):this.console.warn("Poster can only be set on HTML5 video")},get:function(){return"video"!==this.type?null:this.media.getAttribute("poster")}},{key:"autoplay",get:function(){return this.config.autoplay},set:function(e){var t=s.is.boolean(e)?e:this.config.autoplay;this.config.autoplay=t}},{key:"language",set:function(e){if(s.is.string(e)){var t=e.toLowerCase();this.language!==t&&(this.toggleCaptions(!0),this.captions.language=t,s.dispatchEvent.call(this,this.media,"languagechange"),m.set.call(this),m.setup.call(this))}},get:function(){return this.captions.language}},{key:"pip",set:function(e){var t={pip:"picture-in-picture",inline:"inline"};if(a.pip){var i=s.is.boolean(e)?e:this.pip===t.inline;this.media.webkitSetPresentationMode(i?t.pip:t.inline)}},get:function(){return a.pip?this.media.webkitPresentationMode:null}}]),e}()}); //# sourceMappingURL=plyr.js.map diff --git a/dist/plyr.js.map b/dist/plyr.js.map index 327d4c87..ddf6564c 100644 --- a/dist/plyr.js.map +++ b/dist/plyr.js.map @@ -1 +1 @@ -{"version":3,"file":"plyr.js","sources":["src/js/storage.js","src/js/defaults.js","src/js/types.js","src/js/utils.js","src/js/support.js","src/js/fullscreen.js","src/js/listeners.js","src/js/ui.js","src/js/controls.js","src/js/captions.js","src/js/plugins/youtube.js","src/js/plugins/vimeo.js","src/js/media.js","src/js/source.js","src/js/plyr.js"],"sourcesContent":["// ==========================================================================\n// Plyr storage\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\n\n// Get contents of local storage\nfunction get() {\n const store = window.localStorage.getItem(this.config.storage.key);\n\n if (utils.is.empty(store)) {\n return {};\n }\n\n return JSON.parse(store);\n}\n\n// Save a value back to local storage\nfunction set(object) {\n // Bail if we don't have localStorage support or it's disabled\n if (!support.storage || !this.config.storage.enabled) {\n return;\n }\n\n // Can only store objectst\n if (!utils.is.object(object)) {\n return;\n }\n\n // Get current storage\n const storage = get.call(this);\n\n // Update the working copy of the values\n utils.extend(storage, object);\n\n // Update storage\n window.localStorage.setItem(this.config.storage.key, JSON.stringify(storage));\n}\n\n// Setup localStorage\nfunction setup() {\n let value = null;\n let storage = {};\n\n // Bail if we don't have localStorage support or it's disabled\n if (!support.storage || !this.config.storage.enabled) {\n return storage;\n }\n\n // Clean up old volume\n // https://github.com/sampotts/plyr/issues/171\n window.localStorage.removeItem('plyr-volume');\n\n // load value from the current key\n value = window.localStorage.getItem(this.config.storage.key);\n\n if (!value) {\n // Key wasn't set (or had been cleared), move along\n } else if (/^\\d+(\\.\\d+)?$/.test(value)) {\n // If value is a number, it's probably volume from an older\n // version of this. See: https://github.com/sampotts/plyr/pull/313\n // Update the key to be JSON\n set({\n volume: parseFloat(value),\n });\n } else {\n // Assume it's JSON from this or a later version of plyr\n storage = JSON.parse(value);\n }\n\n return storage;\n}\n\nexport default { setup, set, get };\n","// Default config\nconst defaults = {\n // Disable\n enabled: true,\n\n // Custom media title\n title: '',\n\n // Logging to console\n debug: false,\n\n // Auto play (if supported)\n autoplay: false,\n\n // Default time to skip when rewind/fast forward\n seekTime: 10,\n\n // Default volume\n volume: 1,\n muted: false,\n\n // Pass a custom duration\n duration: null,\n\n // Display the media duration\n displayDuration: true,\n\n // Aspect ratio (for embeds)\n ratio: '16:9',\n\n // Click video to play\n clickToPlay: true,\n\n // Auto hide the controls\n hideControls: true,\n\n // Revert to poster on finish (HTML5 - will cause reload)\n showPosterOnEnd: false,\n\n // Disable the standard context menu\n disableContextMenu: true,\n\n // Sprite (for icons)\n loadSprite: true,\n iconPrefix: 'plyr',\n iconUrl: 'https://cdn.plyr.io/2.0.10/plyr.svg',\n\n // Blank video (used to prevent errors on source change)\n blankVideo: 'https://cdn.plyr.io/static/blank.mp4',\n\n // Quality default\n quality: {\n default: 'default',\n options: ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny', 'default'],\n },\n\n // Set loops\n loop: {\n active: false,\n // start: null,\n // end: null,\n },\n\n // Speed default and options to display\n speed: {\n selected: 1,\n options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2],\n },\n\n // Keyboard shortcut settings\n keyboard: {\n focused: true,\n global: false,\n },\n\n // Display tooltips\n tooltips: {\n controls: false,\n seek: true,\n },\n\n // Captions settings\n captions: {\n active: false,\n language: window.navigator.language.split('-')[0],\n },\n\n // Fullscreen settings\n fullscreen: {\n enabled: true, // Allow fullscreen?\n fallback: true, // Fallback for vintage browsers\n },\n\n // Local storage\n storage: {\n enabled: true,\n key: 'plyr',\n },\n\n // Default controls\n controls: [\n 'play-large',\n 'play',\n 'progress',\n 'current-time',\n 'mute',\n 'volume',\n 'captions',\n 'settings',\n 'pip',\n 'airplay',\n 'fullscreen',\n ],\n settings: ['captions', 'quality', 'speed', 'loop'],\n\n // Localisation\n i18n: {\n restart: 'Restart',\n rewind: 'Rewind {seektime} secs',\n play: 'Play',\n pause: 'Pause',\n forward: 'Forward {seektime} secs',\n seek: 'Seek',\n played: 'Played',\n buffered: 'Buffered',\n currentTime: 'Current time',\n duration: 'Duration',\n volume: 'Volume',\n toggleMute: 'Toggle Mute',\n toggleCaptions: 'Toggle Captions',\n toggleFullscreen: 'Toggle Fullscreen',\n frameTitle: 'Player for {title}',\n captions: 'Captions',\n settings: 'Settings',\n speed: 'Speed',\n quality: 'Quality',\n loop: 'Loop',\n start: 'Start',\n end: 'End',\n all: 'All',\n reset: 'Reset',\n none: 'None',\n disabled: 'Disabled',\n },\n\n // URLs\n urls: {\n vimeo: {\n api: 'https://player.vimeo.com/api/player.js',\n },\n youtube: {\n api: 'https://www.youtube.com/iframe_api',\n },\n },\n\n // Custom control listeners\n listeners: {\n seek: null,\n play: null,\n pause: null,\n restart: null,\n rewind: null,\n forward: null,\n mute: null,\n volume: null,\n captions: null,\n fullscreen: null,\n pip: null,\n airplay: null,\n speed: null,\n quality: null,\n loop: null,\n language: null,\n },\n\n // Events to watch and bubble\n events: [\n // Events to watch on HTML5 media elements and bubble\n // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events\n 'ended',\n 'progress',\n 'stalled',\n 'playing',\n 'waiting',\n 'canplay',\n 'canplaythrough',\n 'loadstart',\n 'loadeddata',\n 'loadedmetadata',\n 'timeupdate',\n 'volumechange',\n 'play',\n 'pause',\n 'error',\n 'seeking',\n 'seeked',\n 'emptied',\n 'ratechange',\n 'cuechange',\n\n // Custom events\n 'enterfullscreen',\n 'exitfullscreen',\n 'captionsenabled',\n 'captionsdisabled',\n 'languagechange',\n 'controlshidden',\n 'controlsshown',\n 'ready',\n\n // YouTube\n 'statechange',\n 'qualitychange',\n 'qualityrequested',\n ],\n\n // Selectors\n // Change these to match your template if using custom HTML\n selectors: {\n editable: 'input, textarea, select, [contenteditable]',\n container: '.plyr',\n controls: {\n container: null,\n wrapper: '.plyr__controls',\n },\n labels: '[data-plyr]',\n buttons: {\n play: '[data-plyr=\"play\"]',\n pause: '[data-plyr=\"pause\"]',\n restart: '[data-plyr=\"restart\"]',\n rewind: '[data-plyr=\"rewind\"]',\n forward: '[data-plyr=\"fast-forward\"]',\n mute: '[data-plyr=\"mute\"]',\n captions: '[data-plyr=\"captions\"]',\n fullscreen: '[data-plyr=\"fullscreen\"]',\n pip: '[data-plyr=\"pip\"]',\n airplay: '[data-plyr=\"airplay\"]',\n settings: '[data-plyr=\"settings\"]',\n loop: '[data-plyr=\"loop\"]',\n },\n inputs: {\n seek: '[data-plyr=\"seek\"]',\n volume: '[data-plyr=\"volume\"]',\n speed: '[data-plyr=\"speed\"]',\n language: '[data-plyr=\"language\"]',\n quality: '[data-plyr=\"quality\"]',\n },\n display: {\n currentTime: '.plyr__time--current',\n duration: '.plyr__time--duration',\n buffer: '.plyr__progress--buffer',\n played: '.plyr__progress--played',\n loop: '.plyr__progress--loop',\n volume: '.plyr__volume--display',\n },\n progress: '.plyr__progress',\n captions: '.plyr__captions',\n menu: {\n quality: '.js-plyr__menu__list--quality',\n },\n },\n\n // Class hooks added to the player in different states\n classNames: {\n video: 'plyr__video-wrapper',\n embed: 'plyr__video-embed',\n control: 'plyr__control',\n type: 'plyr--{0}',\n stopped: 'plyr--stopped',\n playing: 'plyr--playing',\n loading: 'plyr--loading',\n hover: 'plyr--hover',\n tooltip: 'plyr__tooltip',\n hidden: 'plyr__sr-only',\n hideControls: 'plyr--hide-controls',\n isIos: 'plyr--is-ios',\n isTouch: 'plyr--is-touch',\n uiSupported: 'plyr--full-ui',\n menu: {\n value: 'plyr__menu__value',\n badge: 'plyr__badge',\n },\n captions: {\n enabled: 'plyr--captions-enabled',\n active: 'plyr--captions-active',\n },\n fullscreen: {\n enabled: 'plyr--fullscreen-enabled',\n fallback: 'plyr--fullscreen-fallback',\n },\n pip: {\n supported: 'plyr--pip-supported',\n active: 'plyr--pip-active',\n },\n airplay: {\n supported: 'plyr--airplay-supported',\n active: 'plyr--airplay-active',\n },\n tabFocus: 'plyr__tab-focus',\n },\n};\n\nexport default defaults;\n","// ==========================================================================\n// Plyr supported types\n// ==========================================================================\n\nconst types = {\n embed: ['youtube', 'vimeo'],\n html5: ['video', 'audio'],\n};\n\nexport default types;\n","// ==========================================================================\n// Plyr utils\n// ==========================================================================\n\nimport support from './support';\n\nconst utils = {\n // Check variable types\n is: {\n object(input) {\n return this.getConstructor(input) === Object;\n },\n number(input) {\n return this.getConstructor(input) === Number && !Number.isNaN(input);\n },\n string(input) {\n return this.getConstructor(input) === String;\n },\n boolean(input) {\n return this.getConstructor(input) === Boolean;\n },\n function(input) {\n return this.getConstructor(input) === Function;\n },\n array(input) {\n return !this.undefined(input) && Array.isArray(input);\n },\n nodeList(input) {\n return !this.undefined(input) && input instanceof NodeList;\n },\n htmlElement(input) {\n return !this.undefined(input) && input instanceof HTMLElement;\n },\n event(input) {\n return !this.undefined(input) && input instanceof Event;\n },\n cue(input) {\n return this.instanceOf(input, window.TextTrackCue) || this.instanceOf(input, window.VTTCue);\n },\n track(input) {\n return (\n !this.undefined(input) && (this.instanceOf(input, window.TextTrack) || typeof input.kind === 'string')\n );\n },\n undefined(input) {\n return input !== null && typeof input === 'undefined';\n },\n empty(input) {\n return (\n input === null ||\n typeof input === 'undefined' ||\n ((this.string(input) || this.array(input) || this.nodeList(input)) && input.length === 0) ||\n (this.object(input) && Object.keys(input).length === 0)\n );\n },\n getConstructor(input) {\n if (input === null || typeof input === 'undefined') {\n return null;\n }\n\n return input.constructor;\n },\n instanceOf(input, constructor) {\n return Boolean(input && constructor && input instanceof constructor);\n },\n },\n\n // Unfortunately, due to mixed support, UA sniffing is required\n getBrowser() {\n return {\n isIE: /* @cc_on!@ */ false || !!document.documentMode,\n isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent),\n isIPhone: /(iPhone|iPod)/gi.test(navigator.platform),\n isIos: /(iPad|iPhone|iPod)/gi.test(navigator.platform),\n };\n },\n\n // Load an external script\n loadScript(url, callback) {\n // Check script is not already referenced\n if (document.querySelectorAll(`script[src=\"${url}\"]`).length) {\n return;\n }\n\n // Build the element\n const element = document.createElement('script');\n element.src = url;\n\n // Find first script\n const first = document.getElementsByTagName('script')[0];\n\n // Bind callback\n if (utils.is.function(callback)) {\n element.addEventListener('load', event => callback.call(null, event), false);\n }\n\n // Inject\n first.parentNode.insertBefore(element, first);\n },\n\n // Load an external SVG sprite\n loadSprite(url, id) {\n if (!utils.is.string(url)) {\n return;\n }\n\n const prefix = 'cache-';\n const hasId = utils.is.string(id);\n let isCached = false;\n\n function updateSprite(data) {\n // Inject content\n this.innerHTML = data;\n\n // Inject the SVG to the body\n document.body.insertBefore(this, document.body.childNodes[0]);\n }\n\n // Only load once\n if (!hasId || !document.querySelectorAll(`#${id}`).length) {\n // Create container\n const container = document.createElement('div');\n container.setAttribute('hidden', '');\n\n if (hasId) {\n container.setAttribute('id', id);\n }\n\n // Check in cache\n if (support.storage) {\n const cached = window.localStorage.getItem(prefix + id);\n isCached = cached !== null;\n\n if (isCached) {\n const data = JSON.parse(cached);\n updateSprite.call(container, data.content);\n return;\n }\n }\n\n // Get the sprite\n fetch(url)\n .then(response => response.text())\n .then(text => {\n if (support.storage) {\n window.localStorage.setItem(\n prefix + id,\n JSON.stringify({\n content: text,\n })\n );\n }\n\n updateSprite.call(container, text);\n });\n }\n },\n\n // Generate a random ID\n generateId(prefix) {\n return `${prefix}-${Math.floor(Math.random() * 10000)}`;\n },\n\n // Determine if we're in an iframe\n inFrame() {\n try {\n return window.self !== window.top;\n } catch (e) {\n return true;\n }\n },\n\n // Wrap an element\n wrap(elements, wrapper) {\n // Convert `elements` to an array, if necessary.\n const targets = elements.length ? elements : [elements];\n\n // Loops backwards to prevent having to clone the wrapper on the\n // first element (see `child` below).\n Array.from(targets)\n .reverse()\n .forEach((element, index) => {\n const child = index > 0 ? wrapper.cloneNode(true) : wrapper;\n\n // Cache the current parent and sibling.\n const parent = element.parentNode;\n const sibling = element.nextSibling;\n\n // Wrap the element (is automatically removed from its current\n // parent).\n child.appendChild(element);\n\n // If the element had a sibling, insert the wrapper before\n // the sibling to maintain the HTML structure; otherwise, just\n // append it to the parent.\n if (sibling) {\n parent.insertBefore(child, sibling);\n } else {\n parent.appendChild(child);\n }\n });\n },\n\n // Remove an element\n removeElement(element) {\n if (!utils.is.htmlElement(element) || !utils.is.htmlElement(element.parentNode)) {\n return null;\n }\n\n element.parentNode.removeChild(element);\n\n return element;\n },\n\n // Inaert an element after another\n insertAfter(element, target) {\n target.parentNode.insertBefore(element, target.nextSibling);\n },\n\n // Create a DocumentFragment\n createElement(type, attributes, text) {\n // Create a new <element>\n const element = document.createElement(type);\n\n // Set all passed attributes\n if (utils.is.object(attributes)) {\n utils.setAttributes(element, attributes);\n }\n\n // Add text node\n if (utils.is.string(text)) {\n element.textContent = text;\n }\n\n // Return built element\n return element;\n },\n\n // Insert a DocumentFragment\n insertElement(type, parent, attributes, text) {\n // Inject the new <element>\n parent.appendChild(utils.createElement(type, attributes, text));\n },\n\n // Remove all child elements\n emptyElement(element) {\n let { length } = element.childNodes;\n\n while (length > 0) {\n element.removeChild(element.lastChild);\n length -= 1;\n }\n },\n\n // Set attributes\n setAttributes(element, attributes) {\n Object.keys(attributes).forEach(key => {\n element.setAttribute(key, attributes[key]);\n });\n },\n\n // Get an attribute object from a string selector\n getAttributesFromSelector(sel, existingAttributes) {\n // For example:\n // '.test' to { class: 'test' }\n // '#test' to { id: 'test' }\n // '[data-test=\"test\"]' to { 'data-test': 'test' }\n\n if (!utils.is.string(sel) || utils.is.empty(sel)) {\n return {};\n }\n\n const attributes = {};\n const existing = existingAttributes;\n\n sel.split(',').forEach(s => {\n // Remove whitespace\n const selector = s.trim();\n const className = selector.replace('.', '');\n const stripped = selector.replace(/[[\\]]/g, '');\n\n // Get the parts and value\n const parts = stripped.split('=');\n const key = parts[0];\n const value = parts.length > 1 ? parts[1].replace(/[\"']/g, '') : '';\n\n // Get the first character\n const start = selector.charAt(0);\n\n switch (start) {\n case '.':\n // Add to existing classname\n if (utils.is.object(existing) && utils.is.string(existing.class)) {\n existing.class += ` ${className}`;\n }\n\n attributes.class = className;\n break;\n\n case '#':\n // ID selector\n attributes.id = selector.replace('#', '');\n break;\n\n case '[':\n // Attribute selector\n attributes[key] = value;\n\n break;\n\n default:\n break;\n }\n });\n\n return attributes;\n },\n\n // Toggle class on an element\n toggleClass(element, className, toggle) {\n if (utils.is.htmlElement(element)) {\n const contains = element.classList.contains(className);\n\n element.classList[toggle ? 'add' : 'remove'](className);\n\n return (toggle && !contains) || (!toggle && contains);\n }\n\n return null;\n },\n\n // Has class name\n hasClass(element, className) {\n return utils.is.htmlElement(element) && element.classList.contains(className);\n },\n\n // Element matches selector\n matches(element, selector) {\n const prototype = { Element };\n\n function match() {\n return Array.from(document.querySelectorAll(selector)).includes(this);\n }\n\n const matches =\n prototype.matches ||\n prototype.webkitMatchesSelector ||\n prototype.mozMatchesSelector ||\n prototype.msMatchesSelector ||\n match;\n\n return matches.call(element, selector);\n },\n\n // Find all elements\n getElements(selector) {\n return this.elements.container.querySelectorAll(selector);\n },\n\n // Find a single element\n getElement(selector) {\n return this.elements.container.querySelector(selector);\n },\n\n // Find the UI controls and store references in custom controls\n // TODO: Allow settings menus with custom controls\n findElements() {\n try {\n this.elements.controls = utils.getElement.call(this, this.config.selectors.controls.wrapper);\n\n // Buttons\n this.elements.buttons = {\n play: utils.getElements.call(this, this.config.selectors.buttons.play),\n pause: utils.getElement.call(this, this.config.selectors.buttons.pause),\n restart: utils.getElement.call(this, this.config.selectors.buttons.restart),\n rewind: utils.getElement.call(this, this.config.selectors.buttons.rewind),\n forward: utils.getElement.call(this, this.config.selectors.buttons.forward),\n mute: utils.getElement.call(this, this.config.selectors.buttons.mute),\n pip: utils.getElement.call(this, this.config.selectors.buttons.pip),\n airplay: utils.getElement.call(this, this.config.selectors.buttons.airplay),\n settings: utils.getElement.call(this, this.config.selectors.buttons.settings),\n captions: utils.getElement.call(this, this.config.selectors.buttons.captions),\n fullscreen: utils.getElement.call(this, this.config.selectors.buttons.fullscreen),\n };\n\n // Progress\n this.elements.progress = utils.getElement.call(this, this.config.selectors.progress);\n\n // Inputs\n this.elements.inputs = {\n seek: utils.getElement.call(this, this.config.selectors.inputs.seek),\n volume: utils.getElement.call(this, this.config.selectors.inputs.volume),\n };\n\n // Display\n this.elements.display = {\n buffer: utils.getElement.call(this, this.config.selectors.display.buffer),\n duration: utils.getElement.call(this, this.config.selectors.display.duration),\n currentTime: utils.getElement.call(this, this.config.selectors.display.currentTime),\n };\n\n // Seek tooltip\n if (utils.is.htmlElement(this.elements.progress)) {\n this.elements.display.seekTooltip = this.elements.progress.querySelector(\n `.${this.config.classNames.tooltip}`\n );\n }\n\n return true;\n } catch (error) {\n // Log it\n this.console.warn('It looks like there is a problem with your custom controls HTML', error);\n\n // Restore native video controls\n this.toggleNativeControls(true);\n\n return false;\n }\n },\n\n // Get the focused element\n getFocusElement() {\n let focused = document.activeElement;\n\n if (!focused || focused === document.body) {\n focused = null;\n } else {\n focused = document.querySelector(':focus');\n }\n\n return focused;\n },\n\n // Trap focus inside container\n trapFocus() {\n const tabbables = utils.getElements.call(this, 'button:not(:disabled), input:not(:disabled), [tabindex]');\n const first = tabbables[0];\n const last = tabbables[tabbables.length - 1];\n\n utils.on(\n this.elements.container,\n 'keydown',\n event => {\n // Bail if not tab key or not fullscreen\n if (event.key !== 'Tab' || event.keyCode !== 9 || !this.fullscreen.active) {\n return;\n }\n\n // Get the current focused element\n const focused = utils.getFocusElement();\n\n if (focused === last && !event.shiftKey) {\n // Move focus to first element that can be tabbed if Shift isn't used\n first.focus();\n event.preventDefault();\n } else if (focused === first && event.shiftKey) {\n // Move focus to last element that can be tabbed if Shift is used\n last.focus();\n event.preventDefault();\n }\n },\n false\n );\n },\n\n // Toggle event listener\n toggleListener(elements, event, callback, toggle, passive, capture) {\n // Bail if no elements\n if (elements === null || utils.is.undefined(elements)) {\n return;\n }\n\n // If a nodelist is passed, call itself on each node\n if (utils.is.nodeList(elements)) {\n // Create listener for each node\n Array.from(elements).forEach(element => {\n if (element instanceof Node) {\n utils.toggleListener.call(null, element, event, callback, toggle, passive, capture);\n }\n });\n\n return;\n }\n\n // Allow multiple events\n const events = event.split(' ');\n\n // Build options\n // Default to just capture boolean\n let options = utils.is.boolean(capture) ? capture : false;\n\n // If passive events listeners are supported\n if (support.passiveListeners) {\n options = {\n // Whether the listener can be passive (i.e. default never prevented)\n passive: utils.is.boolean(passive) ? passive : true,\n // Whether the listener is a capturing listener or not\n capture: utils.is.boolean(capture) ? capture : false,\n };\n }\n\n // If a single node is passed, bind the event listener\n events.forEach(type => {\n elements[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options);\n });\n },\n\n // Bind event handler\n on(element, events, callback, passive, capture) {\n utils.toggleListener(element, events, callback, true, passive, capture);\n },\n\n // Unbind event handler\n off(element, events, callback, passive, capture) {\n utils.toggleListener(element, events, callback, false, passive, capture);\n },\n\n // Trigger event\n dispatchEvent(element, type, bubbles, detail) {\n // Bail if no element\n if (!element || !type) {\n return;\n }\n\n // Create and dispatch the event\n const event = new CustomEvent(type, {\n bubbles: utils.is.boolean(bubbles) ? bubbles : false,\n detail: Object.assign({}, detail, {\n plyr: this instanceof Plyr ? this : null,\n }),\n });\n\n // Dispatch the event\n element.dispatchEvent(event);\n },\n\n // Toggle aria-pressed state on a toggle button\n // http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles\n toggleState(element, input) {\n // Bail if no target\n if (!utils.is.htmlElement(element)) {\n return;\n }\n\n // Get state\n const state = utils.is.boolean(input) ? input : !element.getAttribute('aria-pressed');\n\n // Set the attribute on target\n element.setAttribute('aria-pressed', state);\n },\n\n // Get percentage\n getPercentage(current, max) {\n if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) {\n return 0;\n }\n return (current / max * 100).toFixed(2);\n },\n\n // Deep extend/merge destination object with N more objects\n // http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/\n // Removed call to arguments.callee (used explicit function name instead)\n extend(...objects) {\n const { length } = objects;\n\n // Bail if nothing to merge\n if (!length) {\n return null;\n }\n\n // Return first if specified but nothing to merge\n if (length === 1) {\n return objects[0];\n }\n\n // First object is the destination\n let destination = Array.prototype.shift.call(objects);\n if (!utils.is.object(destination)) {\n destination = {};\n }\n\n // Loop through all objects to merge\n objects.forEach(source => {\n if (!utils.is.object(source)) {\n return;\n }\n\n Object.keys(source).forEach(property => {\n if (source[property] && source[property].constructor && source[property].constructor === Object) {\n destination[property] = destination[property] || {};\n utils.extend(destination[property], source[property]);\n } else {\n destination[property] = source[property];\n }\n });\n });\n\n return destination;\n },\n\n // Parse YouTube ID from URL\n parseYouTubeId(url) {\n const regex = /^.*(youtu.be\\/|v\\/|u\\/\\w\\/|embed\\/|watch\\?v=|&v=)([^#&?]*).*/;\n return url.match(regex) ? RegExp.$2 : url;\n },\n\n // Parse Vimeo ID from URL\n parseVimeoId(url) {\n if (utils.is.number(Number(url))) {\n return url;\n }\n\n const regex = /^.*(vimeo.com\\/|video\\/)(\\d+).*/;\n return url.match(regex) ? RegExp.$2 : url;\n },\n\n // Convert object to URL parameters\n buildUrlParameters(input) {\n if (!utils.is.object(input)) {\n return '';\n }\n\n return Object.keys(input)\n .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(input[key])}`)\n .join('&');\n },\n\n // Remove HTML from a string\n stripHTML(source) {\n const fragment = document.createDocumentFragment();\n const element = document.createElement('div');\n fragment.appendChild(element);\n element.innerHTML = source;\n return fragment.firstChild.innerText;\n },\n\n // Get aspect ratio for dimensions\n getAspectRatio(width, height) {\n const getRatio = (w, h) => (h === 0 ? w : getRatio(h, w % h));\n const ratio = getRatio(width, height);\n return `${width / ratio}:${height / ratio}`;\n },\n\n // Get the transition end event\n transitionEnd: (() => {\n const element = document.createElement('span');\n\n const events = {\n WebkitTransition: 'webkitTransitionEnd',\n MozTransition: 'transitionend',\n OTransition: 'oTransitionEnd otransitionend',\n transition: 'transitionend',\n };\n\n const type = Object.keys(events).find(event => element.style[event] !== undefined);\n\n return typeof type === 'string' ? type : false;\n })(),\n};\n\nexport default utils;\n","// ==========================================================================\n// Plyr support checks\n// ==========================================================================\n\nimport utils from './utils';\n\n// Check for feature support\nconst support = {\n // Basic support\n audio: 'canPlayType' in document.createElement('audio'),\n video: 'canPlayType' in document.createElement('video'),\n\n // Check for support\n // Basic functionality vs full UI\n check(type, inline) {\n let api = false;\n let ui = false;\n const browser = utils.getBrowser();\n const playsInline = browser.isIPhone && inline && support.inline;\n\n switch (type) {\n case 'video':\n api = support.video;\n ui = api && support.rangeInput && (!browser.isIPhone || playsInline);\n break;\n\n case 'audio':\n api = support.audio;\n ui = api && support.rangeInput;\n break;\n\n case 'youtube':\n api = true;\n ui = support.rangeInput && (!browser.isIPhone || playsInline);\n break;\n\n case 'vimeo':\n api = true;\n ui = support.rangeInput && !browser.isIPhone;\n break;\n\n default:\n api = support.audio && support.video;\n ui = api && support.rangeInput;\n }\n\n return {\n api,\n ui,\n };\n },\n\n // Local storage\n // We can't assume if local storage is present that we can use it\n storage: (() => {\n if (!('localStorage' in window)) {\n return false;\n }\n\n // Try to use it (it might be disabled, e.g. user is in private/porn mode)\n // see: https://github.com/sampotts/plyr/issues/131\n const test = '___test';\n try {\n window.localStorage.setItem(test, test);\n window.localStorage.removeItem(test);\n return true;\n } catch (e) {\n return false;\n }\n })(),\n\n // Picture-in-picture support\n // Safari only currently\n pip: (() => {\n const browser = utils.getBrowser();\n return !browser.isIPhone && utils.is.function(utils.createElement('video').webkitSetPresentationMode);\n })(),\n\n // Airplay support\n // Safari only currently\n airplay: utils.is.function(window.WebKitPlaybackTargetAvailabilityEvent),\n\n // Inline playback support\n // https://webkit.org/blog/6784/new-video-policies-for-ios/\n inline: 'playsInline' in document.createElement('video'),\n\n // Check for mime type support against a player instance\n // Credits: http://diveintohtml5.info/everything.html\n // Related: http://www.leanbackplayer.com/test/h5mt.html\n mime(type) {\n const { media } = this;\n\n try {\n // Bail if no checking function\n if (!utils.is.function(media.canPlayType)) {\n return false;\n }\n\n // Type specific checks\n if (this.type === 'video') {\n switch (type) {\n case 'video/webm':\n return media.canPlayType('video/webm; codecs=\"vp8, vorbis\"').replace(/no/, '');\n\n case 'video/mp4':\n return media.canPlayType('video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"').replace(/no/, '');\n\n case 'video/ogg':\n return media.canPlayType('video/ogg; codecs=\"theora\"').replace(/no/, '');\n\n default:\n return false;\n }\n } else if (this.type === 'audio') {\n switch (type) {\n case 'audio/mpeg':\n return media.canPlayType('audio/mpeg;').replace(/no/, '');\n\n case 'audio/ogg':\n return media.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/no/, '');\n\n case 'audio/wav':\n return media.canPlayType('audio/wav; codecs=\"1\"').replace(/no/, '');\n\n default:\n return false;\n }\n }\n } catch (e) {\n return false;\n }\n\n // If we got this far, we're stuffed\n return false;\n },\n\n // Check for textTracks support\n textTracks: 'textTracks' in document.createElement('video'),\n\n // Check for passive event listener support\n // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n // https://www.youtube.com/watch?v=NPM6172J22g\n passiveListeners: (() => {\n // Test via a getter in the options object to see if the passive property is accessed\n let supported = false;\n try {\n const options = Object.defineProperty({}, 'passive', {\n get() {\n supported = true;\n return null;\n },\n });\n window.addEventListener('test', null, options);\n } catch (e) {\n // Do nothing\n }\n\n return supported;\n })(),\n\n // <input type=\"range\"> Sliders\n rangeInput: (() => {\n const range = document.createElement('input');\n range.type = 'range';\n return range.type === 'range';\n })(),\n\n // Touch\n // Remember a device can be moust + touch enabled\n touch: 'ontouchstart' in document.documentElement,\n\n // Detect transitions support\n transitions: utils.transitionEnd !== false,\n\n // Reduced motion iOS & MacOS setting\n // https://webkit.org/blog/7551/responsive-design-for-motion/\n reducedMotion: 'matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches,\n};\n\nexport default support;\n","// ==========================================================================\n// Plyr fullscreen API\n// ==========================================================================\n\nimport utils from './utils';\n\n// Determine the prefix\nconst prefix = (() => {\n let value = false;\n\n if (utils.is.function(document.cancelFullScreen)) {\n value = '';\n } else {\n // Check for fullscreen support by vendor prefix\n ['webkit', 'o', 'moz', 'ms', 'khtml'].some(pre => {\n if (utils.is.function(document[`${pre}CancelFullScreen`])) {\n value = pre;\n return true;\n } else if (utils.is.function(document.msExitFullscreen) && document.msFullscreenEnabled) {\n // Special case for MS (when isn't it?)\n value = 'ms';\n return true;\n }\n\n return false;\n });\n }\n\n return value;\n})();\n\n// Fullscreen API\nconst fullscreen = {\n // Get the prefix\n prefix,\n\n // Check if we can use it\n enabled:\n document.fullscreenEnabled ||\n document.webkitFullscreenEnabled ||\n document.mozFullScreenEnabled ||\n document.msFullscreenEnabled,\n\n // Yet again Microsoft awesomeness,\n // Sometimes the prefix is 'ms', sometimes 'MS' to keep you on your toes\n eventType: prefix === 'ms' ? 'MSFullscreenChange' : `${prefix}fullscreenchange`,\n\n // Is an element fullscreen\n isFullScreen(element) {\n if (!fullscreen.enabled) {\n return false;\n }\n\n const target = utils.is.undefined(element) ? document.body : element;\n\n switch (prefix) {\n case '':\n return document.fullscreenElement === target;\n\n case 'moz':\n return document.mozFullScreenElement === target;\n\n default:\n return document[`${prefix}FullscreenElement`] === target;\n }\n },\n\n // Make an element fullscreen\n requestFullScreen(element) {\n if (!fullscreen.enabled) {\n return false;\n }\n\n const target = utils.is.undefined(element) ? document.body : element;\n\n return !prefix.length\n ? target.requestFullScreen()\n : target[prefix + (prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')]();\n },\n\n // Bail from fullscreen\n cancelFullScreen() {\n if (!fullscreen.enabled) {\n return false;\n }\n\n return !prefix.length\n ? document.cancelFullScreen()\n : document[prefix + (prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen')]();\n },\n\n // Get the current element\n element() {\n if (!fullscreen.enabled) {\n return null;\n }\n\n return !prefix.length ? document.fullscreenElement : document[`${prefix}FullscreenElement`];\n },\n\n // Setup fullscreen\n setup() {\n if (!this.supported.ui || this.type === 'audio' || !this.config.fullscreen.enabled) {\n return;\n }\n\n // Check for native support\n const nativeSupport = fullscreen.enabled;\n\n if (nativeSupport || (this.config.fullscreen.fallback && !utils.inFrame())) {\n this.console.log(`${nativeSupport ? 'Native' : 'Fallback'} fullscreen enabled`);\n\n // Add styling hook to show button\n utils.toggleClass(this.elements.container, this.config.classNames.fullscreen.enabled, true);\n } else {\n this.console.log('Fullscreen not supported and fallback disabled');\n }\n\n // Toggle state\n if (this.elements.buttons && this.elements.buttons.fullscreen) {\n utils.toggleState(this.elements.buttons.fullscreen, false);\n }\n\n // Trap focus in container\n utils.trapFocus.call(this);\n },\n};\n\nexport default fullscreen;\n","// ==========================================================================\n// Plyr Event Listeners\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport controls from './controls';\nimport fullscreen from './fullscreen';\nimport storage from './storage';\nimport ui from './ui';\n\n// Sniff out the browser\nconst browser = utils.getBrowser();\n\nconst listeners = {\n // Global listeners\n global() {\n let last = null;\n\n // Get the key code for an event\n const getKeyCode = event => (event.keyCode ? event.keyCode : event.which);\n\n // Handle key press\n const handleKey = event => {\n const code = getKeyCode(event);\n const pressed = event.type === 'keydown';\n const held = pressed && code === last;\n\n // If the event is bubbled from the media element\n // Firefox doesn't get the keycode for whatever reason\n if (!utils.is.number(code)) {\n return;\n }\n\n // Seek by the number keys\n const seekByKey = () => {\n // Divide the max duration into 10th's and times by the number value\n this.currentTime = this.duration / 10 * (code - 48);\n };\n\n // Handle the key on keydown\n // Reset on keyup\n if (pressed) {\n // Which keycodes should we prevent default\n const preventDefault = [\n 48,\n 49,\n 50,\n 51,\n 52,\n 53,\n 54,\n 56,\n 57,\n 32,\n 75,\n 38,\n 40,\n 77,\n 39,\n 37,\n 70,\n 67,\n 73,\n 76,\n 79,\n ];\n\n // Check focused element\n // and if the focused element is not editable (e.g. text input)\n // and any that accept key input http://webaim.org/techniques/keyboard/\n const focused = utils.getFocusElement();\n if (utils.is.htmlElement(focused) && utils.matches(focused, this.config.selectors.editable)) {\n return;\n }\n\n // If the code is found prevent default (e.g. prevent scrolling for arrows)\n if (preventDefault.includes(code)) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n switch (code) {\n case 48:\n case 49:\n case 50:\n case 51:\n case 52:\n case 53:\n case 54:\n case 55:\n case 56:\n case 57:\n // 0-9\n if (!held) {\n seekByKey();\n }\n break;\n\n case 32:\n case 75:\n // Space and K key\n if (!held) {\n this.togglePlay();\n }\n break;\n\n case 38:\n // Arrow up\n this.increaseVolume(0.1);\n break;\n\n case 40:\n // Arrow down\n this.decreaseVolume(0.1);\n break;\n\n case 77:\n // M key\n if (!held) {\n this.muted = !this.muted;\n }\n break;\n\n case 39:\n // Arrow forward\n this.forward();\n break;\n\n case 37:\n // Arrow back\n this.rewind();\n break;\n\n case 70:\n // F key\n this.toggleFullscreen();\n break;\n\n case 67:\n // C key\n if (!held) {\n this.toggleCaptions();\n }\n break;\n\n case 76:\n // L key\n this.loop = !this.loop;\n break;\n\n /* case 73:\n this.setLoop('start');\n break;\n\n case 76:\n this.setLoop();\n break;\n\n case 79:\n this.setLoop('end');\n break; */\n\n default:\n break;\n }\n\n // Escape is handle natively when in full screen\n // So we only need to worry about non native\n if (!fullscreen.enabled && this.fullscreen.active && code === 27) {\n this.toggleFullscreen();\n }\n\n // Store last code for next cycle\n last = code;\n } else {\n last = null;\n }\n };\n\n // Keyboard shortcuts\n if (this.config.keyboard.global) {\n utils.on(window, 'keydown keyup', handleKey, false);\n } else if (this.config.keyboard.focused) {\n utils.on(this.elements.container, 'keydown keyup', handleKey, false);\n }\n\n // Detect tab focus\n // Remove class on blur/focusout\n utils.on(this.elements.container, 'focusout', event => {\n utils.toggleClass(event.target, this.config.classNames.tabFocus, false);\n });\n\n // Add classname to tabbed elements\n utils.on(this.elements.container, 'keydown', event => {\n if (event.keyCode !== 9) {\n return;\n }\n\n // Delay the adding of classname until the focus has changed\n // This event fires before the focusin event\n window.setTimeout(() => {\n utils.toggleClass(utils.getFocusElement(), this.config.classNames.tabFocus, true);\n }, 0);\n });\n\n // Toggle controls visibility based on mouse movement\n if (this.config.hideControls) {\n // Toggle controls on mouse events and entering fullscreen\n utils.on(\n this.elements.container,\n 'mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen',\n event => {\n this.toggleControls(event);\n }\n );\n }\n\n // Handle user exiting fullscreen by escaping etc\n if (fullscreen.enabled) {\n utils.on(document, fullscreen.eventType, event => {\n this.toggleFullscreen(event);\n });\n }\n },\n\n // Listen for media events\n media() {\n // Time change on media\n utils.on(this.media, 'timeupdate seeking', event => ui.timeUpdate.call(this, event));\n\n // Display duration\n utils.on(this.media, 'durationchange loadedmetadata', event => ui.displayDuration.call(this, event));\n\n // Handle the media finishing\n utils.on(this.media, 'ended', () => {\n // Show poster on end\n if (this.type === 'video' && this.config.showPosterOnEnd) {\n // Restart\n this.restart();\n\n // Re-load media\n this.media.load();\n }\n });\n\n // Check for buffer progress\n utils.on(this.media, 'progress playing', event => ui.updateProgress.call(this, event));\n\n // Handle native mute\n utils.on(this.media, 'volumechange', event => ui.updateVolume.call(this, event));\n\n // Handle native play/pause\n utils.on(this.media, 'play pause ended', event => ui.checkPlaying.call(this, event));\n\n // Loading\n utils.on(this.media, 'waiting canplay seeked', event => ui.checkLoading.call(this, event));\n\n // Click video\n if (this.supported.ui && this.config.clickToPlay && this.type !== 'audio') {\n // Re-fetch the wrapper\n const wrapper = utils.getElement.call(this, `.${this.config.classNames.video}`);\n\n // Bail if there's no wrapper (this should never happen)\n if (!wrapper) {\n return;\n }\n\n // Set cursor\n wrapper.style.cursor = 'pointer';\n\n // On click play, pause ore restart\n utils.on(wrapper, 'click', () => {\n // Touch devices will just show controls (if we're hiding controls)\n if (this.config.hideControls && support.touch && !this.media.paused) {\n return;\n }\n\n if (this.media.paused) {\n this.play();\n } else if (this.media.ended) {\n this.restart();\n this.play();\n } else {\n this.pause();\n }\n });\n }\n\n // Disable right click\n if (this.config.disableContextMenu) {\n utils.on(\n this.media,\n 'contextmenu',\n event => {\n event.preventDefault();\n },\n false\n );\n }\n\n // Speed change\n utils.on(this.media, 'ratechange', () => {\n // Update UI\n controls.updateSetting.call(this, 'speed');\n\n // Save to storage\n storage.set.call(this, { speed: this.speed });\n });\n\n // Quality change\n utils.on(this.media, 'qualitychange', () => {\n // Update UI\n controls.updateSetting.call(this, 'quality');\n\n // Save to storage\n storage.set.call(this, { quality: this.quality });\n });\n\n // Caption language change\n utils.on(this.media, 'languagechange', () => {\n // Save to storage\n storage.set.call(this, { language: this.language });\n });\n\n // Volume change\n utils.on(this.media, 'volumechange', () => {\n // Save to storage\n storage.set.call(this, { volume: this.volume, muted: this.muted });\n });\n\n // Captions toggle\n utils.on(this.media, 'captionsenabled captionsdisabled', () => {\n // Update UI\n controls.updateSetting.call(this, 'captions');\n\n // Save to storage\n storage.set.call(this, { captions: this.captions.enabled });\n });\n\n // Proxy events to container\n // Bubble up key events for Edge\n utils.on(this.media, this.config.events.concat(['keyup', 'keydown']).join(' '), event => {\n let detail = {};\n\n // Get error details from media\n if (event.type === 'error') {\n detail = this.media.error;\n }\n\n utils.dispatchEvent.call(this, this.elements.container, event.type, true, detail);\n });\n },\n\n // Listen for control events\n controls() {\n // IE doesn't support input event, so we fallback to change\n const inputEvent = browser.isIE ? 'change' : 'input';\n\n // Trigger custom and default handlers\n const proxy = (event, handlerKey, defaultHandler) => {\n const customHandler = this.config.listeners[handlerKey];\n\n // Execute custom handler\n if (utils.is.function(customHandler)) {\n customHandler.call(this, event);\n }\n\n // Only call default handler if not prevented in custom handler\n if (!event.defaultPrevented && utils.is.function(defaultHandler)) {\n defaultHandler.call(this, event);\n }\n };\n\n // Click play/pause helper\n const togglePlay = () => {\n const play = this.togglePlay();\n\n // Determine which buttons\n const target = this.elements.buttons[play ? 'pause' : 'play'];\n\n // Transfer focus\n if (utils.is.htmlElement(target)) {\n target.focus();\n }\n };\n\n // Play\n utils.on(this.elements.buttons.play, 'click', event => proxy(event, 'play', togglePlay));\n\n // Pause\n utils.on(this.elements.buttons.pause, 'click', event => proxy(event, 'pause', togglePlay));\n\n // Pause\n utils.on(this.elements.buttons.restart, 'click', event =>\n proxy(event, 'restart', () => {\n this.restart();\n })\n );\n\n // Rewind\n utils.on(this.elements.buttons.rewind, 'click', event =>\n proxy(event, 'rewind', () => {\n this.rewind();\n })\n );\n\n // Rewind\n utils.on(this.elements.buttons.forward, 'click', event =>\n proxy(event, 'forward', () => {\n this.forward();\n })\n );\n\n // Mute\n utils.on(this.elements.buttons.mute, 'click', event =>\n proxy(event, 'mute', () => {\n this.muted = !this.muted;\n })\n );\n\n // Captions\n utils.on(this.elements.buttons.captions, 'click', event =>\n proxy(event, 'captions', () => {\n this.toggleCaptions();\n })\n );\n\n // Fullscreen\n utils.on(this.elements.buttons.fullscreen, 'click', event =>\n proxy(event, 'fullscreen', () => {\n this.toggleFullscreen();\n })\n );\n\n // Picture-in-Picture\n utils.on(this.elements.buttons.pip, 'click', event =>\n proxy(event, 'pip', () => {\n this.pip = 'toggle';\n })\n );\n\n // Airplay\n utils.on(this.elements.buttons.airplay, 'click', event =>\n proxy(event, 'airplay', () => {\n this.airPlay();\n })\n );\n\n // Settings menu\n utils.on(this.elements.buttons.settings, 'click', event => {\n controls.toggleMenu.call(this, event);\n });\n\n // Click anywhere closes menu\n utils.on(document.documentElement, 'click', event => {\n controls.toggleMenu.call(this, event);\n });\n\n // Settings menu\n utils.on(this.elements.settings.form, 'click', event => {\n // Show tab in menu\n controls.showTab.call(this, event);\n\n // Settings menu items - use event delegation as items are added/removed\n // Settings - Language\n if (utils.matches(event.target, this.config.selectors.inputs.language)) {\n proxy(event, 'language', () => {\n this.toggleCaptions(true);\n this.language = event.target.value.toLowerCase();\n });\n } else if (utils.matches(event.target, this.config.selectors.inputs.quality)) {\n // Settings - Quality\n proxy(event, 'quality', () => {\n this.quality = event.target.value;\n });\n } else if (utils.matches(event.target, this.config.selectors.inputs.speed)) {\n // Settings - Speed\n proxy(event, 'speed', () => {\n this.speed = parseFloat(event.target.value);\n });\n } else if (utils.matches(event.target, this.config.selectors.buttons.loop)) {\n // Settings - Looping\n // TODO: use toggle buttons\n proxy(event, 'loop', () => {\n // TODO: This should be done in the method itself I think\n // var value = event.target.getAttribute('data-loop__value') || event.target.getAttribute('data-loop__type');\n\n this.console.warn('Set loop');\n });\n }\n });\n\n // Seek\n utils.on(this.elements.inputs.seek, inputEvent, event =>\n proxy(event, 'seek', () => {\n this.currentTime = event.target.value / event.target.max * this.duration;\n })\n );\n\n // Volume\n utils.on(this.elements.inputs.volume, inputEvent, event =>\n proxy(event, 'volume', () => {\n this.volume = event.target.value;\n })\n );\n\n // Polyfill for lower fill in <input type=\"range\"> for webkit\n if (browser.isWebkit) {\n utils.on(utils.getElements.call(this, 'input[type=\"range\"]'), 'input', event => {\n controls.updateRangeFill.call(this, event.target);\n });\n }\n\n // Seek tooltip\n utils.on(this.elements.progress, 'mouseenter mouseleave mousemove', event =>\n controls.updateSeekTooltip.call(this, event)\n );\n\n // Toggle controls visibility based on mouse movement\n if (this.config.hideControls) {\n // Watch for cursor over controls so they don't hide when trying to interact\n utils.on(this.elements.controls, 'mouseenter mouseleave', event => {\n this.elements.controls.hover = event.type === 'mouseenter';\n });\n\n // Watch for cursor over controls so they don't hide when trying to interact\n utils.on(this.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {\n this.elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);\n });\n\n // Focus in/out on controls\n // TODO: Check we need capture here\n utils.on(\n this.elements.controls,\n 'focus blur',\n event => {\n this.toggleControls(event);\n },\n true\n );\n }\n\n // Mouse wheel for volume\n utils.on(\n this.elements.inputs.volume,\n 'wheel',\n event =>\n proxy(event, 'volume', () => {\n // Detect \"natural\" scroll - suppored on OS X Safari only\n // Other browsers on OS X will be inverted until support improves\n const inverted = event.webkitDirectionInvertedFromDevice;\n const step = 1 / 50;\n let direction = 0;\n\n // Scroll down (or up on natural) to decrease\n if (event.deltaY < 0 || event.deltaX > 0) {\n if (inverted) {\n this.decreaseVolume(step);\n direction = -1;\n } else {\n this.increaseVolume(step);\n direction = 1;\n }\n }\n\n // Scroll up (or down on natural) to increase\n if (event.deltaY > 0 || event.deltaX < 0) {\n if (inverted) {\n this.increaseVolume(step);\n direction = 1;\n } else {\n this.decreaseVolume(step);\n direction = -1;\n }\n }\n\n // Don't break page scrolling at max and min\n if ((direction === 1 && this.media.volume < 1) || (direction === -1 && this.media.volume > 0)) {\n event.preventDefault();\n }\n }),\n false\n );\n },\n};\n\nexport default listeners;\n","// ==========================================================================\n// Plyr UI\n// ==========================================================================\n\nimport utils from './utils';\nimport captions from './captions';\nimport controls from './controls';\nimport fullscreen from './fullscreen';\nimport listeners from './listeners';\n\nconst ui = {\n addStyleHook() {\n utils.toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);\n utils.toggleClass(this.elements.container, this.config.classNames.uiSupported, this.supported.ui);\n },\n\n // Toggle native HTML5 media controls\n toggleNativeControls(toggle) {\n if (toggle && this.isHTML5) {\n this.media.setAttribute('controls', '');\n } else {\n this.media.removeAttribute('controls');\n }\n },\n\n // Setup the UI\n build() {\n // Re-attach media element listeners\n // TODO: Use event bubbling\n listeners.media.call(this);\n\n // Don't setup interface if no support\n if (!this.supported.ui) {\n this.console.warn(`Basic support only for ${this.type}`);\n\n // Remove controls\n utils.removeElement.call(this, 'controls');\n\n // Remove large play\n utils.removeElement.call(this, 'buttons.play');\n\n // Restore native controls\n ui.toggleNativeControls.call(this, true);\n\n // Bail\n return;\n }\n\n // Inject custom controls if not present\n if (!utils.is.htmlElement(this.elements.controls)) {\n // Inject custom controls\n controls.inject.call(this);\n\n // Re-attach control listeners\n listeners.controls.call(this);\n }\n\n // If there's no controls, bail\n if (!utils.is.htmlElement(this.elements.controls)) {\n return;\n }\n\n // Remove native controls\n ui.toggleNativeControls.call(this);\n\n // Setup fullscreen\n fullscreen.setup.call(this);\n\n // Captions\n captions.setup.call(this);\n\n // Reset volume\n this.volume = null;\n\n // Reset mute state\n this.muted = null;\n\n // Reset speed\n this.speed = null;\n\n // Reset loop state\n this.loop = null;\n\n // Reset quality options\n this.options.quality = [];\n\n // Reset time display\n ui.timeUpdate.call(this);\n\n // Update the UI\n ui.checkPlaying.call(this);\n\n // Ready for API calls\n this.ready = true;\n\n // Ready event at end of execution stack\n utils.dispatchEvent.call(this, this.media, 'ready');\n\n // Set the title\n ui.setTitle.call(this);\n },\n\n // Show the duration on metadataloaded\n displayDuration() {\n if (!this.supported.ui) {\n return;\n }\n\n // If there's only one time display, display duration there\n if (!this.elements.display.duration && this.config.displayDuration && this.paused) {\n ui.updateTimeDisplay.call(this, this.duration, this.elements.display.currentTime);\n }\n\n // If there's a duration element, update content\n if (this.elements.display.duration) {\n ui.updateTimeDisplay.call(this, this.duration, this.elements.display.duration);\n }\n\n // Update the tooltip (if visible)\n controls.updateSeekTooltip.call(this);\n },\n\n // Setup aria attribute for play and iframe title\n setTitle() {\n // Find the current text\n let label = this.config.i18n.play;\n\n // If there's a media title set, use that for the label\n if (utils.is.string(this.config.title) && !utils.is.empty(this.config.title)) {\n label += `, ${this.config.title}`;\n\n // Set container label\n this.elements.container.setAttribute('aria-label', this.config.title);\n }\n\n // If there's a play button, set label\n if (utils.is.nodeList(this.elements.buttons.play)) {\n Array.from(this.elements.buttons.play).forEach(button => {\n button.setAttribute('aria-label', label);\n });\n }\n\n // Set iframe title\n // https://github.com/sampotts/plyr/issues/124\n if (this.isEmbed) {\n const iframe = utils.getElement.call(this, 'iframe');\n\n if (!utils.is.htmlElement(iframe)) {\n return;\n }\n\n // Default to media type\n const title = !utils.is.empty(this.config.title) ? this.config.title : 'video';\n\n iframe.setAttribute('title', this.config.i18n.frameTitle.replace('{title}', title));\n }\n },\n\n // Check playing state\n checkPlaying() {\n utils.toggleClass(this.elements.container, this.config.classNames.playing, !this.paused);\n\n utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.paused);\n\n this.toggleControls(this.paused);\n },\n\n // Update volume UI and storage\n updateVolume() {\n if (!this.supported.ui) {\n return;\n }\n\n // Update range\n if (utils.is.htmlElement(this.elements.inputs.volume)) {\n ui.setRange.call(this, this.elements.inputs.volume, this.muted ? 0 : this.volume);\n }\n\n // Update checkbox for mute state\n if (utils.is.htmlElement(this.elements.buttons.mute)) {\n utils.toggleState(this.elements.buttons.mute, this.muted || this.volume === 0);\n }\n },\n\n // Check if media is loading\n checkLoading(event) {\n this.loading = event.type === 'waiting';\n\n // Clear timer\n clearTimeout(this.timers.loading);\n\n // Timer to prevent flicker when seeking\n this.timers.loading = setTimeout(() => {\n // Toggle container class hook\n utils.toggleClass(this.elements.container, this.config.classNames.loading, this.loading);\n\n // Show controls if loading, hide if done\n this.toggleControls(this.loading);\n }, this.loading ? 250 : 0);\n },\n\n // Update seek value and lower fill\n setRange(target, value) {\n if (!utils.is.htmlElement(target)) {\n return;\n }\n\n // eslint-disable-next-line\n target.value = value;\n\n // Webkit range fill\n controls.updateRangeFill.call(this, target);\n },\n\n // Set <progress> value\n setProgress(target, input) {\n // Default to 0\n const value = !utils.is.undefined(input) ? input : 0;\n const progress = !utils.is.undefined(target) ? target : this.elements.display.buffer;\n\n // Update value and label\n if (utils.is.htmlElement(progress)) {\n progress.value = value;\n\n // Update text label inside\n const label = progress.getElementsByTagName('span')[0];\n if (utils.is.htmlElement(label)) {\n label.childNodes[0].nodeValue = value;\n }\n }\n },\n\n // Update <progress> elements\n updateProgress(event) {\n if (!this.supported.ui) {\n return;\n }\n\n let value = 0;\n\n if (event) {\n switch (event.type) {\n // Video playing\n case 'timeupdate':\n case 'seeking':\n value = utils.getPercentage(this.currentTime, this.duration);\n\n // Set seek range value only if it's a 'natural' time event\n if (event.type === 'timeupdate') {\n ui.setRange.call(this, this.elements.inputs.seek, value);\n }\n\n break;\n\n // Check buffer status\n case 'playing':\n case 'progress':\n value = (() => {\n const { buffered } = this.media;\n\n if (buffered && buffered.length) {\n // HTML5\n return utils.getPercentage(buffered.end(0), this.duration);\n } else if (utils.is.number(buffered)) {\n // YouTube returns between 0 and 1\n return buffered * 100;\n }\n\n return 0;\n })();\n\n ui.setProgress.call(this, this.elements.display.buffer, value);\n\n break;\n\n default:\n break;\n }\n }\n },\n\n // Update the displayed time\n updateTimeDisplay(value, element) {\n // Bail if there's no duration display\n if (!utils.is.htmlElement(element)) {\n return null;\n }\n\n // Fallback to 0\n const time = !Number.isNaN(value) ? value : 0;\n\n let secs = parseInt(time % 60, 10);\n let mins = parseInt((time / 60) % 60, 10);\n const hours = parseInt((time / 60 / 60) % 60, 10);\n\n // Do we need to display hours?\n const displayHours = parseInt((this.duration / 60 / 60) % 60, 10) > 0;\n\n // Ensure it's two digits. For example, 03 rather than 3.\n secs = `0${secs}`.slice(-2);\n mins = `0${mins}`.slice(-2);\n\n // Generate display\n const display = `${(displayHours ? `${hours}:` : '') + mins}:${secs}`;\n\n // Render\n // eslint-disable-next-line\n element.textContent = display;\n\n // Return for looping\n return display;\n },\n\n // Handle time change event\n timeUpdate(event) {\n // Duration\n ui.updateTimeDisplay.call(this, this.currentTime, this.elements.display.currentTime);\n\n // Ignore updates while seeking\n if (event && event.type === 'timeupdate' && this.media.seeking) {\n return;\n }\n\n // Playing progress\n ui.updateProgress.call(this, event);\n },\n};\n\nexport default ui;\n","// ==========================================================================\n// Plyr controls\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport ui from './ui';\n\n// Sniff out the browser\nconst browser = utils.getBrowser();\n\nconst controls = {\n // Webkit polyfill for lower fill range\n updateRangeFill(target) {\n // WebKit only\n if (!browser.isWebkit) {\n return;\n }\n\n // Get range from event if event passed\n const range = utils.is.event(target) ? target.target : target;\n\n // Needs to be a valid <input type='range'>\n if (!utils.is.htmlElement(range) || range.getAttribute('type') !== 'range') {\n return;\n }\n\n // Inject the stylesheet if needed\n if (!utils.is.htmlElement(this.elements.styleSheet)) {\n this.elements.styleSheet = utils.createElement('style');\n this.elements.container.appendChild(this.elements.styleSheet);\n }\n\n const styleSheet = this.elements.styleSheet.sheet;\n const percentage = range.value / range.max * 100;\n const selector = `#${range.id}::-webkit-slider-runnable-track`;\n const styles = `{ background-image: linear-gradient(to right, currentColor ${percentage}%, transparent ${percentage}%) }`;\n\n // Find old rule if it exists\n const index = Array.from(styleSheet.rules).findIndex(rule => rule.selectorText === selector);\n\n // Remove old rule\n if (index !== -1) {\n styleSheet.deleteRule(index);\n }\n\n // Insert new one\n styleSheet.insertRule([selector, styles].join(' '));\n },\n\n // Get icon URL\n getIconUrl() {\n return {\n url: this.config.iconUrl,\n absolute: this.config.iconUrl.indexOf('http') === 0 || (browser.isIE && !window.svg4everybody),\n };\n },\n\n // Create <svg> icon\n createIcon(type, attributes) {\n const namespace = 'http://www.w3.org/2000/svg';\n const iconUrl = controls.getIconUrl.call(this);\n const iconPath = `${!iconUrl.absolute ? iconUrl.url : ''}#${this.config.iconPrefix}`;\n\n // Create <svg>\n const icon = document.createElementNS(namespace, 'svg');\n utils.setAttributes(\n icon,\n utils.extend(attributes, {\n role: 'presentation',\n })\n );\n\n // Create the <use> to reference sprite\n const use = document.createElementNS(namespace, 'use');\n const path = `${iconPath}-${type}`;\n\n // Set `href` attributes\n // https://github.com/sampotts/plyr/issues/460\n // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path);\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path);\n\n // Add <use> to <svg>\n icon.appendChild(use);\n\n return icon;\n },\n\n // Create hidden text label\n createLabel(type) {\n let text = this.config.i18n[type];\n\n switch (type) {\n case 'pip':\n text = 'PIP';\n break;\n\n case 'airplay':\n text = 'AirPlay';\n break;\n\n default:\n break;\n }\n\n return utils.createElement(\n 'span',\n {\n class: this.config.classNames.hidden,\n },\n text\n );\n },\n\n // Create a badge\n createBadge(text) {\n const badge = utils.createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n badge.appendChild(\n utils.createElement(\n 'span',\n {\n class: this.config.classNames.menu.badge,\n },\n text\n )\n );\n\n return badge;\n },\n\n // Create a <button>\n createButton(buttonType, attr) {\n const button = utils.createElement('button');\n const attributes = Object.assign({}, attr);\n let type = buttonType;\n let iconDefault;\n let iconToggled;\n let labelKey;\n\n if (!('type' in attributes)) {\n attributes.type = 'button';\n }\n\n if ('class' in attributes) {\n if (attributes.class.indexOf(this.config.classNames.control) === -1) {\n attributes.class += ` ${this.config.classNames.control}`;\n }\n } else {\n attributes.class = this.config.classNames.control;\n }\n\n // Large play button\n switch (type) {\n case 'mute':\n labelKey = 'toggleMute';\n iconDefault = 'volume';\n iconToggled = 'muted';\n break;\n\n case 'captions':\n labelKey = 'toggleCaptions';\n iconDefault = 'captions-off';\n iconToggled = 'captions-on';\n break;\n\n case 'fullscreen':\n labelKey = 'toggleFullscreen';\n iconDefault = 'enter-fullscreen';\n iconToggled = 'exit-fullscreen';\n break;\n\n case 'play-large':\n attributes.class = 'plyr__play-large';\n type = 'play';\n labelKey = 'play';\n iconDefault = 'play';\n break;\n\n default:\n labelKey = type;\n iconDefault = type;\n }\n\n // Merge attributes\n utils.extend(attributes, utils.getAttributesFromSelector(this.config.selectors.buttons[type], attributes));\n\n // Add toggle icon if needed\n if (utils.is.string(iconToggled)) {\n button.appendChild(\n controls.createIcon.call(this, iconToggled, {\n class: 'icon--pressed',\n })\n );\n button.appendChild(\n controls.createIcon.call(this, iconDefault, {\n class: 'icon--not-pressed',\n })\n );\n } else {\n button.appendChild(controls.createIcon.call(this, iconDefault));\n }\n\n button.appendChild(controls.createLabel.call(this, labelKey));\n\n utils.setAttributes(button, attributes);\n\n this.elements.buttons[type] = button;\n\n return button;\n },\n\n // Create an <input type='range'>\n createRange(type, attributes) {\n // Seek label\n const label = utils.createElement(\n 'label',\n {\n for: attributes.id,\n class: this.config.classNames.hidden,\n },\n this.config.i18n[type]\n );\n\n // Seek input\n const input = utils.createElement(\n 'input',\n utils.extend(\n utils.getAttributesFromSelector(this.config.selectors.inputs[type]),\n {\n type: 'range',\n min: 0,\n max: 100,\n step: 0.01,\n value: 0,\n autocomplete: 'off',\n },\n attributes\n )\n );\n\n this.elements.inputs[type] = input;\n\n // Set the fill for webkit now\n controls.updateRangeFill.call(this, input);\n\n return {\n label,\n input,\n };\n },\n\n // Create a <progress>\n createProgress(type, attributes) {\n const progress = utils.createElement(\n 'progress',\n utils.extend(\n utils.getAttributesFromSelector(this.config.selectors.display[type]),\n {\n min: 0,\n max: 100,\n value: 0,\n },\n attributes\n )\n );\n\n // Create the label inside\n if (type !== 'volume') {\n progress.appendChild(utils.createElement('span', null, '0'));\n\n let suffix = '';\n switch (type) {\n case 'played':\n suffix = this.config.i18n.played;\n break;\n\n case 'buffer':\n suffix = this.config.i18n.buffered;\n break;\n\n default:\n break;\n }\n\n progress.textContent = `% ${suffix.toLowerCase()}`;\n }\n\n this.elements.display[type] = progress;\n\n return progress;\n },\n\n // Create time display\n createTime(type) {\n const container = utils.createElement('span', {\n class: 'plyr__time',\n });\n\n container.appendChild(\n utils.createElement(\n 'span',\n {\n class: this.config.classNames.hidden,\n },\n this.config.i18n[type]\n )\n );\n\n container.appendChild(\n utils.createElement('span', utils.getAttributesFromSelector(this.config.selectors.display[type]), '00:00')\n );\n\n this.elements.display[type] = container;\n\n return container;\n },\n\n // Update hover tooltip for seeking\n updateSeekTooltip(event) {\n // Bail if setting not true\n if (\n !this.config.tooltips.seek ||\n !utils.is.htmlElement(this.elements.inputs.seek) ||\n !utils.is.htmlElement(this.elements.display.seekTooltip) ||\n this.duration === 0\n ) {\n return;\n }\n\n // Calculate percentage\n let percent = 0;\n const clientRect = this.elements.inputs.seek.getBoundingClientRect();\n const visible = `${this.config.classNames.tooltip}--visible`;\n\n // Determine percentage, if already visible\n if (utils.is.event(event)) {\n percent = 100 / clientRect.width * (event.pageX - clientRect.left);\n } else if (utils.hasClass(this.elements.display.seekTooltip, visible)) {\n percent = this.elements.display.seekTooltip.style.left.replace('%', '');\n } else {\n return;\n }\n\n // Set bounds\n if (percent < 0) {\n percent = 0;\n } else if (percent > 100) {\n percent = 100;\n }\n\n // Display the time a click would seek to\n ui.updateTimeDisplay.call(this, this.duration / 100 * percent, this.elements.display.seekTooltip);\n\n // Set position\n this.elements.display.seekTooltip.style.left = `${percent}%`;\n\n // Show/hide the tooltip\n // If the event is a moues in/out and percentage is inside bounds\n if (utils.is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) {\n utils.toggleClass(this.elements.display.seekTooltip, visible, event.type === 'mouseenter');\n }\n },\n\n // Hide/show a tab\n toggleTab(setting, toggle) {\n const tab = this.elements.settings.tabs[setting];\n const pane = this.elements.settings.panes[setting];\n\n if (utils.is.htmlElement(tab)) {\n if (toggle) {\n tab.removeAttribute('hidden');\n } else {\n tab.setAttribute('hidden', '');\n }\n }\n\n if (utils.is.htmlElement(pane)) {\n if (toggle) {\n pane.removeAttribute('hidden');\n } else {\n pane.setAttribute('hidden', '');\n }\n }\n },\n\n // Set the YouTube quality menu\n // TODO: Support for HTML5\n setQualityMenu(options) {\n const list = this.elements.settings.panes.quality.querySelector('ul');\n\n // Set options if passed and filter based on config\n if (utils.is.array(options)) {\n this.options.quality = options.filter(quality => this.config.quality.options.includes(quality));\n } else {\n this.options.quality = this.config.quality.options;\n }\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.options.quality) && this.type === 'youtube';\n controls.toggleTab.call(this, 'quality', toggle);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Empty the menu\n utils.emptyElement(list);\n\n // Get the badge HTML for HD, 4K etc\n const getBadge = quality => {\n let label = '';\n\n switch (quality) {\n case 'hd2160':\n label = '4K';\n break;\n\n case 'hd1440':\n label = 'WQHD';\n break;\n\n case 'hd1080':\n label = 'HD';\n break;\n\n case 'hd720':\n label = 'HD';\n break;\n\n default:\n break;\n }\n\n if (!label.length) {\n return null;\n }\n\n return controls.createBadge.call(this, label);\n };\n\n this.options.quality.forEach(quality => {\n const item = utils.createElement('li');\n\n const label = utils.createElement('label', {\n class: this.config.classNames.control,\n });\n\n const radio = utils.createElement(\n 'input',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs.quality), {\n type: 'radio',\n name: 'plyr-quality',\n value: quality,\n })\n );\n\n label.appendChild(radio);\n label.appendChild(document.createTextNode(controls.getLabel.call(this, 'quality', quality)));\n\n const badge = getBadge(quality);\n if (utils.is.htmlElement(badge)) {\n label.appendChild(badge);\n }\n\n item.appendChild(label);\n list.appendChild(item);\n });\n\n controls.updateSetting.call(this, 'quality', list);\n },\n\n // Translate a value into a nice label\n // TODO: Localisation\n getLabel(setting, value) {\n switch (setting) {\n case 'speed':\n return value === 1 ? 'Normal' : `${value}×`;\n\n case 'quality':\n switch (value) {\n case 'hd2160':\n return '2160P';\n case 'hd1440':\n return '1440P';\n case 'hd1080':\n return '1080P';\n case 'hd720':\n return '720P';\n case 'large':\n return '480P';\n case 'medium':\n return '360P';\n case 'small':\n return '240P';\n case 'tiny':\n return 'Tiny';\n case 'default':\n return 'Auto';\n default:\n return value;\n }\n\n case 'captions':\n return controls.getLanguage.call(this);\n\n default:\n return null;\n }\n },\n\n // Update the selected setting\n updateSetting(setting, container) {\n const pane = this.elements.settings.panes[setting];\n let value = null;\n let list = container;\n\n switch (setting) {\n case 'captions':\n value = this.captions.language;\n\n if (!this.captions.enabled) {\n value = '';\n }\n\n break;\n\n default:\n value = this[setting];\n\n // Get default\n if (utils.is.empty(value)) {\n value = this.config[setting].default;\n }\n\n // Unsupported value\n if (!this.options[setting].includes(value)) {\n this.console.warn(`Unsupported value of '${value}' for ${setting}`);\n return;\n }\n\n // Disabled value\n if (!this.config[setting].options.includes(value)) {\n this.console.warn(`Disabled value of '${value}' for ${setting}`);\n return;\n }\n\n break;\n }\n\n // Get the list if we need to\n if (!utils.is.htmlElement(list)) {\n list = pane && pane.querySelector('ul');\n }\n\n // Find the radio option\n const target = list && list.querySelector(`input[value=\"${value}\"]`);\n\n if (!utils.is.htmlElement(target)) {\n return;\n }\n\n // Check it\n target.checked = true;\n\n // Find the label\n const label = this.elements.settings.tabs[setting].querySelector(`.${this.config.classNames.menu.value}`);\n label.innerHTML = controls.getLabel.call(this, setting, value);\n },\n\n // Set the looping options\n setLoopMenu() {\n const options = ['start', 'end', 'all', 'reset'];\n const list = this.elements.settings.panes.loop.querySelector('ul');\n\n // Show the pane and tab\n this.elements.settings.tabs.loop.removeAttribute('hidden');\n this.elements.settings.panes.loop.removeAttribute('hidden');\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.loop.options);\n controls.toggleTab.call(this, 'loop', toggle);\n\n // Empty the menu\n utils.emptyElement(list);\n\n options.forEach(option => {\n const item = utils.createElement('li');\n\n const button = utils.createElement(\n 'button',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.buttons.loop), {\n type: 'button',\n class: this.config.classNames.control,\n 'data-plyr-loop-action': option,\n }),\n this.config.i18n[option]\n );\n\n if (['start', 'end'].includes(option)) {\n const badge = controls.createBadge.call(this, '00:00');\n button.appendChild(badge);\n }\n\n item.appendChild(button);\n list.appendChild(item);\n });\n },\n\n // Get current selected caption language\n // TODO: rework this to user the getter in the API?\n getLanguage() {\n if (!this.supported.ui) {\n return null;\n }\n\n if (!support.textTracks || utils.is.empty(this.captions.tracks)) {\n return this.config.i18n.none;\n }\n\n if (this.captions.enabled) {\n return this.captions.currentTrack.label;\n }\n\n return this.config.i18n.disabled;\n },\n\n // Set a list of available captions languages\n setCaptionsMenu() {\n const list = this.elements.settings.panes.captions.querySelector('ul');\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.captions.tracks);\n controls.toggleTab.call(this, 'captions', toggle);\n\n // Empty the menu\n utils.emptyElement(list);\n\n // If there's no captions, bail\n if (utils.is.empty(this.captions.tracks)) {\n return;\n }\n\n // Re-map the tracks into just the data we need\n const tracks = Array.from(this.captions.tracks).map(track => ({\n language: track.language,\n badge: true,\n label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase(),\n }));\n\n // Add the \"None\" option to turn off captions\n tracks.unshift({\n language: '',\n label: this.config.i18n.none,\n });\n\n // Generate options\n tracks.forEach(track => {\n const item = utils.createElement('li');\n\n const label = utils.createElement('label', {\n class: this.config.classNames.control,\n });\n\n const radio = utils.createElement(\n 'input',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs.language), {\n type: 'radio',\n name: 'plyr-language',\n value: track.language,\n })\n );\n\n if (track.language.toLowerCase() === this.captions.language.toLowerCase()) {\n radio.checked = true;\n }\n\n label.appendChild(radio);\n label.appendChild(document.createTextNode(track.label || track.language));\n\n if (track.badge) {\n label.appendChild(controls.createBadge.call(this, track.language.toUpperCase()));\n }\n\n item.appendChild(label);\n list.appendChild(item);\n });\n\n controls.updateSetting.call(this, 'captions', list);\n },\n\n // Set a list of available captions languages\n setSpeedMenu(options) {\n // Set options if passed and filter based on config\n if (utils.is.array(options)) {\n this.options.speed = options.filter(speed => this.config.speed.options.includes(speed));\n } else {\n this.options.speed = this.config.speed.options;\n }\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.options.speed);\n controls.toggleTab.call(this, 'speed', toggle);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Get the list to populate\n const list = this.elements.settings.panes.speed.querySelector('ul');\n\n // Show the pane and tab\n this.elements.settings.tabs.speed.removeAttribute('hidden');\n this.elements.settings.panes.speed.removeAttribute('hidden');\n\n // Empty the menu\n utils.emptyElement(list);\n\n // Create items\n this.options.speed.forEach(speed => {\n const item = utils.createElement('li');\n\n const label = utils.createElement('label', {\n class: this.config.classNames.control,\n });\n\n const radio = utils.createElement(\n 'input',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs.speed), {\n type: 'radio',\n name: 'plyr-speed',\n value: speed,\n })\n );\n\n label.appendChild(radio);\n label.insertAdjacentHTML('beforeend', controls.getLabel.call(this, 'speed', speed));\n item.appendChild(label);\n list.appendChild(item);\n });\n\n controls.updateSetting.call(this, 'speed', list);\n },\n\n // Show/hide menu\n toggleMenu(event) {\n const { form } = this.elements.settings;\n const button = this.elements.buttons.settings;\n const show = utils.is.boolean(event) ? event : form && form.getAttribute('aria-hidden') === 'true';\n\n if (utils.is.event(event)) {\n const isMenuItem = form && form.contains(event.target);\n const isButton = event.target === this.elements.buttons.settings;\n\n // If the click was inside the form or if the click\n // wasn't the button or menu item and we're trying to\n // show the menu (a doc click shouldn't show the menu)\n if (isMenuItem || (!isMenuItem && !isButton && show)) {\n return;\n }\n\n // Prevent the toggle being caught by the doc listener\n if (isButton) {\n event.stopPropagation();\n }\n }\n\n // Set form and button attributes\n if (button) {\n button.setAttribute('aria-expanded', show);\n }\n if (form) {\n form.setAttribute('aria-hidden', !show);\n\n if (show) {\n form.removeAttribute('tabindex');\n } else {\n form.setAttribute('tabindex', -1);\n }\n }\n },\n\n // Get the natural size of a tab\n getTabSize(tab) {\n const clone = tab.cloneNode(true);\n clone.style.position = 'absolute';\n clone.style.opacity = 0;\n clone.setAttribute('aria-hidden', false);\n\n // Prevent input's being unchecked due to the name being identical\n Array.from(clone.querySelectorAll('input[name]')).forEach(input => {\n const name = input.getAttribute('name');\n input.setAttribute('name', `${name}-clone`);\n });\n\n // Append to parent so we get the \"real\" size\n tab.parentNode.appendChild(clone);\n\n // Get the sizes before we remove\n const width = clone.scrollWidth;\n const height = clone.scrollHeight;\n\n // Remove from the DOM\n utils.removeElement(clone);\n\n return {\n width,\n height,\n };\n },\n\n // Toggle Menu\n showTab(event) {\n const { menu } = this.elements.settings;\n const tab = event.target;\n const show = tab.getAttribute('aria-expanded') === 'false';\n const pane = document.getElementById(tab.getAttribute('aria-controls'));\n\n // Nothing to show, bail\n if (!utils.is.htmlElement(pane)) {\n return;\n }\n\n // Are we targetting a tab? If not, bail\n const isTab = pane.getAttribute('role') === 'tabpanel';\n if (!isTab) {\n return;\n }\n\n // Hide all other tabs\n // Get other tabs\n const current = menu.querySelector('[role=\"tabpanel\"][aria-hidden=\"false\"]');\n const container = current.parentNode;\n\n // Set other toggles to be expanded false\n Array.from(menu.querySelectorAll(`[aria-controls=\"${current.getAttribute('id')}\"]`)).forEach(toggle => {\n toggle.setAttribute('aria-expanded', false);\n });\n\n // If we can do fancy animations, we'll animate the height/width\n if (support.transitions && !support.reducedMotion) {\n // Set the current width as a base\n container.style.width = `${current.scrollWidth}px`;\n container.style.height = `${current.scrollHeight}px`;\n\n // Get potential sizes\n const size = controls.getTabSize.call(this, pane);\n\n // Restore auto height/width\n const restore = e => {\n // We're only bothered about height and width on the container\n if (e.target !== container || !['width', 'height'].includes(e.propertyName)) {\n return;\n }\n\n // Revert back to auto\n container.style.width = '';\n container.style.height = '';\n\n // Only listen once\n utils.off(container, utils.transitionEnd, restore);\n };\n\n // Listen for the transition finishing and restore auto height/width\n utils.on(container, utils.transitionEnd, restore);\n\n // Set dimensions to target\n container.style.width = `${size.width}px`;\n container.style.height = `${size.height}px`;\n }\n\n // Set attributes on current tab\n current.setAttribute('aria-hidden', true);\n current.setAttribute('tabindex', -1);\n\n // Set attributes on target\n pane.setAttribute('aria-hidden', !show);\n tab.setAttribute('aria-expanded', show);\n pane.removeAttribute('tabindex');\n },\n\n // Build the default HTML\n // TODO: Set order based on order in the config.controls array?\n create(data) {\n // Do nothing if we want no controls\n if (utils.is.empty(this.config.controls)) {\n return null;\n }\n\n // Create the container\n const container = utils.createElement(\n 'div',\n utils.getAttributesFromSelector(this.config.selectors.controls.wrapper)\n );\n\n // Restart button\n if (this.config.controls.includes('restart')) {\n container.appendChild(controls.createButton.call(this, 'restart'));\n }\n\n // Rewind button\n if (this.config.controls.includes('rewind')) {\n container.appendChild(controls.createButton.call(this, 'rewind'));\n }\n\n // Play Pause button\n if (this.config.controls.includes('play')) {\n container.appendChild(controls.createButton.call(this, 'play'));\n container.appendChild(controls.createButton.call(this, 'pause'));\n }\n\n // Fast forward button\n if (this.config.controls.includes('fast-forward')) {\n container.appendChild(controls.createButton.call(this, 'fast-forward'));\n }\n\n // Progress\n if (this.config.controls.includes('progress')) {\n const progress = utils.createElement(\n 'span',\n utils.getAttributesFromSelector(this.config.selectors.progress)\n );\n\n // Seek range slider\n const seek = controls.createRange.call(this, 'seek', {\n id: `plyr-seek-${data.id}`,\n });\n progress.appendChild(seek.label);\n progress.appendChild(seek.input);\n\n // Buffer progress\n progress.appendChild(controls.createProgress.call(this, 'buffer'));\n\n // TODO: Add loop display indicator\n\n // Seek tooltip\n if (this.config.tooltips.seek) {\n const tooltip = utils.createElement(\n 'span',\n {\n role: 'tooltip',\n class: this.config.classNames.tooltip,\n },\n '00:00'\n );\n\n progress.appendChild(tooltip);\n this.elements.display.seekTooltip = tooltip;\n }\n\n this.elements.progress = progress;\n container.appendChild(this.elements.progress);\n }\n\n // Media current time display\n if (this.config.controls.includes('current-time')) {\n container.appendChild(controls.createTime.call(this, 'currentTime'));\n }\n\n // Media duration display\n if (this.config.controls.includes('duration')) {\n container.appendChild(controls.createTime.call(this, 'duration'));\n }\n\n // Toggle mute button\n if (this.config.controls.includes('mute')) {\n container.appendChild(controls.createButton.call(this, 'mute'));\n }\n\n // Volume range control\n if (this.config.controls.includes('volume')) {\n const volume = utils.createElement('span', {\n class: 'plyr__volume',\n });\n\n // Set the attributes\n const attributes = {\n max: 1,\n step: 0.05,\n value: this.config.volume,\n };\n\n // Create the volume range slider\n const range = controls.createRange.call(\n this,\n 'volume',\n utils.extend(attributes, {\n id: `plyr-volume-${data.id}`,\n })\n );\n volume.appendChild(range.label);\n volume.appendChild(range.input);\n\n container.appendChild(volume);\n }\n\n // Toggle captions button\n if (this.config.controls.includes('captions')) {\n container.appendChild(controls.createButton.call(this, 'captions'));\n }\n\n // Settings button / menu\n if (this.config.controls.includes('settings') && !utils.is.empty(this.config.settings)) {\n const menu = utils.createElement('div', {\n class: 'plyr__menu',\n });\n\n menu.appendChild(\n controls.createButton.call(this, 'settings', {\n id: `plyr-settings-toggle-${data.id}`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}`,\n 'aria-expanded': false,\n })\n );\n\n const form = utils.createElement('form', {\n class: 'plyr__menu__container',\n id: `plyr-settings-${data.id}`,\n 'aria-hidden': true,\n 'aria-labelled-by': `plyr-settings-toggle-${data.id}`,\n role: 'tablist',\n tabindex: -1,\n });\n\n const inner = utils.createElement('div');\n\n const home = utils.createElement('div', {\n id: `plyr-settings-${data.id}-home`,\n 'aria-hidden': false,\n 'aria-labelled-by': `plyr-settings-toggle-${data.id}`,\n role: 'tabpanel',\n });\n\n // Create the tab list\n const tabs = utils.createElement('ul', {\n role: 'tablist',\n });\n\n // Build the tabs\n this.config.settings.forEach(type => {\n const tab = utils.createElement('li', {\n role: 'tab',\n hidden: '',\n });\n\n const button = utils.createElement(\n 'button',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.buttons.settings), {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--forward`,\n id: `plyr-settings-${data.id}-${type}-tab`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}-${type}`,\n 'aria-expanded': false,\n }),\n this.config.i18n[type]\n );\n\n const value = utils.createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n // Speed contains HTML entities\n value.innerHTML = data[type];\n\n button.appendChild(value);\n tab.appendChild(button);\n tabs.appendChild(tab);\n\n this.elements.settings.tabs[type] = tab;\n });\n\n home.appendChild(tabs);\n inner.appendChild(home);\n\n // Build the panes\n this.config.settings.forEach(type => {\n const pane = utils.createElement('div', {\n id: `plyr-settings-${data.id}-${type}`,\n 'aria-hidden': true,\n 'aria-labelled-by': `plyr-settings-${data.id}-${type}-tab`,\n role: 'tabpanel',\n tabindex: -1,\n hidden: '',\n });\n\n const back = utils.createElement(\n 'button',\n {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--back`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}-home`,\n 'aria-expanded': false,\n },\n this.config.i18n[type]\n );\n\n pane.appendChild(back);\n\n const options = utils.createElement('ul');\n\n pane.appendChild(options);\n inner.appendChild(pane);\n\n this.elements.settings.panes[type] = pane;\n });\n\n form.appendChild(inner);\n menu.appendChild(form);\n container.appendChild(menu);\n\n this.elements.settings.form = form;\n this.elements.settings.menu = menu;\n }\n\n // Picture in picture button\n if (this.config.controls.includes('pip') && support.pip) {\n container.appendChild(controls.createButton.call(this, 'pip'));\n }\n\n // Airplay button\n if (this.config.controls.includes('airplay') && support.airplay) {\n container.appendChild(controls.createButton.call(this, 'airplay'));\n }\n\n // Toggle fullscreen button\n if (this.config.controls.includes('fullscreen')) {\n container.appendChild(controls.createButton.call(this, 'fullscreen'));\n }\n\n // Larger overlaid play button\n if (this.config.controls.includes('play-large')) {\n this.elements.container.appendChild(controls.createButton.call(this, 'play-large'));\n }\n\n this.elements.controls = container;\n\n if (this.config.controls.includes('settings') && this.config.settings.includes('speed')) {\n controls.setSpeedMenu.call(this);\n }\n\n return container;\n },\n\n // Insert controls\n inject() {\n // Sprite\n if (this.config.loadSprite) {\n const icon = controls.getIconUrl.call(this);\n\n // Only load external sprite using AJAX\n if (icon.absolute) {\n utils.loadSprite(icon.url, 'sprite-plyr');\n }\n }\n\n // Create a unique ID\n this.id = Math.floor(Math.random() * 10000);\n\n // Null by default\n let container = null;\n\n // HTML passed as the option\n if (utils.is.string(this.config.controls)) {\n container = this.config.controls;\n } else if (utils.is.function(this.config.controls)) {\n // A custom function to build controls\n // The function can return a HTMLElement or String\n container = this.config.controls({\n id: this.id,\n seektime: this.config.seekTime,\n title: this.config.title,\n });\n } else {\n // Create controls\n container = controls.create.call(this, {\n id: this.id,\n seektime: this.config.seekTime,\n speed: this.speed,\n quality: this.quality,\n captions: controls.getLanguage.call(this),\n // TODO: Looping\n // loop: 'None',\n });\n }\n\n // Controls container\n let target;\n\n // Inject to custom location\n if (utils.is.string(this.config.selectors.controls.container)) {\n target = document.querySelector(this.config.selectors.controls.container);\n }\n\n // Inject into the container by default\n if (!utils.is.htmlElement(target)) {\n target = this.elements.container;\n }\n\n // Inject controls HTML\n if (utils.is.htmlElement(container)) {\n target.appendChild(container);\n } else {\n target.insertAdjacentHTML('beforeend', container);\n }\n\n // Find the elements if need be\n if (utils.is.htmlElement(this.elements.controls)) {\n utils.findElements.call(this);\n }\n\n // Setup tooltips\n if (this.config.tooltips.controls) {\n const labels = utils.getElements.call(\n this,\n [\n this.config.selectors.controls.wrapper,\n ' ',\n this.config.selectors.labels,\n ' .',\n this.config.classNames.hidden,\n ].join('')\n );\n\n Array.from(labels).forEach(label => {\n utils.toggleClass(label, this.config.classNames.hidden, false);\n utils.toggleClass(label, this.config.classNames.tooltip, true);\n });\n }\n },\n};\n\nexport default controls;\n","// ==========================================================================\n// Plyr Captions\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport controls from './controls';\nimport storage from './storage';\n\nconst captions = {\n // Setup captions\n setup() {\n // Requires UI support\n if (!this.supported.ui) {\n return;\n }\n\n // Set default language if not set\n if (!utils.is.empty(storage.get.call(this).language)) {\n this.captions.language = storage.get.call(this).language;\n } else if (utils.is.empty(this.captions.language)) {\n this.captions.language = this.config.captions.language.toLowerCase();\n }\n\n // Set captions enabled state if not set\n if (!utils.is.boolean(this.captions.enabled)) {\n if (!utils.is.empty(storage.get.call(this).language)) {\n this.captions.enabled = storage.get.call(this).captions;\n } else {\n this.captions.enabled = this.config.captions.active;\n }\n }\n\n // Only Vimeo and HTML5 video supported at this point\n if (!['video', 'vimeo'].includes(this.type) || (this.type === 'video' && !support.textTracks)) {\n this.captions.tracks = null;\n\n // Clear menu and hide\n if (this.config.controls.includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n\n return;\n }\n\n // Inject the container\n if (!utils.is.htmlElement(this.elements.captions)) {\n this.elements.captions = utils.createElement(\n 'div',\n utils.getAttributesFromSelector(this.config.selectors.captions)\n );\n utils.insertAfter(this.elements.captions, this.elements.wrapper);\n }\n\n // Get tracks from HTML5\n if (this.type === 'video') {\n this.captions.tracks = this.media.textTracks;\n }\n\n // Set the class hook\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.captions.enabled,\n !utils.is.empty(this.captions.tracks)\n );\n\n // If no caption file exists, hide container for caption text\n if (utils.is.empty(this.captions.tracks)) {\n return;\n }\n\n // Enable UI\n captions.show.call(this);\n\n // Get a track\n const setCurrentTrack = () => {\n // Reset by default\n this.captions.currentTrack = null;\n\n // Filter doesn't seem to work for a TextTrackList :-(\n Array.from(this.captions.tracks).forEach(track => {\n if (track.language === this.captions.language.toLowerCase()) {\n this.captions.currentTrack = track;\n }\n });\n };\n\n // Get current track\n setCurrentTrack();\n\n // If we couldn't get the requested language, revert to default\n if (!utils.is.track(this.captions.currentTrack)) {\n const { language } = this.config.captions;\n\n // Reset to default\n // We don't update user storage as the selected language could become available\n this.captions.language = language;\n\n // Get fallback track\n setCurrentTrack();\n\n // If no match, disable captions\n if (!utils.is.track(this.captions.currentTrack)) {\n this.toggleCaptions(false);\n }\n\n controls.updateSetting.call(this, 'captions');\n }\n\n // Setup HTML5 track rendering\n if (this.type === 'video') {\n // Turn off native caption rendering to avoid double captions\n Array.from(this.captions.tracks).forEach(track => {\n // Remove previous bindings (if we've changed source or language)\n utils.off(track, 'cuechange', event => captions.setCue.call(this, event));\n\n // Hide captions\n // eslint-disable-next-line\n track.mode = 'hidden';\n });\n\n // Check if suported kind\n const supported =\n this.captions.currentTrack && ['captions', 'subtitles'].includes(this.captions.currentTrack.kind);\n\n if (utils.is.track(this.captions.currentTrack) && supported) {\n utils.on(this.captions.currentTrack, 'cuechange', event => captions.setCue.call(this, event));\n\n // If we change the active track while a cue is already displayed we need to update it\n if (this.captions.currentTrack.activeCues && this.captions.currentTrack.activeCues.length > 0) {\n captions.setCue.call(this, this.captions.currentTrack);\n }\n }\n } else if (this.type === 'vimeo' && this.captions.active) {\n this.embed.enableTextTrack(this.captions.language);\n }\n\n // Set available languages in list\n if (this.config.controls.includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n },\n\n // Display active caption if it contains text\n setCue(input) {\n // Get the track from the event if needed\n const track = utils.is.event(input) ? input.target : input;\n const active = track.activeCues[0];\n\n // Display a cue, if there is one\n if (utils.is.cue(active)) {\n captions.set.call(this, active.getCueAsHTML());\n } else {\n captions.set.call(this);\n }\n\n utils.dispatchEvent.call(this, this.media, 'cuechange');\n },\n\n // Set the current caption\n set(input) {\n // Requires UI\n if (!this.supported.ui) {\n return;\n }\n\n if (utils.is.htmlElement(this.elements.captions)) {\n const content = utils.createElement('span');\n\n // Empty the container\n utils.emptyElement(this.elements.captions);\n\n // Default to empty\n const caption = !utils.is.undefined(input) ? input : '';\n\n // Set the span content\n if (utils.is.string(caption)) {\n content.textContent = caption.trim();\n } else {\n content.appendChild(caption);\n }\n\n // Set new caption text\n this.elements.captions.appendChild(content);\n } else {\n this.console.warn('No captions element to render to');\n }\n },\n\n // Display captions container and button (for initialization)\n show() {\n // If there's no caption toggle, bail\n if (!utils.is.htmlElement(this.elements.buttons.captions)) {\n return;\n }\n\n // Try to load the value from storage\n let active = storage.get.call(this).captions;\n\n // Otherwise fall back to the default config\n if (!utils.is.boolean(active)) {\n ({ active } = this.config.captions);\n } else {\n this.captions.active = active;\n }\n\n if (active) {\n utils.toggleClass(this.elements.container, this.config.classNames.captions.active, true);\n utils.toggleState(this.elements.buttons.captions, true);\n }\n },\n};\n\nexport default captions;\n","// ==========================================================================\n// YouTube plugin\n// ==========================================================================\n\nimport utils from './../utils';\nimport controls from './../controls';\nimport ui from './../ui';\n\nconst youtube = {\n setup() {\n const videoId = utils.parseYouTubeId(this.embedId);\n\n // Remove old containers\n const containers = utils.getElements.call(this, `[id^=\"${this.type}-\"]`);\n Array.from(containers).forEach(utils.removeElement);\n\n // Add embed class for responsive\n utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true);\n\n // Set aspect ratio\n youtube.setAspectRatio.call(this);\n\n // Set ID\n this.media.setAttribute('id', utils.generateId(this.type));\n\n // Get the title\n const key = 'AIzaSyDrNwtN3nLH_8rjCmu5Wq3ZCm4MNAVdc0c';\n const url = `https://www.googleapis.com/youtube/v3/videos?id=${videoId}&fields=items(snippet(title))&part=snippet&key=${key}`;\n\n fetch(url)\n .then(response => response.json())\n .then(obj => {\n if (utils.is.object(obj)) {\n this.config.title = obj.items[0].snippet.title;\n ui.setTitle.call(this);\n }\n })\n .catch(() => {});\n\n // Setup API\n if (utils.is.object(window.YT)) {\n youtube.ready.call(this, videoId);\n } else {\n // Load the API\n utils.loadScript(this.config.urls.youtube.api);\n\n // Setup callback for the API\n window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];\n\n // Add to queue\n window.onYouTubeReadyCallbacks.push(() => {\n youtube.ready.call(this, videoId);\n });\n\n // Set callback to process queue\n window.onYouTubeIframeAPIReady = () => {\n window.onYouTubeReadyCallbacks.forEach(callback => {\n callback();\n });\n };\n }\n },\n\n // Set aspect ratio\n setAspectRatio() {\n const ratio = this.config.ratio.split(':');\n this.elements.wrapper.style.paddingBottom = `${100 / ratio[0] * ratio[1]}%`;\n },\n\n // API ready\n ready(videoId) {\n const player = this;\n\n // Setup instance\n // https://developers.google.com/youtube/iframe_api_reference\n player.embed = new window.YT.Player(player.media.id, {\n videoId,\n playerVars: {\n autoplay: player.config.autoplay ? 1 : 0, // Autoplay\n controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported\n rel: 0, // No related vids\n showinfo: 0, // Hide info\n iv_load_policy: 3, // Hide annotations\n modestbranding: 1, // Hide logos as much as possible (they still show one in the corner when paused)\n disablekb: 1, // Disable keyboard as we handle it\n playsinline: 1, // Allow iOS inline playback\n\n // Tracking for stats\n origin: window && window.location.hostname,\n widget_referrer: window && window.location.href,\n\n // Captions are flaky on YouTube\n cc_load_policy: this.captions.active ? 1 : 0,\n cc_lang_pref: this.config.captions.language,\n },\n events: {\n onError(event) {\n // If we've already fired an error, don't do it again\n // YouTube fires onError twice\n if (utils.is.object(player.media.error)) {\n return;\n }\n\n const detail = {\n code: event.data,\n };\n\n // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError\n switch (event.data) {\n case 2:\n detail.message =\n 'The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.';\n break;\n\n case 5:\n detail.message =\n 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.';\n break;\n\n case 100:\n detail.message =\n 'The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.';\n break;\n\n case 101:\n case 150:\n detail.message =\n 'The owner of the requested video does not allow it to be played in embedded players.';\n break;\n\n default:\n detail.message = 'An unknown error occured';\n break;\n }\n\n player.media.error = detail;\n\n utils.dispatchEvent.call(player, player.media, 'error');\n },\n onPlaybackQualityChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Get current quality\n player.media.quality = instance.getPlaybackQuality();\n\n utils.dispatchEvent.call(player, player.media, 'qualitychange');\n },\n onPlaybackRateChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Get current speed\n player.media.playbackRate = instance.getPlaybackRate();\n\n utils.dispatchEvent.call(player, player.media, 'ratechange');\n },\n onReady(event) {\n // Get the instance\n const instance = event.target;\n\n // Create a faux HTML5 API using the YouTube API\n player.media.play = () => {\n instance.playVideo();\n player.media.paused = false;\n };\n player.media.pause = () => {\n instance.pauseVideo();\n player.media.paused = true;\n };\n player.media.stop = () => {\n instance.stopVideo();\n player.media.paused = true;\n };\n player.media.duration = instance.getDuration();\n player.media.paused = true;\n\n // Seeking\n player.media.currentTime = 0;\n Object.defineProperty(player.media, 'currentTime', {\n get() {\n return Number(instance.getCurrentTime());\n },\n set(time) {\n // Set seeking flag\n player.media.seeking = true;\n\n // Trigger seeking\n utils.dispatchEvent.call(player, player.media, 'seeking');\n\n // Seek after events sent\n instance.seekTo(time);\n },\n });\n\n // Playback speed\n Object.defineProperty(player.media, 'playbackRate', {\n get() {\n return instance.getPlaybackRate();\n },\n set(input) {\n instance.setPlaybackRate(input);\n },\n });\n\n // Quality\n Object.defineProperty(player.media, 'quality', {\n get() {\n return instance.getPlaybackQuality();\n },\n set(input) {\n // Trigger request event\n utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {\n quality: input,\n });\n\n instance.setPlaybackQuality(input);\n },\n });\n\n // Volume\n let { volume } = player.config;\n Object.defineProperty(player.media, 'volume', {\n get() {\n return volume;\n },\n set(input) {\n volume = input;\n instance.setVolume(volume * 100);\n utils.dispatchEvent.call(player, player.media, 'volumechange');\n },\n });\n\n // Muted\n let { muted } = player.config;\n Object.defineProperty(player.media, 'muted', {\n get() {\n return muted;\n },\n set(input) {\n const toggle = utils.is.boolean(input) ? input : muted;\n muted = toggle;\n instance[toggle ? 'mute' : 'unMute']();\n utils.dispatchEvent.call(player, player.media, 'volumechange');\n },\n });\n\n // Source\n Object.defineProperty(player.media, 'currentSrc', {\n get() {\n return instance.getVideoUrl();\n },\n });\n\n // Get available speeds\n if (player.config.controls.includes('settings') && player.config.settings.includes('speed')) {\n controls.setSpeedMenu.call(player, instance.getAvailablePlaybackRates());\n }\n\n // Set title\n if (utils.is.function(instance.getVideoData)) {\n player.config.title = instance.getVideoData().title;\n }\n\n // Set the tabindex to avoid focus entering iframe\n if (player.supported.ui) {\n player.media.setAttribute('tabindex', -1);\n }\n\n utils.dispatchEvent.call(player, player.media, 'timeupdate');\n utils.dispatchEvent.call(player, player.media, 'durationchange');\n\n // Reset timer\n window.clearInterval(player.timers.buffering);\n\n // Setup buffering\n player.timers.buffering = window.setInterval(() => {\n // Get loaded % from YouTube\n player.media.buffered = instance.getVideoLoadedFraction();\n\n // Trigger progress only when we actually buffer something\n if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {\n utils.dispatchEvent.call(player, player.media, 'progress');\n }\n\n // Set last buffer point\n player.media.lastBuffered = player.media.buffered;\n\n // Bail if we're at 100%\n if (player.media.buffered === 1) {\n window.clearInterval(player.timers.buffering);\n\n // Trigger event\n utils.dispatchEvent.call(player, player.media, 'canplaythrough');\n }\n }, 200);\n\n // Rebuild UI\n window.setTimeout(() => ui.build.call(player), 50);\n },\n onStateChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Reset timer\n window.clearInterval(player.timers.playing);\n\n // Handle events\n // -1 Unstarted\n // 0 Ended\n // 1 Playing\n // 2 Paused\n // 3 Buffering\n // 5 Video cued\n switch (event.data) {\n case 0:\n // YouTube doesn't support loop for a single video, so mimick it.\n if (player.media.loop) {\n // YouTube needs a call to `stopVideo` before playing again\n instance.stopVideo();\n instance.playVideo();\n } else {\n utils.dispatchEvent.call(player, player.media, 'ended');\n player.media.paused = true;\n }\n\n break;\n\n case 1:\n player.media.paused = false;\n\n // If we were seeking, fire seeked event\n if (player.media.seeking) {\n utils.dispatchEvent.call(player, player.media, 'seeked');\n }\n\n player.media.seeking = false;\n\n utils.dispatchEvent.call(player, player.media, 'play');\n utils.dispatchEvent.call(player, player.media, 'playing');\n\n // Poll to get playback progress\n player.timers.playing = window.setInterval(() => {\n utils.dispatchEvent.call(player, player.media, 'timeupdate');\n }, 50);\n\n // Check duration again due to YouTube bug\n // https://github.com/sampotts/plyr/issues/374\n // https://code.google.com/p/gdata-issues/issues/detail?id=8690\n if (player.media.duration !== instance.getDuration()) {\n player.media.duration = instance.getDuration();\n utils.dispatchEvent.call(player, player.media, 'durationchange');\n }\n\n // Get quality\n controls.setQualityMenu.call(player, instance.getAvailableQualityLevels());\n\n break;\n\n case 2:\n player.media.paused = true;\n\n utils.dispatchEvent.call(player, player.media, 'pause');\n\n break;\n\n default:\n break;\n }\n\n utils.dispatchEvent.call(player, player.elements.container, 'statechange', false, {\n code: event.data,\n });\n },\n },\n });\n },\n};\n\nexport default youtube;\n","// ==========================================================================\n// Vimeo plugin\n// ==========================================================================\n\nimport utils from './../utils';\nimport captions from './../captions';\nimport controls from './../controls';\nimport ui from './../ui';\n\nconst vimeo = {\n setup() {\n // Remove old containers\n const containers = utils.getElements.call(this, `[id^=\"${this.type}-\"]`);\n Array.from(containers).forEach(utils.removeElement);\n\n // Add embed class for responsive\n utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true);\n\n // Set intial ratio\n vimeo.setAspectRatio.call(this);\n\n // Set ID\n this.media.setAttribute('id', utils.generateId(this.type));\n\n // Load the API if not already\n if (!utils.is.object(window.Vimeo)) {\n utils.loadScript(this.config.urls.vimeo.api, () => {\n vimeo.ready.call(this);\n });\n } else {\n vimeo.ready.call(this);\n }\n },\n\n // Set aspect ratio\n // For Vimeo we have an extra 300% height <div> to hide the standard controls and UI\n setAspectRatio(input) {\n const ratio = utils.is.string(input) ? input.split(':') : this.config.ratio.split(':');\n const padding = 100 / ratio[0] * ratio[1];\n const height = 200;\n const offset = (height - padding) / (height / 50);\n this.elements.wrapper.style.paddingBottom = `${padding}%`;\n this.media.style.transform = `translateY(-${offset}%)`;\n },\n\n // API Ready\n ready() {\n const player = this;\n\n // Get Vimeo params for the iframe\n const options = {\n loop: player.config.loop.active,\n autoplay: player.autoplay,\n byline: false,\n portrait: false,\n title: false,\n speed: true,\n transparent: 0,\n gesture: 'media',\n };\n const params = utils.buildUrlParameters(options);\n const id = utils.parseVimeoId(player.embedId);\n\n // Build an iframe\n const iframe = utils.createElement('iframe');\n const src = `https://player.vimeo.com/video/${id}?${params}`;\n iframe.setAttribute('src', src);\n iframe.setAttribute('allowfullscreen', '');\n player.media.appendChild(iframe);\n\n // Setup instance\n // https://github.com/vimeo/player.js\n player.embed = new window.Vimeo.Player(iframe);\n\n player.media.paused = true;\n player.media.currentTime = 0;\n\n // Create a faux HTML5 API using the Vimeo API\n player.media.play = () => {\n player.embed.play().then(() => {\n player.media.paused = false;\n });\n };\n player.media.pause = () => {\n player.embed.pause().then(() => {\n player.media.paused = true;\n });\n };\n player.media.stop = () => {\n player.embed.stop().then(() => {\n player.media.paused = true;\n player.currentTime = 0;\n });\n };\n\n // Seeking\n let { currentTime } = player.media;\n Object.defineProperty(player.media, 'currentTime', {\n get() {\n return currentTime;\n },\n set(time) {\n // Get current paused state\n // Vimeo will automatically play on seek\n const { paused } = player.media;\n\n // Set seeking flag\n player.media.seeking = true;\n\n // Trigger seeking\n utils.dispatchEvent.call(player, player.media, 'seeking');\n\n // Seek after events\n player.embed.setCurrentTime(time);\n\n // Restore pause state\n if (paused) {\n player.pause();\n }\n },\n });\n\n // Playback speed\n let speed = player.config.speed.selected;\n Object.defineProperty(player.media, 'playbackRate', {\n get() {\n return speed;\n },\n set(input) {\n player.embed.setPlaybackRate(input).then(() => {\n speed = input;\n utils.dispatchEvent.call(player, player.media, 'ratechange');\n });\n },\n });\n\n // Volume\n let { volume } = player.config;\n Object.defineProperty(player.media, 'volume', {\n get() {\n return volume;\n },\n set(input) {\n player.embed.setVolume(input).then(() => {\n volume = input;\n utils.dispatchEvent.call(player, player.media, 'volumechange');\n });\n },\n });\n\n // Muted\n let { muted } = player.config;\n Object.defineProperty(player.media, 'muted', {\n get() {\n return muted;\n },\n set(input) {\n const toggle = utils.is.boolean(input) ? input : false;\n\n player.embed.setVolume(toggle ? 0 : player.config.volume).then(() => {\n muted = toggle;\n utils.dispatchEvent.call(player, player.media, 'volumechange');\n });\n },\n });\n\n // Loop\n let { loop } = player.config;\n Object.defineProperty(player.media, 'loop', {\n get() {\n return loop;\n },\n set(input) {\n const toggle = utils.is.boolean(input) ? input : player.config.loop.active;\n\n player.embed.setLoop(toggle).then(() => {\n loop = toggle;\n });\n },\n });\n\n // Source\n let currentSrc;\n player.embed.getVideoUrl().then(value => {\n currentSrc = value;\n });\n Object.defineProperty(player.media, 'currentSrc', {\n get() {\n return currentSrc;\n },\n });\n\n // Set aspect ratio based on video size\n Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then(dimensions => {\n const ratio = utils.getAspectRatio(dimensions[0], dimensions[1]);\n vimeo.setAspectRatio.call(this, ratio);\n });\n\n // Get available speeds\n if (player.config.controls.includes('settings') && player.config.settings.includes('speed')) {\n controls.setSpeedMenu.call(player);\n }\n\n // Get title\n player.embed.getVideoTitle().then(title => {\n player.config.title = title;\n ui.setTitle.call(this);\n });\n\n // Get current time\n player.embed.getCurrentTime().then(value => {\n currentTime = value;\n utils.dispatchEvent.call(player, player.media, 'timeupdate');\n });\n\n // Get duration\n player.embed.getDuration().then(value => {\n player.media.duration = value;\n utils.dispatchEvent.call(player, player.media, 'durationchange');\n });\n\n // Get captions\n player.embed.getTextTracks().then(tracks => {\n player.captions.tracks = tracks;\n captions.setup.call(player);\n });\n\n player.embed.on('cuechange', data => {\n let cue = null;\n\n if (data.cues.length) {\n cue = utils.stripHTML(data.cues[0].text);\n }\n\n captions.set.call(player, cue);\n });\n\n player.embed.on('loaded', () => {\n if (utils.is.htmlElement(player.embed.element) && player.supported.ui) {\n const frame = player.embed.element;\n\n // Fix keyboard focus issues\n // https://github.com/sampotts/plyr/issues/317\n frame.setAttribute('tabindex', -1);\n }\n });\n\n player.embed.on('play', () => {\n player.media.paused = false;\n utils.dispatchEvent.call(player, player.media, 'play');\n utils.dispatchEvent.call(player, player.media, 'playing');\n });\n\n player.embed.on('pause', () => {\n player.media.paused = true;\n utils.dispatchEvent.call(player, player.media, 'pause');\n });\n\n player.embed.on('timeupdate', data => {\n player.media.seeking = false;\n currentTime = data.seconds;\n utils.dispatchEvent.call(player, player.media, 'timeupdate');\n });\n\n player.embed.on('progress', data => {\n player.media.buffered = data.percent;\n utils.dispatchEvent.call(player, player.media, 'progress');\n\n if (parseInt(data.percent, 10) === 1) {\n // Trigger event\n utils.dispatchEvent.call(player, player.media, 'canplaythrough');\n }\n });\n\n player.embed.on('seeked', () => {\n player.media.seeking = false;\n utils.dispatchEvent.call(player, player.media, 'seeked');\n utils.dispatchEvent.call(player, player.media, 'play');\n });\n\n player.embed.on('ended', () => {\n player.media.paused = true;\n utils.dispatchEvent.call(player, player.media, 'ended');\n });\n\n player.embed.on('error', detail => {\n player.media.error = detail;\n utils.dispatchEvent.call(player, player.media, 'error');\n });\n\n // Rebuild UI\n window.setTimeout(() => ui.build.call(player), 0);\n },\n};\n\nexport default vimeo;\n","// ==========================================================================\n// Plyr Media\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport youtube from './plugins/youtube';\nimport vimeo from './plugins/vimeo';\nimport ui from './ui';\n\n// Sniff out the browser\nconst browser = utils.getBrowser();\n\nconst media = {\n // Setup media\n setup() {\n // If there's no media, bail\n if (!this.media) {\n this.console.warn('No media element found!');\n return;\n }\n\n // Add type class\n utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', this.type), true);\n\n // Add video class for embeds\n // This will require changes if audio embeds are added\n if (this.isEmbed) {\n utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', 'video'), true);\n }\n\n if (this.supported.ui) {\n // Check for picture-in-picture support\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.pip.supported,\n support.pip && this.type === 'video'\n );\n\n // Check for airplay support\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.airplay.supported,\n support.airplay && this.isHTML5\n );\n\n // If there's no autoplay attribute, assume the video is stopped and add state class\n utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.config.autoplay);\n\n // Add iOS class\n utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos);\n\n // Add touch class\n utils.toggleClass(this.elements.container, this.config.classNames.isTouch, support.touch);\n }\n\n // Inject the player wrapper\n if (['video', 'youtube', 'vimeo'].includes(this.type)) {\n // Create the wrapper div\n this.elements.wrapper = utils.createElement('div', {\n class: this.config.classNames.video,\n });\n\n // Wrap the video in a container\n utils.wrap(this.media, this.elements.wrapper);\n }\n\n if (this.isEmbed) {\n switch (this.type) {\n case 'youtube':\n youtube.setup.call(this);\n break;\n\n case 'vimeo':\n vimeo.setup.call(this);\n break;\n\n default:\n break;\n }\n } else {\n ui.setTitle.call(this);\n }\n },\n\n // Cancel current network requests\n // See https://github.com/sampotts/plyr/issues/174\n cancelRequests() {\n if (!this.isHTML5) {\n return;\n }\n\n // Remove child sources\n Array.from(this.media.querySelectorAll('source')).forEach(utils.removeElement);\n\n // Set blank video src attribute\n // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error\n // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection\n this.media.setAttribute('src', this.config.blankVideo);\n\n // Load the new empty source\n // This will cancel existing requests\n // See https://github.com/sampotts/plyr/issues/174\n this.media.load();\n\n // Debugging\n this.console.log('Cancelled network requests');\n },\n};\n\nexport default media;\n","// ==========================================================================\n// Plyr source update\n// ==========================================================================\n\nimport types from './types';\nimport utils from './utils';\nimport media from './media';\nimport ui from './ui';\nimport support from './support';\n\nconst source = {\n // Add elements to HTML5 media (source, tracks, etc)\n insertElements(type, attributes) {\n if (utils.is.string(attributes)) {\n utils.insertElement(type, this.media, {\n src: attributes,\n });\n } else if (utils.is.array(attributes)) {\n attributes.forEach(attribute => {\n utils.insertElement(type, this.media, attribute);\n });\n }\n },\n\n // Update source\n // Sources are not checked for support so be careful\n change(input) {\n if (!utils.is.object(input) || !('sources' in input) || !input.sources.length) {\n this.console.warn('Invalid source format');\n return;\n }\n\n // Cancel current network requests\n media.cancelRequests.call(this);\n\n // Destroy instance and re-setup\n this.destroy.call(\n this,\n () => {\n // TODO: Reset menus here\n\n // Remove elements\n utils.removeElement(this.media);\n this.media = null;\n\n // Reset class name\n if (utils.is.htmlElement(this.elements.container)) {\n this.elements.container.removeAttribute('class');\n }\n\n // Set the type\n if ('type' in input) {\n this.type = input.type;\n\n // Get child type for video (it might be an embed)\n if (this.type === 'video') {\n const firstSource = input.sources[0];\n\n if ('type' in firstSource && types.embed.includes(firstSource.type)) {\n this.type = firstSource.type;\n }\n }\n }\n\n // Check for support\n this.supported = support.check(this.type, this.config.inline);\n\n // Create new markup\n switch (this.type) {\n case 'video':\n this.media = utils.createElement('video');\n break;\n\n case 'audio':\n this.media = utils.createElement('audio');\n break;\n\n case 'youtube':\n case 'vimeo':\n this.media = utils.createElement('div');\n this.embedId = input.sources[0].src;\n break;\n\n default:\n break;\n }\n\n // Inject the new element\n this.elements.container.appendChild(this.media);\n\n // Autoplay the new source?\n if (utils.is.boolean(input.autoplay)) {\n this.config.autoplay = input.autoplay;\n }\n\n // Set attributes for audio and video\n if (this.isHTML5) {\n if (this.config.crossorigin) {\n this.media.setAttribute('crossorigin', '');\n }\n if (this.config.autoplay) {\n this.media.setAttribute('autoplay', '');\n }\n if ('poster' in input) {\n this.media.setAttribute('poster', input.poster);\n }\n if (this.config.loop.active) {\n this.media.setAttribute('loop', '');\n }\n if (this.config.muted) {\n this.media.setAttribute('muted', '');\n }\n if (this.config.inline) {\n this.media.setAttribute('playsinline', '');\n }\n }\n\n // Restore class hooks\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.captions.active,\n this.supported.ui && this.captions.enabled\n );\n\n ui.addStyleHook.call(this);\n\n // Set new sources for html5\n if (this.isHTML5) {\n source.insertElements.call(this, 'source', input.sources);\n }\n\n // Set video title\n this.config.title = input.title;\n\n // Set up from scratch\n media.setup.call(this);\n\n // HTML5 stuff\n if (this.isHTML5) {\n // Setup captions\n if ('tracks' in input) {\n source.insertElements.call(this, 'track', input.tracks);\n }\n\n // Load HTML5 sources\n this.media.load();\n }\n\n // If HTML5 or embed but not fully supported, setupInterface and call ready now\n if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) {\n // Setup interface\n ui.build.call(this);\n }\n },\n true\n );\n },\n};\n\nexport default source;\n","// ==========================================================================\n// Plyr\n// plyr.js v3.0.0\n// https://github.com/sampotts/plyr\n// License: The MIT License (MIT)\n// ==========================================================================\n\nimport defaults from './defaults';\nimport types from './types';\nimport support from './support';\nimport utils from './utils';\n\nimport captions from './captions';\nimport controls from './controls';\nimport fullscreen from './fullscreen';\nimport listeners from './listeners';\nimport media from './media';\nimport storage from './storage';\nimport source from './source';\nimport ui from './ui';\n\n// Globals\nlet scrollPosition = {\n x: 0,\n y: 0,\n};\n\n// Plyr instance\nclass Plyr {\n constructor(target, options) {\n this.timers = {};\n this.ready = false;\n\n // Set the media element\n this.media = target;\n\n // String selector passed\n if (utils.is.string(this.media)) {\n this.media = document.querySelectorAll(this.media);\n }\n\n // jQuery, NodeList or Array passed, use first element\n if (\n (window.jQuery && this.media instanceof jQuery) ||\n utils.is.nodeList(this.media) ||\n utils.is.array(this.media)\n ) {\n // eslint-disable-next-line\n this.media = this.media[0];\n }\n\n // Set config\n this.config = utils.extend(\n {},\n defaults,\n options,\n (() => {\n try {\n return JSON.parse(this.media.getAttribute('data-plyr'));\n } catch (e) {\n return null;\n }\n })()\n );\n\n // Elements cache\n this.elements = {\n container: null,\n buttons: {},\n display: {},\n progress: {},\n inputs: {},\n settings: {\n menu: null,\n panes: {},\n tabs: {},\n },\n captions: null,\n };\n\n // Captions\n this.captions = {\n enabled: null,\n tracks: null,\n currentTrack: null,\n };\n\n // Fullscreen\n this.fullscreen = {\n active: false,\n };\n\n // Options\n this.options = {\n speed: [],\n quality: [],\n };\n\n // Debugging\n this.console = {\n log() {},\n warn() {},\n error() {},\n };\n if (this.config.debug && 'console' in window) {\n this.console = {\n log: console.log, // eslint-disable-line\n warn: console.warn, // eslint-disable-line\n error: console.error, // eslint-disable-line\n };\n this.console.log('Debugging enabled');\n }\n\n // Log config options and support\n this.console.log('Config', this.config);\n this.console.log('Support', support);\n\n // We need an element to setup\n if (this.media === null || utils.is.undefined(this.media) || !utils.is.htmlElement(this.media)) {\n this.console.error('Setup failed: no suitable element passed');\n return;\n }\n\n // Bail if the element is initialized\n if (this.media.plyr) {\n this.console.warn('Target already setup');\n return;\n }\n\n // Bail if not enabled\n if (!this.config.enabled) {\n this.console.error('Setup failed: disabled by config');\n return;\n }\n\n // Bail if disabled or no basic support\n // You may want to disable certain UAs etc\n if (!support.check().api) {\n this.console.error('Setup failed: no support');\n return;\n }\n\n // Cache original element state for .destroy()\n this.elements.original = this.media.cloneNode(true);\n\n // Set media type based on tag or data attribute\n // Supported: video, audio, vimeo, youtube\n const type = this.media.tagName.toLowerCase();\n\n // Different setup based on type\n switch (type) {\n // TODO: Handle passing an iframe for true progressive enhancement\n // case 'iframe':\n case 'div':\n this.type = this.media.getAttribute('data-type');\n this.embedId = this.media.getAttribute('data-video-id');\n\n if (utils.is.empty(this.type)) {\n this.console.error('Setup failed: embed type missing');\n return;\n }\n\n if (utils.is.empty(this.embedId)) {\n this.console.error('Setup failed: video id missing');\n return;\n }\n\n // Clean up\n this.media.removeAttribute('data-type');\n this.media.removeAttribute('data-video-id');\n break;\n\n case 'video':\n case 'audio':\n this.type = type;\n\n if (this.media.hasAttribute('crossorigin')) {\n this.config.crossorigin = true;\n }\n if (this.media.hasAttribute('autoplay')) {\n this.config.autoplay = true;\n }\n if (this.media.hasAttribute('playsinline')) {\n this.config.inline = true;\n }\n if (this.media.hasAttribute('muted')) {\n this.config.muted = true;\n }\n if (this.media.hasAttribute('loop')) {\n this.config.loop.active = true;\n }\n\n break;\n\n default:\n this.console.error('Setup failed: unsupported type');\n return;\n }\n\n // Setup local storage for user settings\n storage.setup.call(this);\n\n // Check for support again but with type\n this.supported = support.check(this.type, this.config.inline);\n\n // If no support for even API, bail\n if (!this.supported.api) {\n this.console.error('Setup failed: no support');\n return;\n }\n\n // Store reference\n this.media.plyr = this;\n\n // Wrap media\n this.elements.container = utils.createElement('div');\n utils.wrap(this.media, this.elements.container);\n\n // Allow focus to be captured\n this.elements.container.setAttribute('tabindex', 0);\n\n // Global listeners\n listeners.global.call(this);\n\n // Add style hook\n ui.addStyleHook.call(this);\n\n // Setup media\n media.setup.call(this);\n\n // Listen for events if debugging\n if (this.config.debug) {\n utils.on(this.elements.container, this.config.events.join(' '), event => {\n this.console.log(`event: ${event.type}`);\n });\n }\n\n // Setup interface\n // If embed but not fully supported, build interface now to avoid flash of controls\n if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) {\n ui.build.call(this);\n }\n }\n\n // ---------------------------------------\n // API\n // ---------------------------------------\n\n /**\n * If the player is HTML5\n */\n get isHTML5() {\n return types.html5.includes(this.type);\n }\n\n /**\n * If the player is an embed - e.g. YouTube or Vimeo\n */\n get isEmbed() {\n return types.embed.includes(this.type);\n }\n\n /**\n * Play the media\n */\n play() {\n if ('play' in this.media) {\n this.media.play();\n }\n return this;\n }\n\n /**\n * Pause the media\n */\n pause() {\n if ('pause' in this.media) {\n this.media.pause();\n }\n return this;\n }\n\n get paused() {\n return this.media.paused;\n }\n\n /**\n * Toggle playback based on current status\n * @param {boolean} toggle\n */\n togglePlay(toggle) {\n // True toggle if nothing passed\n if ((!utils.is.boolean(toggle) && this.media.paused) || toggle) {\n return this.play();\n }\n\n return this.pause();\n }\n\n /**\n * Stop playback\n */\n stop() {\n return this.restart().pause();\n }\n\n /**\n * Restart playback\n */\n restart() {\n this.currentTime = 0;\n return this;\n }\n\n /**\n * Rewind\n * @param {number} seekTime - how far to rewind in seconds. Defaults to the config.seekTime\n */\n rewind(seekTime) {\n this.currentTime = this.currentTime - (utils.is.number(seekTime) ? seekTime : this.config.seekTime);\n return this;\n }\n\n /**\n * Fast forward\n * @param {number} seekTime - how far to fast forward in seconds. Defaults to the config.seekTime\n */\n forward(seekTime) {\n this.currentTime = this.currentTime + (utils.is.number(seekTime) ? seekTime : this.config.seekTime);\n return this;\n }\n\n /**\n * Seek to a time\n * @param {number} input - where to seek to in seconds. Defaults to 0 (the start)\n */\n set currentTime(input) {\n let targetTime = 0;\n\n if (utils.is.number(input)) {\n targetTime = input;\n }\n\n // Normalise targetTime\n if (targetTime < 0) {\n targetTime = 0;\n } else if (targetTime > this.duration) {\n targetTime = this.duration;\n }\n\n // Set\n this.media.currentTime = targetTime.toFixed(4);\n\n // Logging\n this.console.log(`Seeking to ${this.currentTime} seconds`);\n }\n\n get currentTime() {\n return Number(this.media.currentTime);\n }\n\n get seeking() {\n return this.media.seeking;\n }\n\n /**\n * Get the duration of the current media\n */\n get duration() {\n // Faux duration set via config\n const fauxDuration = parseInt(this.config.duration, 10);\n\n // True duration\n const realDuration = Number(this.media.duration);\n\n // If custom duration is funky, use regular duration\n return !Number.isNaN(fauxDuration) ? fauxDuration : realDuration;\n }\n\n /**\n * Set the player volume\n * @param {number} value - must be between 0 and 1. Defaults to the value from local storage and config.volume if not set in storage\n */\n set volume(value) {\n let volume = value;\n const max = 1;\n const min = 0;\n\n if (utils.is.string(volume)) {\n volume = Number(volume);\n }\n\n // Load volume from storage if no value specified\n if (!utils.is.number(volume)) {\n ({ volume } = storage.get.call(this));\n }\n\n // Use config if all else fails\n if (!utils.is.number(volume)) {\n ({ volume } = this.config);\n }\n\n // Maximum is volumeMax\n if (volume > max) {\n volume = max;\n }\n // Minimum is volumeMin\n if (volume < min) {\n volume = min;\n }\n\n // Update config\n this.config.volume = volume;\n\n // Set the player volume\n this.media.volume = volume;\n\n // If muted, and we're increasing volume, reset muted state\n if (this.muted && volume > 0) {\n this.muted = false;\n }\n }\n\n /**\n * Get the current player volume\n */\n get volume() {\n return this.media.volume;\n }\n\n // Increase volume\n increaseVolume(step) {\n const volume = this.media.muted ? 0 : this.volume;\n this.volume = volume + utils.is.number(step) ? step : 1;\n return this;\n }\n\n // Decrease volume\n decreaseVolume(step) {\n const volume = this.media.muted ? 0 : this.volume;\n this.volume = volume - utils.is.number(step) ? step : 1;\n return this;\n }\n\n // Toggle mute\n set muted(mute) {\n let toggle = mute;\n\n // Load muted state from storage\n if (!utils.is.boolean(toggle)) {\n toggle = storage.get.call(this).muted;\n }\n\n // Use config if all else fails\n if (!utils.is.boolean(toggle)) {\n toggle = this.config.muted;\n }\n\n // Update config\n this.config.muted = toggle;\n\n // Set mute on the player\n this.media.muted = toggle;\n }\n\n get muted() {\n return this.media.muted;\n }\n\n // Playback speed\n set speed(input) {\n let speed = null;\n\n if (utils.is.number(input)) {\n speed = input;\n } else if (utils.is.number(storage.get.call(this).speed)) {\n ({ speed } = storage.get.call(this));\n } else {\n speed = this.config.speed.selected;\n }\n\n // Set min/max\n if (speed < 0.1) {\n speed = 0.1;\n }\n if (speed > 2.0) {\n speed = 2.0;\n }\n\n if (!this.config.speed.options.includes(speed)) {\n this.console.warn(`Unsupported speed (${speed})`);\n return;\n }\n\n // Update config\n this.config.speed.selected = speed;\n\n // Set media speed\n this.media.playbackRate = speed;\n }\n\n get speed() {\n return this.media.playbackRate;\n }\n\n // Set playback quality\n set quality(input) {\n let quality = null;\n\n if (utils.is.string(input)) {\n quality = input;\n } else if (utils.is.number(storage.get.call(this).speed)) {\n ({ quality } = storage.get.call(this));\n } else {\n quality = this.config.quality.selected;\n }\n\n if (!this.options.quality.includes(quality)) {\n this.console.warn(`Unsupported quality option (${quality})`);\n return;\n }\n\n // Update config\n this.config.quality.selected = quality;\n\n // Set quality\n this.media.quality = quality;\n }\n\n get quality() {\n return this.media.quality;\n }\n\n // Toggle loop\n // TODO: Finish fancy new logic. Set the indicator on load as user may pass loop as config\n set loop(input) {\n const toggle = utils.is.boolean(input) ? input : this.config.loop.active;\n this.config.loop.active = toggle;\n this.media.loop = toggle;\n\n // Set default to be a true toggle\n /* const type = ['start', 'end', 'all', 'none', 'toggle'].includes(input) ? input : 'toggle';\n\n switch (type) {\n case 'start':\n if (this.config.loop.end && this.config.loop.end <= this.currentTime) {\n this.config.loop.end = null;\n }\n this.config.loop.start = this.currentTime;\n // this.config.loop.indicator.start = this.elements.display.played.value;\n break;\n\n case 'end':\n if (this.config.loop.start >= this.currentTime) {\n return this;\n }\n this.config.loop.end = this.currentTime;\n // this.config.loop.indicator.end = this.elements.display.played.value;\n break;\n\n case 'all':\n this.config.loop.start = 0;\n this.config.loop.end = this.duration - 2;\n this.config.loop.indicator.start = 0;\n this.config.loop.indicator.end = 100;\n break;\n\n case 'toggle':\n if (this.config.loop.active) {\n this.config.loop.start = 0;\n this.config.loop.end = null;\n } else {\n this.config.loop.start = 0;\n this.config.loop.end = this.duration - 2;\n }\n break;\n\n default:\n this.config.loop.start = 0;\n this.config.loop.end = null;\n break;\n } */\n }\n\n get loop() {\n return this.media.loop;\n }\n\n // Media source\n set source(input) {\n source.change.call(this, input);\n }\n\n get source() {\n return this.media.currentSrc;\n }\n\n // Poster image\n set poster(input) {\n if (this.type !== 'video') {\n this.console.warn('Poster can only be set on HTML5 video');\n return;\n }\n\n if (utils.is.string(input)) {\n this.media.setAttribute('poster', input);\n }\n }\n\n get poster() {\n if (this.type !== 'video') {\n return null;\n }\n\n return this.media.getAttribute('poster');\n }\n\n // Autoplay\n get autoplay() {\n return this.config.autoplay;\n }\n\n set autoplay(input) {\n const toggle = utils.is.boolean(input) ? input : this.config.autoplay;\n this.config.autoplay = toggle;\n }\n\n // Toggle captions\n toggleCaptions(input) {\n // If there's no full support, or there's no caption toggle\n if (!this.supported.ui || !utils.is.htmlElement(this.elements.buttons.captions)) {\n return this;\n }\n\n // If the method is called without parameter, toggle based on current value\n const show = utils.is.boolean(input)\n ? input\n : this.elements.container.className.indexOf(this.config.classNames.captions.active) === -1;\n\n // Nothing to change...\n if (this.captions.enabled === show) {\n return this;\n }\n\n // Set global\n this.captions.enabled = show;\n\n // Toggle state\n utils.toggleState(this.elements.buttons.captions, this.captions.enabled);\n\n // Add class hook\n utils.toggleClass(this.elements.container, this.config.classNames.captions.active, this.captions.enabled);\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, this.captions.enabled ? 'captionsenabled' : 'captionsdisabled');\n\n // Allow chaining\n return this;\n }\n\n // Caption language\n set language(input) {\n // Nothing specified\n if (!utils.is.string(input)) {\n return;\n }\n\n // Normalize\n const language = input.toLowerCase();\n\n // If nothing to change, bail\n if (this.captions.language === language) {\n return;\n }\n\n // Reset UI\n this.toggleCaptions(true);\n\n // Update config\n this.captions.language = language;\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, 'languagechange');\n\n // Clear caption\n captions.set.call(this);\n\n // Re-run setup\n captions.setup.call(this);\n }\n\n get language() {\n return this.captions.language;\n }\n\n // Toggle fullscreen\n // Requires user input event\n toggleFullscreen(event) {\n // Check for native support\n if (fullscreen.enabled) {\n // If it's a fullscreen change event, update the UI\n if (utils.is.event(event) && event.type === fullscreen.eventType) {\n this.fullscreen.active = fullscreen.isFullScreen(this.elements.container);\n } else {\n // Else it's a user request to enter or exit\n if (!this.fullscreen.active) {\n // Request full screen\n fullscreen.requestFullScreen(this.elements.container);\n } else {\n // Bail from fullscreen\n fullscreen.cancelFullScreen();\n }\n\n // Check if we're actually full screen (it could fail)\n this.fullscreen.active = fullscreen.isFullScreen(this.elements.container);\n\n return this;\n }\n } else {\n // Otherwise, it's a simple toggle\n this.fullscreen.active = !this.fullscreen.active;\n\n // Add class hook\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.fullscreen.fallback,\n this.fullscreen.active\n );\n\n // Make sure we don't lose scroll position\n if (this.fullscreen.active) {\n scrollPosition = {\n x: window.pageXOffset || 0,\n y: window.pageYOffset || 0,\n };\n } else {\n window.scrollTo(scrollPosition.x, scrollPosition.y);\n }\n\n // Bind/unbind escape key\n document.body.style.overflow = this.fullscreen.active ? 'hidden' : '';\n }\n\n // Set button state\n if (this.elements.buttons && this.elements.buttons.fullscreen) {\n utils.toggleState(this.elements.buttons.fullscreen, this.fullscreen.active);\n }\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, this.fullscreen.active ? 'enterfullscreen' : 'exitfullscreen');\n\n return this;\n }\n\n // Toggle picture-in-picture\n // TODO: update player with state, support, enabled\n // TODO: detect outside changes\n set pip(input) {\n const states = {\n pip: 'picture-in-picture',\n inline: 'inline',\n };\n\n // Bail if no support\n if (!support.pip) {\n return;\n }\n\n // Toggle based on current state if not passed\n const toggle = utils.is.boolean(input) ? input : this.pip === states.inline;\n\n // Toggle based on current state\n this.media.webkitSetPresentationMode(toggle ? states.pip : states.inline);\n }\n\n get pip() {\n if (!support.pip) {\n return null;\n }\n\n return this.media.webkitPresentationMode;\n }\n\n // Trigger airplay\n // TODO: update player with state, support, enabled\n airplay() {\n // Bail if no support\n if (!support.airplay) {\n return this;\n }\n\n // Show dialog\n this.media.webkitShowPlaybackTargetPicker();\n\n return this;\n }\n\n // Show the player controls in fullscreen mode\n toggleControls(toggle) {\n const player = this;\n\n // We need controls of course...\n if (!utils.is.htmlElement(this.elements.controls)) {\n return player;\n }\n\n // Don't hide if config says not to, it's audio, or not ready or loading\n if (!this.supported.ui || !this.config.hideControls || this.type === 'audio') {\n return player;\n }\n\n let delay = 0;\n let show = toggle;\n let isEnterFullscreen = false;\n const loading = utils.hasClass(this.elements.container, this.config.classNames.loading);\n\n // Default to false if no boolean\n if (!utils.is.boolean(toggle)) {\n if (utils.is.event(toggle)) {\n // Is the enter fullscreen event\n isEnterFullscreen = toggle.type === 'enterfullscreen';\n\n // Whether to show controls\n show = ['mousemove', 'touchstart', 'mouseenter', 'focus'].includes(toggle.type);\n\n // Delay hiding on move events\n if (['mousemove', 'touchmove'].includes(toggle.type)) {\n delay = 2000;\n }\n\n // Delay a little more for keyboard users\n if (toggle.type === 'focus') {\n delay = 3000;\n }\n } else {\n show = utils.hasClass(this.elements.container, this.config.classNames.hideControls);\n }\n }\n\n // Clear timer every movement\n window.clearTimeout(this.timers.hover);\n\n // If the mouse is not over the controls, set a timeout to hide them\n if (show || this.media.paused || loading) {\n // Check if controls toggled\n const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, false);\n\n // Trigger event\n if (toggled) {\n utils.dispatchEvent.call(this, this.media, 'controlsshown');\n }\n\n // Always show controls when paused or if touch\n if (this.media.paused || loading) {\n return player;\n }\n\n // Delay for hiding on touch\n if (support.touch) {\n delay = 3000;\n }\n }\n\n // If toggle is false or if we're playing (regardless of toggle),\n // then set the timer to hide the controls\n if (!show || !this.media.paused) {\n this.timers.hover = window.setTimeout(() => {\n // If the mouse is over the controls (and not entering fullscreen), bail\n if ((this.elements.controls.pressed || this.elements.controls.hover) && !isEnterFullscreen) {\n return;\n }\n\n // Check if controls toggled\n const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, true);\n\n // Trigger event and close menu\n if (toggled) {\n utils.dispatchEvent.call(this, this.media, 'controlshidden');\n\n if (this.config.controls.includes('settings') && !utils.is.empty(this.config.settings)) {\n controls.toggleMenu.call(this, false);\n }\n }\n }, delay);\n }\n\n return this;\n }\n\n // Event listeners\n on(event, callback) {\n utils.on(this.elements.container, event, callback);\n return this;\n }\n\n off(event, callback) {\n utils.off(this.elements.container, event, callback);\n return this;\n }\n\n // Check for support\n supports(type) {\n return support.mime.call(this, type);\n }\n\n // Destroy an instance\n // Event listeners are removed when elements are removed\n // http://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory\n destroy(callback, soft = false) {\n const done = () => {\n // Reset overflow (incase destroyed while in fullscreen)\n document.body.style.overflow = '';\n\n // GC for embed\n this.embed = null;\n this.embedId = null;\n\n // If it's a soft destroy, make minimal changes\n if (soft) {\n if (Object.keys(this.elements).length) {\n // Remove buttons\n if (this.elements.buttons && this.elements.buttons.play) {\n Array.from(this.elements.buttons.play).forEach(button => utils.removeElement(button));\n }\n\n // Remove others\n utils.removeElement(this.elements.captions);\n utils.removeElement(this.elements.controls);\n utils.removeElement(this.elements.wrapper);\n\n // Clear for GC\n this.elements.buttons.play = null;\n this.elements.captions = null;\n this.elements.controls = null;\n this.elements.wrapper = null;\n }\n\n // Callback\n if (utils.is.function(callback)) {\n callback();\n }\n } else {\n // Replace the container with the original element provided\n const parent = this.elements.container.parentNode;\n\n if (utils.is.htmlElement(parent)) {\n parent.replaceChild(this.elements.original, this.elements.container);\n }\n\n // Event\n utils.dispatchEvent.call(this, this.elements.original, 'destroyed', true);\n\n // Callback\n if (utils.is.function(callback)) {\n callback.call(this.elements.original);\n }\n\n // Clear for GC\n this.elements = null;\n }\n };\n\n // Type specific stuff\n switch (this.type) {\n case 'youtube':\n // Clear timers\n window.clearInterval(this.timers.buffering);\n window.clearInterval(this.timers.playing);\n\n // Destroy YouTube API\n this.embed.destroy();\n\n // Clean up\n done();\n\n break;\n\n case 'vimeo':\n // Destroy Vimeo API\n // then clean up (wait, to prevent postmessage errors)\n this.embed.unload().then(done);\n\n // Vimeo does not always return\n window.setTimeout(done, 200);\n\n break;\n\n case 'video':\n case 'audio':\n // Restore native video controls\n ui.toggleNativeControls.call(this, true);\n\n // Clean up\n done();\n\n break;\n\n default:\n break;\n }\n }\n}\n\nexport default Plyr;\n"],"names":["get","store","window","localStorage","getItem","this","config","storage","key","utils","is","empty","JSON","parse","set","object","support","enabled","call","extend","setItem","stringify","defaults","navigator","language","split","types","input","getConstructor","Object","Number","isNaN","String","Boolean","Function","undefined","Array","isArray","NodeList","HTMLElement","Event","instanceOf","TextTrackCue","VTTCue","TextTrack","kind","string","array","nodeList","length","keys","constructor","document","documentMode","documentElement","style","test","userAgent","platform","url","callback","querySelectorAll","element","createElement","src","first","getElementsByTagName","function","addEventListener","event","parentNode","insertBefore","id","updateSprite","data","innerHTML","body","childNodes","hasId","container","setAttribute","cached","content","then","response","text","prefix","Math","floor","random","self","top","e","elements","wrapper","targets","from","reverse","forEach","index","child","cloneNode","parent","sibling","nextSibling","appendChild","htmlElement","removeChild","target","type","attributes","setAttributes","textContent","lastChild","sel","existingAttributes","existing","selector","s","trim","className","replace","parts","value","charAt","class","toggle","contains","classList","prototype","Element","matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","includes","querySelector","controls","getElement","selectors","buttons","getElements","play","pause","restart","rewind","forward","mute","pip","airplay","settings","captions","fullscreen","progress","inputs","seek","volume","display","buffer","duration","currentTime","seekTooltip","classNames","tooltip","error","console","warn","toggleNativeControls","focused","activeElement","tabbables","last","on","keyCode","_this","active","getFocusElement","shiftKey","focus","preventDefault","passive","capture","Node","toggleListener","events","options","boolean","passiveListeners","bubbles","detail","CustomEvent","assign","Plyr","dispatchEvent","state","getAttribute","current","max","toFixed","objects","destination","shift","source","property","match","RegExp","$2","number","map","encodeURIComponent","join","fragment","createDocumentFragment","firstChild","innerText","width","height","ratio","getRatio","w","h","find","inline","api","ui","browser","getBrowser","playsInline","isIPhone","video","rangeInput","audio","removeItem","webkitSetPresentationMode","WebKitPlaybackTargetAvailabilityEvent","media","canPlayType","supported","defineProperty","range","transitionEnd","matchMedia","cancelFullScreen","some","pre","msExitFullscreen","msFullscreenEnabled","fullscreenEnabled","webkitFullscreenEnabled","mozFullScreenEnabled","fullscreenElement","mozFullScreenElement","requestFullScreen","nativeSupport","fallback","inFrame","log","toggleClass","toggleState","trapFocus","setup","parseFloat","listeners","getKeyCode","which","handleKey","code","pressed","held","editable","stopPropagation","togglePlay","increaseVolume","decreaseVolume","muted","toggleFullscreen","toggleCaptions","loop","keyboard","global","tabFocus","setTimeout","hideControls","toggleControls","eventType","timeUpdate","displayDuration","_this2","showPosterOnEnd","load","updateProgress","updateVolume","checkPlaying","checkLoading","clickToPlay","cursor","touch","paused","ended","disableContextMenu","updateSetting","speed","quality","concat","inputEvent","isIE","proxy","handlerKey","defaultHandler","customHandler","_this3","defaultPrevented","airPlay","toggleMenu","form","showTab","toLowerCase","isWebkit","updateRangeFill","updateSeekTooltip","hover","inverted","webkitDirectionInvertedFromDevice","direction","deltaY","deltaX","uiSupported","isHTML5","removeAttribute","removeElement","inject","ready","setTitle","updateTimeDisplay","label","i18n","title","isEmbed","iframe","frameTitle","playing","stopped","setRange","loading","timers","nodeValue","getPercentage","buffered","end","setProgress","time","secs","parseInt","mins","hours","displayHours","slice","seeking","styleSheet","sheet","percentage","styles","rules","findIndex","rule","selectorText","deleteRule","insertRule","iconUrl","indexOf","svg4everybody","getIconUrl","iconPath","absolute","iconPrefix","icon","createElementNS","use","path","setAttributeNS","hidden","badge","menu","buttonType","attr","button","iconDefault","iconToggled","labelKey","control","getAttributesFromSelector","createIcon","createLabel","suffix","played","tooltips","percent","clientRect","getBoundingClientRect","visible","pageX","left","hasClass","setting","tab","tabs","pane","panes","list","filter","toggleTab","emptyElement","getBadge","createBadge","item","radio","createTextNode","getLabel","getLanguage","default","checked","option","textTracks","tracks","none","currentTrack","disabled","track","toUpperCase","unshift","_this4","insertAdjacentHTML","show","isMenuItem","isButton","clone","position","opacity","name","scrollWidth","scrollHeight","getElementById","transitions","reducedMotion","size","getTabSize","restore","propertyName","off","createButton","createRange","createProgress","createTime","inner","home","_this5","back","setSpeedMenu","loadSprite","seekTime","create","findElements","labels","_this6","setCaptionsMenu","insertAfter","setCurrentTrack","setCue","mode","activeCues","embed","enableTextTrack","cue","getCueAsHTML","caption","youtube","videoId","parseYouTubeId","embedId","containers","setAspectRatio","generateId","json","obj","items","snippet","catch","YT","loadScript","urls","onYouTubeReadyCallbacks","push","onYouTubeIframeAPIReady","paddingBottom","player","Player","autoplay","location","hostname","href","message","instance","getPlaybackQuality","playbackRate","getPlaybackRate","playVideo","pauseVideo","stop","stopVideo","getDuration","getCurrentTime","seekTo","setPlaybackRate","setPlaybackQuality","setVolume","getVideoUrl","getAvailablePlaybackRates","getVideoData","clearInterval","buffering","setInterval","getVideoLoadedFraction","lastBuffered","build","setQualityMenu","getAvailableQualityLevels","vimeo","Vimeo","padding","offset","transform","params","buildUrlParameters","parseVimeoId","setCurrentTime","selected","setLoop","currentSrc","all","getVideoWidth","getVideoHeight","getAspectRatio","dimensions","getVideoTitle","getTextTracks","cues","stripHTML","seconds","isIos","isTouch","wrap","blankVideo","insertElement","attribute","sources","cancelRequests","destroy","firstSource","check","crossorigin","poster","addStyleHook","insertElements","scrollPosition","jQuery","debug","plyr","original","tagName","hasAttribute","step","isFullScreen","pageXOffset","pageYOffset","scrollTo","x","y","overflow","webkitShowPlaybackTargetPicker","delay","isEnterFullscreen","clearTimeout","mime","soft","done","replaceChild","unload","html5","targetTime","fauxDuration","realDuration","change","states","webkitPresentationMode"],"mappings":"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"}
\ No newline at end of file +{"version":3,"file":"plyr.js","sources":["src/js/storage.js","src/js/defaults.js","src/js/types.js","src/js/utils.js","src/js/support.js","src/js/fullscreen.js","src/js/listeners.js","src/js/ui.js","src/js/controls.js","src/js/captions.js","src/js/plugins/youtube.js","src/js/plugins/vimeo.js","src/js/media.js","src/js/source.js","src/js/plyr.js"],"sourcesContent":["// ==========================================================================\n// Plyr storage\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\n\n// Get contents of local storage\nfunction get() {\n const store = window.localStorage.getItem(this.config.storage.key);\n\n if (utils.is.empty(store)) {\n return {};\n }\n\n return JSON.parse(store);\n}\n\n// Save a value back to local storage\nfunction set(object) {\n // Bail if we don't have localStorage support or it's disabled\n if (!support.storage || !this.config.storage.enabled) {\n return;\n }\n\n // Can only store objectst\n if (!utils.is.object(object)) {\n return;\n }\n\n // Get current storage\n const storage = get.call(this);\n\n // Update the working copy of the values\n utils.extend(storage, object);\n\n // Update storage\n window.localStorage.setItem(this.config.storage.key, JSON.stringify(storage));\n}\n\n// Setup localStorage\nfunction setup() {\n let value = null;\n let storage = {};\n\n // Bail if we don't have localStorage support or it's disabled\n if (!support.storage || !this.config.storage.enabled) {\n return storage;\n }\n\n // Clean up old volume\n // https://github.com/sampotts/plyr/issues/171\n window.localStorage.removeItem('plyr-volume');\n\n // load value from the current key\n value = window.localStorage.getItem(this.config.storage.key);\n\n if (!value) {\n // Key wasn't set (or had been cleared), move along\n } else if (/^\\d+(\\.\\d+)?$/.test(value)) {\n // If value is a number, it's probably volume from an older\n // version of this. See: https://github.com/sampotts/plyr/pull/313\n // Update the key to be JSON\n set({\n volume: parseFloat(value),\n });\n } else {\n // Assume it's JSON from this or a later version of plyr\n storage = JSON.parse(value);\n }\n\n return storage;\n}\n\nexport default { setup, set, get };\n","// Default config\nconst defaults = {\n // Disable\n enabled: true,\n\n // Custom media title\n title: '',\n\n // Logging to console\n debug: false,\n\n // Auto play (if supported)\n autoplay: false,\n\n // Default time to skip when rewind/fast forward\n seekTime: 10,\n\n // Default volume\n volume: 1,\n muted: false,\n\n // Pass a custom duration\n duration: null,\n\n // Display the media duration on load in the current time position\n // If you have opted to display both duration and currentTime, this is ignored\n displayDuration: true,\n\n // Invert the current time to be a countdown\n invertTime: true,\n\n // Clicking the currentTime inverts it's value to show time left rather than elapsed\n toggleInvert: true,\n\n // Aspect ratio (for embeds)\n ratio: '16:9',\n\n // Click video container to play/pause\n clickToPlay: true,\n\n // Auto hide the controls\n hideControls: true,\n\n // Revert to poster on finish (HTML5 - will cause reload)\n showPosterOnEnd: false,\n\n // Disable the standard context menu\n disableContextMenu: true,\n\n // Sprite (for icons)\n loadSprite: true,\n iconPrefix: 'plyr',\n iconUrl: 'https://cdn.plyr.io/2.0.10/plyr.svg',\n\n // Blank video (used to prevent errors on source change)\n blankVideo: 'https://cdn.plyr.io/static/blank.mp4',\n\n // Quality default\n quality: {\n default: 'default',\n options: ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny', 'default'],\n },\n\n // Set loops\n loop: {\n active: false,\n // start: null,\n // end: null,\n },\n\n // Speed default and options to display\n speed: {\n selected: 1,\n options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2],\n },\n\n // Keyboard shortcut settings\n keyboard: {\n focused: true,\n global: false,\n },\n\n // Display tooltips\n tooltips: {\n controls: false,\n seek: true,\n },\n\n // Captions settings\n captions: {\n active: false,\n language: window.navigator.language.split('-')[0],\n },\n\n // Fullscreen settings\n fullscreen: {\n enabled: true, // Allow fullscreen?\n fallback: true, // Fallback for vintage browsers\n },\n\n // Local storage\n storage: {\n enabled: true,\n key: 'plyr',\n },\n\n // Default controls\n controls: [\n 'play-large',\n 'play',\n 'progress',\n 'current-time',\n 'mute',\n 'volume',\n 'captions',\n 'settings',\n 'pip',\n 'airplay',\n 'fullscreen',\n ],\n settings: ['captions', 'quality', 'speed', 'loop'],\n\n // Localisation\n i18n: {\n restart: 'Restart',\n rewind: 'Rewind {seektime} secs',\n play: 'Play',\n pause: 'Pause',\n forward: 'Forward {seektime} secs',\n seek: 'Seek',\n played: 'Played',\n buffered: 'Buffered',\n currentTime: 'Current time',\n duration: 'Duration',\n volume: 'Volume',\n toggleMute: 'Toggle Mute',\n toggleCaptions: 'Toggle Captions',\n toggleFullscreen: 'Toggle Fullscreen',\n frameTitle: 'Player for {title}',\n captions: 'Captions',\n settings: 'Settings',\n speed: 'Speed',\n quality: 'Quality',\n loop: 'Loop',\n start: 'Start',\n end: 'End',\n all: 'All',\n reset: 'Reset',\n none: 'None',\n disabled: 'Disabled',\n },\n\n // URLs\n urls: {\n vimeo: {\n api: 'https://player.vimeo.com/api/player.js',\n },\n youtube: {\n api: 'https://www.youtube.com/iframe_api',\n },\n },\n\n // Custom control listeners\n listeners: {\n seek: null,\n play: null,\n pause: null,\n restart: null,\n rewind: null,\n forward: null,\n mute: null,\n volume: null,\n captions: null,\n fullscreen: null,\n pip: null,\n airplay: null,\n speed: null,\n quality: null,\n loop: null,\n language: null,\n },\n\n // Events to watch and bubble\n events: [\n // Events to watch on HTML5 media elements and bubble\n // https://developer.mozilla.org/en/docs/Web/Guide/Events/Media_events\n 'ended',\n 'progress',\n 'stalled',\n 'playing',\n 'waiting',\n 'canplay',\n 'canplaythrough',\n 'loadstart',\n 'loadeddata',\n 'loadedmetadata',\n 'timeupdate',\n 'volumechange',\n 'play',\n 'pause',\n 'error',\n 'seeking',\n 'seeked',\n 'emptied',\n 'ratechange',\n 'cuechange',\n\n // Custom events\n 'enterfullscreen',\n 'exitfullscreen',\n 'captionsenabled',\n 'captionsdisabled',\n 'languagechange',\n 'controlshidden',\n 'controlsshown',\n 'ready',\n\n // YouTube\n 'statechange',\n 'qualitychange',\n 'qualityrequested',\n ],\n\n // Selectors\n // Change these to match your template if using custom HTML\n selectors: {\n editable: 'input, textarea, select, [contenteditable]',\n container: '.plyr',\n controls: {\n container: null,\n wrapper: '.plyr__controls',\n },\n labels: '[data-plyr]',\n buttons: {\n play: '[data-plyr=\"play\"]',\n pause: '[data-plyr=\"pause\"]',\n restart: '[data-plyr=\"restart\"]',\n rewind: '[data-plyr=\"rewind\"]',\n forward: '[data-plyr=\"fast-forward\"]',\n mute: '[data-plyr=\"mute\"]',\n captions: '[data-plyr=\"captions\"]',\n fullscreen: '[data-plyr=\"fullscreen\"]',\n pip: '[data-plyr=\"pip\"]',\n airplay: '[data-plyr=\"airplay\"]',\n settings: '[data-plyr=\"settings\"]',\n loop: '[data-plyr=\"loop\"]',\n },\n inputs: {\n seek: '[data-plyr=\"seek\"]',\n volume: '[data-plyr=\"volume\"]',\n speed: '[data-plyr=\"speed\"]',\n language: '[data-plyr=\"language\"]',\n quality: '[data-plyr=\"quality\"]',\n },\n display: {\n currentTime: '.plyr__time--current',\n duration: '.plyr__time--duration',\n buffer: '.plyr__progress--buffer',\n played: '.plyr__progress--played',\n loop: '.plyr__progress--loop',\n volume: '.plyr__volume--display',\n },\n progress: '.plyr__progress',\n captions: '.plyr__captions',\n menu: {\n quality: '.js-plyr__menu__list--quality',\n },\n },\n\n // Class hooks added to the player in different states\n classNames: {\n video: 'plyr__video-wrapper',\n embed: 'plyr__video-embed',\n control: 'plyr__control',\n type: 'plyr--{0}',\n stopped: 'plyr--stopped',\n playing: 'plyr--playing',\n loading: 'plyr--loading',\n hover: 'plyr--hover',\n tooltip: 'plyr__tooltip',\n hidden: 'plyr__sr-only',\n hideControls: 'plyr--hide-controls',\n isIos: 'plyr--is-ios',\n isTouch: 'plyr--is-touch',\n uiSupported: 'plyr--full-ui',\n noTransition: 'plyr--no-transition',\n menu: {\n value: 'plyr__menu__value',\n badge: 'plyr__badge',\n },\n captions: {\n enabled: 'plyr--captions-enabled',\n active: 'plyr--captions-active',\n },\n fullscreen: {\n enabled: 'plyr--fullscreen-enabled',\n fallback: 'plyr--fullscreen-fallback',\n },\n pip: {\n supported: 'plyr--pip-supported',\n active: 'plyr--pip-active',\n },\n airplay: {\n supported: 'plyr--airplay-supported',\n active: 'plyr--airplay-active',\n },\n tabFocus: 'plyr__tab-focus',\n },\n\n // API keys\n keys: {\n google: null,\n },\n};\n\nexport default defaults;\n","// ==========================================================================\n// Plyr supported types\n// ==========================================================================\n\nconst types = {\n embed: ['youtube', 'vimeo'],\n html5: ['video', 'audio'],\n};\n\nexport default types;\n","// ==========================================================================\n// Plyr utils\n// ==========================================================================\n\nimport support from './support';\n\nconst utils = {\n // Check variable types\n is: {\n object(input) {\n return this.getConstructor(input) === Object;\n },\n number(input) {\n return this.getConstructor(input) === Number && !Number.isNaN(input);\n },\n string(input) {\n return this.getConstructor(input) === String;\n },\n boolean(input) {\n return this.getConstructor(input) === Boolean;\n },\n function(input) {\n return this.getConstructor(input) === Function;\n },\n array(input) {\n return !this.undefined(input) && Array.isArray(input);\n },\n nodeList(input) {\n return !this.undefined(input) && input instanceof NodeList;\n },\n htmlElement(input) {\n return !this.undefined(input) && input instanceof HTMLElement;\n },\n textNode(input) {\n return this.getConstructor(input) === Text;\n },\n event(input) {\n return !this.undefined(input) && input instanceof Event;\n },\n cue(input) {\n return this.instanceOf(input, window.TextTrackCue) || this.instanceOf(input, window.VTTCue);\n },\n track(input) {\n return (\n !this.undefined(input) && (this.instanceOf(input, window.TextTrack) || typeof input.kind === 'string')\n );\n },\n undefined(input) {\n return input !== null && typeof input === 'undefined';\n },\n empty(input) {\n return (\n input === null ||\n typeof input === 'undefined' ||\n ((this.string(input) || this.array(input) || this.nodeList(input)) && !input.length) ||\n (this.object(input) && !Object.keys(input).length)\n );\n },\n getConstructor(input) {\n if (input === null || typeof input === 'undefined') {\n return null;\n }\n\n return input.constructor;\n },\n instanceOf(input, constructor) {\n return Boolean(input && constructor && input instanceof constructor);\n },\n },\n\n // Unfortunately, due to mixed support, UA sniffing is required\n getBrowser() {\n return {\n isIE: /* @cc_on!@ */ false || !!document.documentMode,\n isWebkit: 'WebkitAppearance' in document.documentElement.style && !/Edge/.test(navigator.userAgent),\n isIPhone: /(iPhone|iPod)/gi.test(navigator.platform),\n isIos: /(iPad|iPhone|iPod)/gi.test(navigator.platform),\n };\n },\n\n // Load an external script\n loadScript(url, callback) {\n // Check script is not already referenced\n if (document.querySelectorAll(`script[src=\"${url}\"]`).length) {\n return;\n }\n\n // Build the element\n const element = document.createElement('script');\n element.src = url;\n\n // Find first script\n const first = document.getElementsByTagName('script')[0];\n\n // Bind callback\n if (utils.is.function(callback)) {\n element.addEventListener('load', event => callback.call(null, event), false);\n }\n\n // Inject\n first.parentNode.insertBefore(element, first);\n },\n\n // Load an external SVG sprite\n loadSprite(url, id) {\n if (!utils.is.string(url)) {\n return;\n }\n\n const prefix = 'cache-';\n const hasId = utils.is.string(id);\n let isCached = false;\n\n function updateSprite(data) {\n // Inject content\n this.innerHTML = data;\n\n // Inject the SVG to the body\n document.body.insertBefore(this, document.body.childNodes[0]);\n }\n\n // Only load once\n if (!hasId || !document.querySelectorAll(`#${id}`).length) {\n // Create container\n const container = document.createElement('div');\n container.setAttribute('hidden', '');\n\n if (hasId) {\n container.setAttribute('id', id);\n }\n\n // Check in cache\n if (support.storage) {\n const cached = window.localStorage.getItem(prefix + id);\n isCached = cached !== null;\n\n if (isCached) {\n const data = JSON.parse(cached);\n updateSprite.call(container, data.content);\n return;\n }\n }\n\n // Get the sprite\n fetch(url)\n .then(response => (response.ok ? response.text() : null))\n .then(text => {\n if (text === null) {\n return;\n }\n\n if (support.storage) {\n window.localStorage.setItem(\n prefix + id,\n JSON.stringify({\n content: text,\n })\n );\n }\n\n updateSprite.call(container, text);\n })\n .catch(() => {});\n }\n },\n\n // Generate a random ID\n generateId(prefix) {\n return `${prefix}-${Math.floor(Math.random() * 10000)}`;\n },\n\n // Determine if we're in an iframe\n inFrame() {\n try {\n return window.self !== window.top;\n } catch (e) {\n return true;\n }\n },\n\n // Wrap an element\n wrap(elements, wrapper) {\n // Convert `elements` to an array, if necessary.\n const targets = elements.length ? elements : [elements];\n\n // Loops backwards to prevent having to clone the wrapper on the\n // first element (see `child` below).\n Array.from(targets)\n .reverse()\n .forEach((element, index) => {\n const child = index > 0 ? wrapper.cloneNode(true) : wrapper;\n\n // Cache the current parent and sibling.\n const parent = element.parentNode;\n const sibling = element.nextSibling;\n\n // Wrap the element (is automatically removed from its current\n // parent).\n child.appendChild(element);\n\n // If the element had a sibling, insert the wrapper before\n // the sibling to maintain the HTML structure; otherwise, just\n // append it to the parent.\n if (sibling) {\n parent.insertBefore(child, sibling);\n } else {\n parent.appendChild(child);\n }\n });\n },\n\n // Create a DocumentFragment\n createElement(type, attributes, text) {\n // Create a new <element>\n const element = document.createElement(type);\n\n // Set all passed attributes\n if (utils.is.object(attributes)) {\n utils.setAttributes(element, attributes);\n }\n\n // Add text node\n if (utils.is.string(text)) {\n element.textContent = text;\n }\n\n // Return built element\n return element;\n },\n\n // Inaert an element after another\n insertAfter(element, target) {\n target.parentNode.insertBefore(element, target.nextSibling);\n },\n\n // Insert a DocumentFragment\n insertElement(type, parent, attributes, text) {\n // Inject the new <element>\n parent.appendChild(utils.createElement(type, attributes, text));\n },\n\n // Remove an element\n removeElement(element) {\n if (!utils.is.htmlElement(element) || !utils.is.htmlElement(element.parentNode)) {\n return null;\n }\n\n element.parentNode.removeChild(element);\n\n return element;\n },\n\n // Remove all child elements\n emptyElement(element) {\n let { length } = element.childNodes;\n\n while (length > 0) {\n element.removeChild(element.lastChild);\n length -= 1;\n }\n },\n\n // Set attributes\n setAttributes(element, attributes) {\n Object.keys(attributes).forEach(key => {\n element.setAttribute(key, attributes[key]);\n });\n },\n\n // Get an attribute object from a string selector\n getAttributesFromSelector(sel, existingAttributes) {\n // For example:\n // '.test' to { class: 'test' }\n // '#test' to { id: 'test' }\n // '[data-test=\"test\"]' to { 'data-test': 'test' }\n\n if (!utils.is.string(sel) || utils.is.empty(sel)) {\n return {};\n }\n\n const attributes = {};\n const existing = existingAttributes;\n\n sel.split(',').forEach(s => {\n // Remove whitespace\n const selector = s.trim();\n const className = selector.replace('.', '');\n const stripped = selector.replace(/[[\\]]/g, '');\n\n // Get the parts and value\n const parts = stripped.split('=');\n const key = parts[0];\n const value = parts.length > 1 ? parts[1].replace(/[\"']/g, '') : '';\n\n // Get the first character\n const start = selector.charAt(0);\n\n switch (start) {\n case '.':\n // Add to existing classname\n if (utils.is.object(existing) && utils.is.string(existing.class)) {\n existing.class += ` ${className}`;\n }\n\n attributes.class = className;\n break;\n\n case '#':\n // ID selector\n attributes.id = selector.replace('#', '');\n break;\n\n case '[':\n // Attribute selector\n attributes[key] = value;\n\n break;\n\n default:\n break;\n }\n });\n\n return attributes;\n },\n\n // Toggle class on an element\n toggleClass(element, className, toggle) {\n if (utils.is.htmlElement(element)) {\n const contains = element.classList.contains(className);\n\n element.classList[toggle ? 'add' : 'remove'](className);\n\n return (toggle && !contains) || (!toggle && contains);\n }\n\n return null;\n },\n\n // Has class name\n hasClass(element, className) {\n return utils.is.htmlElement(element) && element.classList.contains(className);\n },\n\n // Element matches selector\n matches(element, selector) {\n const prototype = { Element };\n\n function match() {\n return Array.from(document.querySelectorAll(selector)).includes(this);\n }\n\n const matches =\n prototype.matches ||\n prototype.webkitMatchesSelector ||\n prototype.mozMatchesSelector ||\n prototype.msMatchesSelector ||\n match;\n\n return matches.call(element, selector);\n },\n\n // Find all elements\n getElements(selector) {\n return this.elements.container.querySelectorAll(selector);\n },\n\n // Find a single element\n getElement(selector) {\n return this.elements.container.querySelector(selector);\n },\n\n // Find the UI controls and store references in custom controls\n // TODO: Allow settings menus with custom controls\n findElements() {\n try {\n this.elements.controls = utils.getElement.call(this, this.config.selectors.controls.wrapper);\n\n // Buttons\n this.elements.buttons = {\n play: utils.getElements.call(this, this.config.selectors.buttons.play),\n pause: utils.getElement.call(this, this.config.selectors.buttons.pause),\n restart: utils.getElement.call(this, this.config.selectors.buttons.restart),\n rewind: utils.getElement.call(this, this.config.selectors.buttons.rewind),\n forward: utils.getElement.call(this, this.config.selectors.buttons.forward),\n mute: utils.getElement.call(this, this.config.selectors.buttons.mute),\n pip: utils.getElement.call(this, this.config.selectors.buttons.pip),\n airplay: utils.getElement.call(this, this.config.selectors.buttons.airplay),\n settings: utils.getElement.call(this, this.config.selectors.buttons.settings),\n captions: utils.getElement.call(this, this.config.selectors.buttons.captions),\n fullscreen: utils.getElement.call(this, this.config.selectors.buttons.fullscreen),\n };\n\n // Progress\n this.elements.progress = utils.getElement.call(this, this.config.selectors.progress);\n\n // Inputs\n this.elements.inputs = {\n seek: utils.getElement.call(this, this.config.selectors.inputs.seek),\n volume: utils.getElement.call(this, this.config.selectors.inputs.volume),\n };\n\n // Display\n this.elements.display = {\n buffer: utils.getElement.call(this, this.config.selectors.display.buffer),\n duration: utils.getElement.call(this, this.config.selectors.display.duration),\n currentTime: utils.getElement.call(this, this.config.selectors.display.currentTime),\n };\n\n // Seek tooltip\n if (utils.is.htmlElement(this.elements.progress)) {\n this.elements.display.seekTooltip = this.elements.progress.querySelector(\n `.${this.config.classNames.tooltip}`\n );\n }\n\n return true;\n } catch (error) {\n // Log it\n this.console.warn('It looks like there is a problem with your custom controls HTML', error);\n\n // Restore native video controls\n this.toggleNativeControls(true);\n\n return false;\n }\n },\n\n // Get the focused element\n getFocusElement() {\n let focused = document.activeElement;\n\n if (!focused || focused === document.body) {\n focused = null;\n } else {\n focused = document.querySelector(':focus');\n }\n\n return focused;\n },\n\n // Trap focus inside container\n trapFocus() {\n const focusable = utils.getElements.call(this, 'button:not(:disabled), input:not(:disabled), [tabindex]');\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n utils.on(\n this.elements.container,\n 'keydown',\n event => {\n // Bail if not tab key or not fullscreen\n if (event.key !== 'Tab' || event.keyCode !== 9 || !this.fullscreen.active) {\n return;\n }\n\n // Get the current focused element\n const focused = utils.getFocusElement();\n\n if (focused === last && !event.shiftKey) {\n // Move focus to first element that can be tabbed if Shift isn't used\n first.focus();\n event.preventDefault();\n } else if (focused === first && event.shiftKey) {\n // Move focus to last element that can be tabbed if Shift is used\n last.focus();\n event.preventDefault();\n }\n },\n false\n );\n },\n\n // Toggle event listener\n toggleListener(elements, event, callback, toggle, passive, capture) {\n // Bail if no elements\n if (elements === null || utils.is.undefined(elements)) {\n return;\n }\n\n // If a nodelist is passed, call itself on each node\n if (utils.is.nodeList(elements)) {\n // Create listener for each node\n Array.from(elements).forEach(element => {\n if (element instanceof Node) {\n utils.toggleListener.call(null, element, event, callback, toggle, passive, capture);\n }\n });\n\n return;\n }\n\n // Allow multiple events\n const events = event.split(' ');\n\n // Build options\n // Default to just capture boolean\n let options = utils.is.boolean(capture) ? capture : false;\n\n // If passive events listeners are supported\n if (support.passiveListeners) {\n options = {\n // Whether the listener can be passive (i.e. default never prevented)\n passive: utils.is.boolean(passive) ? passive : true,\n // Whether the listener is a capturing listener or not\n capture: utils.is.boolean(capture) ? capture : false,\n };\n }\n\n // If a single node is passed, bind the event listener\n events.forEach(type => {\n elements[toggle ? 'addEventListener' : 'removeEventListener'](type, callback, options);\n });\n },\n\n // Bind event handler\n on(element, events, callback, passive, capture) {\n utils.toggleListener(element, events, callback, true, passive, capture);\n },\n\n // Unbind event handler\n off(element, events, callback, passive, capture) {\n utils.toggleListener(element, events, callback, false, passive, capture);\n },\n\n // Trigger event\n dispatchEvent(element, type, bubbles, detail) {\n // Bail if no element\n if (!element || !type) {\n return;\n }\n\n // Create and dispatch the event\n const event = new CustomEvent(type, {\n bubbles: utils.is.boolean(bubbles) ? bubbles : false,\n detail: Object.assign({}, detail, {\n plyr: this instanceof Plyr ? this : null,\n }),\n });\n\n // Dispatch the event\n element.dispatchEvent(event);\n },\n\n // Toggle aria-pressed state on a toggle button\n // http://www.ssbbartgroup.com/blog/how-not-to-misuse-aria-states-properties-and-roles\n toggleState(element, input) {\n // Bail if no target\n if (!utils.is.htmlElement(element)) {\n return;\n }\n\n // Get state\n const state = utils.is.boolean(input) ? input : !element.getAttribute('aria-pressed');\n\n // Set the attribute on target\n element.setAttribute('aria-pressed', state);\n },\n\n // Get percentage\n getPercentage(current, max) {\n if (current === 0 || max === 0 || Number.isNaN(current) || Number.isNaN(max)) {\n return 0;\n }\n return (current / max * 100).toFixed(2);\n },\n\n // Deep extend/merge destination object with N more objects\n // http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/\n // Removed call to arguments.callee (used explicit function name instead)\n extend(...objects) {\n const { length } = objects;\n\n // Bail if nothing to merge\n if (!length) {\n return null;\n }\n\n // Return first if specified but nothing to merge\n if (length === 1) {\n return objects[0];\n }\n\n // First object is the destination\n let destination = Array.prototype.shift.call(objects);\n if (!utils.is.object(destination)) {\n destination = {};\n }\n\n // Loop through all objects to merge\n objects.forEach(source => {\n if (!utils.is.object(source)) {\n return;\n }\n\n Object.keys(source).forEach(property => {\n if (source[property] && source[property].constructor && source[property].constructor === Object) {\n destination[property] = destination[property] || {};\n utils.extend(destination[property], source[property]);\n } else {\n destination[property] = source[property];\n }\n });\n });\n\n return destination;\n },\n\n // Parse YouTube ID from URL\n parseYouTubeId(url) {\n const regex = /^.*(youtu.be\\/|v\\/|u\\/\\w\\/|embed\\/|watch\\?v=|&v=)([^#&?]*).*/;\n return url.match(regex) ? RegExp.$2 : url;\n },\n\n // Parse Vimeo ID from URL\n parseVimeoId(url) {\n if (utils.is.number(Number(url))) {\n return url;\n }\n\n const regex = /^.*(vimeo.com\\/|video\\/)(\\d+).*/;\n return url.match(regex) ? RegExp.$2 : url;\n },\n\n // Convert object to URL parameters\n buildUrlParameters(input) {\n if (!utils.is.object(input)) {\n return '';\n }\n\n return Object.keys(input)\n .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(input[key])}`)\n .join('&');\n },\n\n // Remove HTML from a string\n stripHTML(source) {\n const fragment = document.createDocumentFragment();\n const element = document.createElement('div');\n fragment.appendChild(element);\n element.innerHTML = source;\n return fragment.firstChild.innerText;\n },\n\n // Get aspect ratio for dimensions\n getAspectRatio(width, height) {\n const getRatio = (w, h) => (h === 0 ? w : getRatio(h, w % h));\n const ratio = getRatio(width, height);\n return `${width / ratio}:${height / ratio}`;\n },\n\n // Get the transition end event\n transitionEnd: (() => {\n const element = document.createElement('span');\n\n const events = {\n WebkitTransition: 'webkitTransitionEnd',\n MozTransition: 'transitionend',\n OTransition: 'oTransitionEnd otransitionend',\n transition: 'transitionend',\n };\n\n const type = Object.keys(events).find(event => element.style[event] !== undefined);\n\n return typeof type === 'string' ? type : false;\n })(),\n};\n\nexport default utils;\n","// ==========================================================================\n// Plyr support checks\n// ==========================================================================\n\nimport utils from './utils';\n\n// Check for feature support\nconst support = {\n // Basic support\n audio: 'canPlayType' in document.createElement('audio'),\n video: 'canPlayType' in document.createElement('video'),\n\n // Check for support\n // Basic functionality vs full UI\n check(type, inline) {\n let api = false;\n let ui = false;\n const browser = utils.getBrowser();\n const playsInline = browser.isIPhone && inline && support.inline;\n\n switch (type) {\n case 'video':\n api = support.video;\n ui = api && support.rangeInput && (!browser.isIPhone || playsInline);\n break;\n\n case 'audio':\n api = support.audio;\n ui = api && support.rangeInput;\n break;\n\n case 'youtube':\n api = true;\n ui = support.rangeInput && (!browser.isIPhone || playsInline);\n break;\n\n case 'vimeo':\n api = true;\n ui = support.rangeInput && !browser.isIPhone;\n break;\n\n default:\n api = support.audio && support.video;\n ui = api && support.rangeInput;\n }\n\n return {\n api,\n ui,\n };\n },\n\n // Local storage\n // We can't assume if local storage is present that we can use it\n storage: (() => {\n if (!('localStorage' in window)) {\n return false;\n }\n\n // Try to use it (it might be disabled, e.g. user is in private/porn mode)\n // see: https://github.com/sampotts/plyr/issues/131\n const test = '___test';\n try {\n window.localStorage.setItem(test, test);\n window.localStorage.removeItem(test);\n return true;\n } catch (e) {\n return false;\n }\n })(),\n\n // Picture-in-picture support\n // Safari only currently\n pip: (() => {\n const browser = utils.getBrowser();\n return !browser.isIPhone && utils.is.function(utils.createElement('video').webkitSetPresentationMode);\n })(),\n\n // Airplay support\n // Safari only currently\n airplay: utils.is.function(window.WebKitPlaybackTargetAvailabilityEvent),\n\n // Inline playback support\n // https://webkit.org/blog/6784/new-video-policies-for-ios/\n inline: 'playsInline' in document.createElement('video'),\n\n // Check for mime type support against a player instance\n // Credits: http://diveintohtml5.info/everything.html\n // Related: http://www.leanbackplayer.com/test/h5mt.html\n mime(type) {\n const { media } = this;\n\n try {\n // Bail if no checking function\n if (!utils.is.function(media.canPlayType)) {\n return false;\n }\n\n // Type specific checks\n if (this.type === 'video') {\n switch (type) {\n case 'video/webm':\n return media.canPlayType('video/webm; codecs=\"vp8, vorbis\"').replace(/no/, '');\n\n case 'video/mp4':\n return media.canPlayType('video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"').replace(/no/, '');\n\n case 'video/ogg':\n return media.canPlayType('video/ogg; codecs=\"theora\"').replace(/no/, '');\n\n default:\n return false;\n }\n } else if (this.type === 'audio') {\n switch (type) {\n case 'audio/mpeg':\n return media.canPlayType('audio/mpeg;').replace(/no/, '');\n\n case 'audio/ogg':\n return media.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/no/, '');\n\n case 'audio/wav':\n return media.canPlayType('audio/wav; codecs=\"1\"').replace(/no/, '');\n\n default:\n return false;\n }\n }\n } catch (e) {\n return false;\n }\n\n // If we got this far, we're stuffed\n return false;\n },\n\n // Check for textTracks support\n textTracks: 'textTracks' in document.createElement('video'),\n\n // Check for passive event listener support\n // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n // https://www.youtube.com/watch?v=NPM6172J22g\n passiveListeners: (() => {\n // Test via a getter in the options object to see if the passive property is accessed\n let supported = false;\n try {\n const options = Object.defineProperty({}, 'passive', {\n get() {\n supported = true;\n return null;\n },\n });\n window.addEventListener('test', null, options);\n } catch (e) {\n // Do nothing\n }\n\n return supported;\n })(),\n\n // <input type=\"range\"> Sliders\n rangeInput: (() => {\n const range = document.createElement('input');\n range.type = 'range';\n return range.type === 'range';\n })(),\n\n // Touch\n // Remember a device can be moust + touch enabled\n touch: 'ontouchstart' in document.documentElement,\n\n // Detect transitions support\n transitions: utils.transitionEnd !== false,\n\n // Reduced motion iOS & MacOS setting\n // https://webkit.org/blog/7551/responsive-design-for-motion/\n reducedMotion: 'matchMedia' in window && window.matchMedia('(prefers-reduced-motion)').matches,\n};\n\nexport default support;\n","// ==========================================================================\n// Plyr fullscreen API\n// ==========================================================================\n\nimport utils from './utils';\n\n// Determine the prefix\nconst prefix = (() => {\n let value = false;\n\n if (utils.is.function(document.cancelFullScreen)) {\n value = '';\n } else {\n // Check for fullscreen support by vendor prefix\n ['webkit', 'o', 'moz', 'ms', 'khtml'].some(pre => {\n if (utils.is.function(document[`${pre}CancelFullScreen`])) {\n value = pre;\n return true;\n } else if (utils.is.function(document.msExitFullscreen) && document.msFullscreenEnabled) {\n // Special case for MS (when isn't it?)\n value = 'ms';\n return true;\n }\n\n return false;\n });\n }\n\n return value;\n})();\n\n// Fullscreen API\nconst fullscreen = {\n // Get the prefix\n prefix,\n\n // Check if we can use it\n enabled:\n document.fullscreenEnabled ||\n document.webkitFullscreenEnabled ||\n document.mozFullScreenEnabled ||\n document.msFullscreenEnabled,\n\n // Yet again Microsoft awesomeness,\n // Sometimes the prefix is 'ms', sometimes 'MS' to keep you on your toes\n eventType: prefix === 'ms' ? 'MSFullscreenChange' : `${prefix}fullscreenchange`,\n\n // Is an element fullscreen\n isFullScreen(element) {\n if (!fullscreen.enabled) {\n return false;\n }\n\n const target = utils.is.undefined(element) ? document.body : element;\n\n switch (prefix) {\n case '':\n return document.fullscreenElement === target;\n\n case 'moz':\n return document.mozFullScreenElement === target;\n\n default:\n return document[`${prefix}FullscreenElement`] === target;\n }\n },\n\n // Make an element fullscreen\n requestFullScreen(element) {\n if (!fullscreen.enabled) {\n return false;\n }\n\n const target = utils.is.undefined(element) ? document.body : element;\n\n return !prefix.length\n ? target.requestFullScreen()\n : target[prefix + (prefix === 'ms' ? 'RequestFullscreen' : 'RequestFullScreen')]();\n },\n\n // Bail from fullscreen\n cancelFullScreen() {\n if (!fullscreen.enabled) {\n return false;\n }\n\n return !prefix.length\n ? document.cancelFullScreen()\n : document[prefix + (prefix === 'ms' ? 'ExitFullscreen' : 'CancelFullScreen')]();\n },\n\n // Get the current element\n element() {\n if (!fullscreen.enabled) {\n return null;\n }\n\n return !prefix.length ? document.fullscreenElement : document[`${prefix}FullscreenElement`];\n },\n\n // Setup fullscreen\n setup() {\n if (!this.supported.ui || this.type === 'audio' || !this.config.fullscreen.enabled) {\n return;\n }\n\n // Check for native support\n const nativeSupport = fullscreen.enabled;\n\n if (nativeSupport || (this.config.fullscreen.fallback && !utils.inFrame())) {\n this.console.log(`${nativeSupport ? 'Native' : 'Fallback'} fullscreen enabled`);\n\n // Add styling hook to show button\n utils.toggleClass(this.elements.container, this.config.classNames.fullscreen.enabled, true);\n } else {\n this.console.log('Fullscreen not supported and fallback disabled');\n }\n\n // Toggle state\n if (this.elements.buttons && this.elements.buttons.fullscreen) {\n utils.toggleState(this.elements.buttons.fullscreen, false);\n }\n\n // Trap focus in container\n utils.trapFocus.call(this);\n },\n};\n\nexport default fullscreen;\n","// ==========================================================================\n// Plyr Event Listeners\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport controls from './controls';\nimport fullscreen from './fullscreen';\nimport storage from './storage';\nimport ui from './ui';\n\n// Sniff out the browser\nconst browser = utils.getBrowser();\n\nconst listeners = {\n // Global listeners\n global() {\n let last = null;\n\n // Get the key code for an event\n const getKeyCode = event => (event.keyCode ? event.keyCode : event.which);\n\n // Handle key press\n const handleKey = event => {\n const code = getKeyCode(event);\n const pressed = event.type === 'keydown';\n const held = pressed && code === last;\n\n // If the event is bubbled from the media element\n // Firefox doesn't get the keycode for whatever reason\n if (!utils.is.number(code)) {\n return;\n }\n\n // Seek by the number keys\n const seekByKey = () => {\n // Divide the max duration into 10th's and times by the number value\n this.currentTime = this.duration / 10 * (code - 48);\n };\n\n // Handle the key on keydown\n // Reset on keyup\n if (pressed) {\n // Which keycodes should we prevent default\n const preventDefault = [\n 48,\n 49,\n 50,\n 51,\n 52,\n 53,\n 54,\n 56,\n 57,\n 32,\n 75,\n 38,\n 40,\n 77,\n 39,\n 37,\n 70,\n 67,\n 73,\n 76,\n 79,\n ];\n\n // Check focused element\n // and if the focused element is not editable (e.g. text input)\n // and any that accept key input http://webaim.org/techniques/keyboard/\n const focused = utils.getFocusElement();\n if (utils.is.htmlElement(focused) && utils.matches(focused, this.config.selectors.editable)) {\n return;\n }\n\n // If the code is found prevent default (e.g. prevent scrolling for arrows)\n if (preventDefault.includes(code)) {\n event.preventDefault();\n event.stopPropagation();\n }\n\n switch (code) {\n case 48:\n case 49:\n case 50:\n case 51:\n case 52:\n case 53:\n case 54:\n case 55:\n case 56:\n case 57:\n // 0-9\n if (!held) {\n seekByKey();\n }\n break;\n\n case 32:\n case 75:\n // Space and K key\n if (!held) {\n this.togglePlay();\n }\n break;\n\n case 38:\n // Arrow up\n this.increaseVolume(0.1);\n break;\n\n case 40:\n // Arrow down\n this.decreaseVolume(0.1);\n break;\n\n case 77:\n // M key\n if (!held) {\n this.muted = !this.muted;\n }\n break;\n\n case 39:\n // Arrow forward\n this.forward();\n break;\n\n case 37:\n // Arrow back\n this.rewind();\n break;\n\n case 70:\n // F key\n this.toggleFullscreen();\n break;\n\n case 67:\n // C key\n if (!held) {\n this.toggleCaptions();\n }\n break;\n\n case 76:\n // L key\n this.loop = !this.loop;\n break;\n\n /* case 73:\n this.setLoop('start');\n break;\n\n case 76:\n this.setLoop();\n break;\n\n case 79:\n this.setLoop('end');\n break; */\n\n default:\n break;\n }\n\n // Escape is handle natively when in full screen\n // So we only need to worry about non native\n if (!fullscreen.enabled && this.fullscreen.active && code === 27) {\n this.toggleFullscreen();\n }\n\n // Store last code for next cycle\n last = code;\n } else {\n last = null;\n }\n };\n\n // Keyboard shortcuts\n if (this.config.keyboard.global) {\n utils.on(window, 'keydown keyup', handleKey, false);\n } else if (this.config.keyboard.focused) {\n utils.on(this.elements.container, 'keydown keyup', handleKey, false);\n }\n\n // Detect tab focus\n // Remove class on blur/focusout\n utils.on(this.elements.container, 'focusout', event => {\n utils.toggleClass(event.target, this.config.classNames.tabFocus, false);\n });\n\n // Add classname to tabbed elements\n utils.on(this.elements.container, 'keydown', event => {\n if (event.keyCode !== 9) {\n return;\n }\n\n // Delay the adding of classname until the focus has changed\n // This event fires before the focusin event\n window.setTimeout(() => {\n utils.toggleClass(utils.getFocusElement(), this.config.classNames.tabFocus, true);\n }, 0);\n });\n\n // Toggle controls visibility based on mouse movement\n if (this.config.hideControls) {\n // Toggle controls on mouse events and entering fullscreen\n utils.on(\n this.elements.container,\n 'click mouseenter mouseleave mousemove touchmove enterfullscreen exitfullscreen',\n event => {\n this.toggleControls(event);\n }\n );\n }\n\n // Handle user exiting fullscreen by escaping etc\n /* if (fullscreen.enabled) {\n utils.on(document, fullscreen.eventType, event => {\n this.toggleFullscreen(event);\n });\n } */\n },\n\n // Listen for media events\n media() {\n // Time change on media\n utils.on(this.media, 'timeupdate seeking', event => ui.timeUpdate.call(this, event));\n\n // Display duration\n utils.on(this.media, 'durationchange loadedmetadata', event => ui.durationUpdate.call(this, event));\n\n // Handle the media finishing\n utils.on(this.media, 'ended', () => {\n // Show poster on end\n if (this.type === 'video' && this.config.showPosterOnEnd) {\n // Restart\n this.restart();\n\n // Re-load media\n this.media.load();\n }\n });\n\n // Check for buffer progress\n utils.on(this.media, 'progress playing', event => ui.updateProgress.call(this, event));\n\n // Handle native mute\n utils.on(this.media, 'volumechange', event => ui.updateVolume.call(this, event));\n\n // Handle native play/pause\n utils.on(this.media, 'play pause ended', event => ui.checkPlaying.call(this, event));\n\n // Loading\n utils.on(this.media, 'waiting canplay seeked', event => ui.checkLoading.call(this, event));\n\n // Click video\n if (this.supported.ui && this.config.clickToPlay && this.type !== 'audio') {\n // Re-fetch the wrapper\n const wrapper = utils.getElement.call(this, `.${this.config.classNames.video}`);\n\n // Bail if there's no wrapper (this should never happen)\n if (!wrapper) {\n return;\n }\n\n // Set cursor\n wrapper.style.cursor = 'pointer';\n\n // On click play, pause ore restart\n utils.on(wrapper, 'click', () => {\n // Touch devices will just show controls (if we're hiding controls)\n if (this.config.hideControls && support.touch && !this.media.paused) {\n return;\n }\n\n if (this.media.paused) {\n this.play();\n } else if (this.media.ended) {\n this.restart();\n this.play();\n } else {\n this.pause();\n }\n });\n }\n\n // Disable right click\n if (this.config.disableContextMenu) {\n utils.on(\n this.media,\n 'contextmenu',\n event => {\n event.preventDefault();\n },\n false\n );\n }\n\n // Speed change\n utils.on(this.media, 'ratechange', () => {\n // Update UI\n controls.updateSetting.call(this, 'speed');\n\n // Save to storage\n storage.set.call(this, { speed: this.speed });\n });\n\n // Quality change\n utils.on(this.media, 'qualitychange', () => {\n // Update UI\n controls.updateSetting.call(this, 'quality');\n\n // Save to storage\n storage.set.call(this, { quality: this.quality });\n });\n\n // Caption language change\n utils.on(this.media, 'languagechange', () => {\n // Save to storage\n storage.set.call(this, { language: this.language });\n });\n\n // Volume change\n utils.on(this.media, 'volumechange', () => {\n // Save to storage\n storage.set.call(this, { volume: this.volume, muted: this.muted });\n });\n\n // Captions toggle\n utils.on(this.media, 'captionsenabled captionsdisabled', () => {\n // Update UI\n controls.updateSetting.call(this, 'captions');\n\n // Save to storage\n storage.set.call(this, { captions: this.captions.enabled });\n });\n\n // Proxy events to container\n // Bubble up key events for Edge\n utils.on(this.media, this.config.events.concat(['keyup', 'keydown']).join(' '), event => {\n let detail = {};\n\n // Get error details from media\n if (event.type === 'error') {\n detail = this.media.error;\n }\n\n utils.dispatchEvent.call(this, this.elements.container, event.type, true, detail);\n });\n },\n\n // Listen for control events\n controls() {\n // IE doesn't support input event, so we fallback to change\n const inputEvent = browser.isIE ? 'change' : 'input';\n\n // Trigger custom and default handlers\n const proxy = (event, handlerKey, defaultHandler) => {\n const customHandler = this.config.listeners[handlerKey];\n\n // Execute custom handler\n if (utils.is.function(customHandler)) {\n customHandler.call(this, event);\n }\n\n // Only call default handler if not prevented in custom handler\n if (!event.defaultPrevented && utils.is.function(defaultHandler)) {\n defaultHandler.call(this, event);\n }\n };\n\n // Click play/pause helper\n const togglePlay = () => {\n const play = this.togglePlay();\n\n // Determine which buttons\n const target = this.elements.buttons[play ? 'pause' : 'play'];\n\n // Transfer focus\n if (utils.is.htmlElement(target)) {\n target.focus();\n }\n };\n\n // Play\n utils.on(this.elements.buttons.play, 'click', event => proxy(event, 'play', togglePlay));\n\n // Pause\n utils.on(this.elements.buttons.pause, 'click', event => proxy(event, 'pause', togglePlay));\n\n // Pause\n utils.on(this.elements.buttons.restart, 'click', event =>\n proxy(event, 'restart', () => {\n this.restart();\n })\n );\n\n // Rewind\n utils.on(this.elements.buttons.rewind, 'click', event =>\n proxy(event, 'rewind', () => {\n this.rewind();\n })\n );\n\n // Rewind\n utils.on(this.elements.buttons.forward, 'click', event =>\n proxy(event, 'forward', () => {\n this.forward();\n })\n );\n\n // Mute\n utils.on(this.elements.buttons.mute, 'click', event =>\n proxy(event, 'mute', () => {\n this.muted = !this.muted;\n })\n );\n\n // Captions\n utils.on(this.elements.buttons.captions, 'click', event =>\n proxy(event, 'captions', () => {\n this.toggleCaptions();\n })\n );\n\n // Fullscreen\n utils.on(this.elements.buttons.fullscreen, 'click', event =>\n proxy(event, 'fullscreen', () => {\n this.toggleFullscreen();\n })\n );\n\n // Picture-in-Picture\n utils.on(this.elements.buttons.pip, 'click', event =>\n proxy(event, 'pip', () => {\n this.pip = 'toggle';\n })\n );\n\n // Airplay\n utils.on(this.elements.buttons.airplay, 'click', event =>\n proxy(event, 'airplay', () => {\n this.airPlay();\n })\n );\n\n // Settings menu\n utils.on(this.elements.buttons.settings, 'click', event => {\n controls.toggleMenu.call(this, event);\n });\n\n // Click anywhere closes menu\n utils.on(document.documentElement, 'click', event => {\n controls.toggleMenu.call(this, event);\n });\n\n // Settings menu\n utils.on(this.elements.settings.form, 'click', event => {\n // Show tab in menu\n controls.showTab.call(this, event);\n\n // Settings menu items - use event delegation as items are added/removed\n if (utils.matches(event.target, this.config.selectors.inputs.language)) {\n // Settings - Language\n proxy(event, 'language', () => {\n const language = event.target.value;\n\n this.toggleCaptions(!utils.is.empty(language));\n\n if (!utils.is.empty(language)) {\n this.language = event.target.value.toLowerCase();\n }\n });\n } else if (utils.matches(event.target, this.config.selectors.inputs.quality)) {\n // Settings - Quality\n proxy(event, 'quality', () => {\n this.quality = event.target.value;\n });\n } else if (utils.matches(event.target, this.config.selectors.inputs.speed)) {\n // Settings - Speed\n proxy(event, 'speed', () => {\n this.speed = parseFloat(event.target.value);\n });\n } /* else if (utils.matches(event.target, this.config.selectors.buttons.loop)) {\n // Settings - Looping\n // TODO: use toggle buttons\n proxy(event, 'loop', () => {\n // TODO: This should be done in the method itself I think\n // var value = event.target.getAttribute('data-loop__value') || event.target.getAttribute('data-loop__type');\n\n this.console.warn('Set loop');\n });\n } */\n });\n\n // Seek\n utils.on(this.elements.inputs.seek, inputEvent, event =>\n proxy(event, 'seek', () => {\n this.currentTime = event.target.value / event.target.max * this.duration;\n })\n );\n\n // Current time invert\n // Only if one time element is used for both currentTime and duration\n if (this.config.toggleInvert && !utils.is.htmlElement(this.elements.display.duration)) {\n utils.on(this.elements.display.currentTime, 'click', () => {\n // Do nothing if we're at the start\n if (this.currentTime === 0) {\n return;\n }\n\n this.config.invertTime = !this.config.invertTime;\n ui.timeUpdate.call(this);\n });\n }\n\n // Volume\n utils.on(this.elements.inputs.volume, inputEvent, event =>\n proxy(event, 'volume', () => {\n this.volume = event.target.value;\n })\n );\n\n // Polyfill for lower fill in <input type=\"range\"> for webkit\n if (browser.isWebkit) {\n utils.on(utils.getElements.call(this, 'input[type=\"range\"]'), 'input', event => {\n controls.updateRangeFill.call(this, event.target);\n });\n }\n\n // Seek tooltip\n utils.on(this.elements.progress, 'mouseenter mouseleave mousemove', event =>\n controls.updateSeekTooltip.call(this, event)\n );\n\n // Toggle controls visibility based on mouse movement\n if (this.config.hideControls) {\n // Watch for cursor over controls so they don't hide when trying to interact\n utils.on(this.elements.controls, 'mouseenter mouseleave', event => {\n this.elements.controls.hover = event.type === 'mouseenter';\n });\n\n // Watch for cursor over controls so they don't hide when trying to interact\n utils.on(this.elements.controls, 'mousedown mouseup touchstart touchend touchcancel', event => {\n this.elements.controls.pressed = ['mousedown', 'touchstart'].includes(event.type);\n });\n\n // Focus in/out on controls\n // TODO: Check we need capture here\n utils.on(\n this.elements.controls,\n 'focusin focusout',\n event => {\n this.toggleControls(event);\n },\n true\n );\n }\n\n // Mouse wheel for volume\n utils.on(\n this.elements.inputs.volume,\n 'wheel',\n event =>\n proxy(event, 'volume', () => {\n // Detect \"natural\" scroll - suppored on OS X Safari only\n // Other browsers on OS X will be inverted until support improves\n const inverted = event.webkitDirectionInvertedFromDevice;\n const step = 1 / 50;\n let direction = 0;\n\n // Scroll down (or up on natural) to decrease\n if (event.deltaY < 0 || event.deltaX > 0) {\n if (inverted) {\n this.decreaseVolume(step);\n direction = -1;\n } else {\n this.increaseVolume(step);\n direction = 1;\n }\n }\n\n // Scroll up (or down on natural) to increase\n if (event.deltaY > 0 || event.deltaX < 0) {\n if (inverted) {\n this.increaseVolume(step);\n direction = 1;\n } else {\n this.decreaseVolume(step);\n direction = -1;\n }\n }\n\n // Don't break page scrolling at max and min\n if ((direction === 1 && this.media.volume < 1) || (direction === -1 && this.media.volume > 0)) {\n event.preventDefault();\n }\n }),\n false\n );\n },\n};\n\nexport default listeners;\n","// ==========================================================================\n// Plyr UI\n// ==========================================================================\n\nimport utils from './utils';\nimport captions from './captions';\nimport controls from './controls';\nimport fullscreen from './fullscreen';\nimport listeners from './listeners';\n\nconst ui = {\n addStyleHook() {\n utils.toggleClass(this.elements.container, this.config.selectors.container.replace('.', ''), true);\n utils.toggleClass(this.elements.container, this.config.classNames.uiSupported, this.supported.ui);\n },\n\n // Toggle native HTML5 media controls\n toggleNativeControls(toggle = false) {\n if (toggle && this.isHTML5) {\n this.media.setAttribute('controls', '');\n } else {\n this.media.removeAttribute('controls');\n }\n },\n\n // Setup the UI\n build() {\n // Re-attach media element listeners\n // TODO: Use event bubbling\n listeners.media.call(this);\n\n // Don't setup interface if no support\n if (!this.supported.ui) {\n this.console.warn(`Basic support only for ${this.type}`);\n\n // Remove controls\n utils.removeElement.call(this, 'controls');\n\n // Remove large play\n utils.removeElement.call(this, 'buttons.play');\n\n // Restore native controls\n ui.toggleNativeControls.call(this, true);\n\n // Bail\n return;\n }\n\n // Inject custom controls if not present\n if (!utils.is.htmlElement(this.elements.controls)) {\n // Inject custom controls\n controls.inject.call(this);\n\n // Re-attach control listeners\n listeners.controls.call(this);\n }\n\n // If there's no controls, bail\n if (!utils.is.htmlElement(this.elements.controls)) {\n return;\n }\n\n // Remove native controls\n ui.toggleNativeControls.call(this);\n\n // Setup fullscreen\n fullscreen.setup.call(this);\n\n // Captions\n captions.setup.call(this);\n\n // Reset volume\n this.volume = null;\n\n // Reset mute state\n this.muted = null;\n\n // Reset speed\n this.speed = null;\n\n // Reset loop state\n this.loop = null;\n\n // Reset quality options\n this.options.quality = [];\n\n // Reset time display\n ui.timeUpdate.call(this);\n\n // Update the UI\n ui.checkPlaying.call(this);\n\n // Ready for API calls\n this.ready = true;\n\n // Ready event at end of execution stack\n utils.dispatchEvent.call(this, this.media, 'ready');\n\n // Set the title\n ui.setTitle.call(this);\n },\n\n // Setup aria attribute for play and iframe title\n setTitle() {\n // Find the current text\n let label = this.config.i18n.play;\n\n // If there's a media title set, use that for the label\n if (utils.is.string(this.config.title) && !utils.is.empty(this.config.title)) {\n label += `, ${this.config.title}`;\n\n // Set container label\n this.elements.container.setAttribute('aria-label', this.config.title);\n }\n\n // If there's a play button, set label\n if (utils.is.nodeList(this.elements.buttons.play)) {\n Array.from(this.elements.buttons.play).forEach(button => {\n button.setAttribute('aria-label', label);\n });\n }\n\n // Set iframe title\n // https://github.com/sampotts/plyr/issues/124\n if (this.isEmbed) {\n const iframe = utils.getElement.call(this, 'iframe');\n\n if (!utils.is.htmlElement(iframe)) {\n return;\n }\n\n // Default to media type\n const title = !utils.is.empty(this.config.title) ? this.config.title : 'video';\n\n iframe.setAttribute('title', this.config.i18n.frameTitle.replace('{title}', title));\n }\n },\n\n // Check playing state\n checkPlaying() {\n utils.toggleClass(this.elements.container, this.config.classNames.playing, !this.paused);\n\n utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.paused);\n\n this.toggleControls(this.paused);\n },\n\n // Check if media is loading\n checkLoading(event) {\n this.loading = event.type === 'waiting';\n\n // Clear timer\n clearTimeout(this.timers.loading);\n\n // Timer to prevent flicker when seeking\n this.timers.loading = setTimeout(() => {\n // Toggle container class hook\n utils.toggleClass(this.elements.container, this.config.classNames.loading, this.loading);\n\n // Show controls if loading, hide if done\n this.toggleControls(this.loading);\n }, this.loading ? 250 : 0);\n },\n\n // Update volume UI and storage\n updateVolume() {\n if (!this.supported.ui) {\n return;\n }\n\n // Update range\n if (utils.is.htmlElement(this.elements.inputs.volume)) {\n ui.setRange.call(this, this.elements.inputs.volume, this.muted ? 0 : this.volume);\n }\n\n // Update checkbox for mute state\n if (utils.is.htmlElement(this.elements.buttons.mute)) {\n utils.toggleState(this.elements.buttons.mute, this.muted || this.volume === 0);\n }\n },\n\n // Update seek value and lower fill\n setRange(target, value = 0) {\n if (!utils.is.htmlElement(target)) {\n return;\n }\n\n // eslint-disable-next-line\n target.value = value;\n\n // Webkit range fill\n controls.updateRangeFill.call(this, target);\n },\n\n // Set <progress> value\n setProgress(target, input) {\n const value = utils.is.number(input) ? input : 0;\n const progress = utils.is.htmlElement(target) ? target : this.elements.display.buffer;\n\n // Update value and label\n if (utils.is.htmlElement(progress)) {\n progress.value = value;\n\n // Update text label inside\n const label = progress.getElementsByTagName('span')[0];\n if (utils.is.htmlElement(label)) {\n label.childNodes[0].nodeValue = value;\n }\n }\n },\n\n // Update <progress> elements\n updateProgress(event) {\n if (!this.supported.ui || !utils.is.event(event)) {\n return;\n }\n\n let value = 0;\n\n if (event) {\n switch (event.type) {\n // Video playing\n case 'timeupdate':\n case 'seeking':\n value = utils.getPercentage(this.currentTime, this.duration);\n\n // Set seek range value only if it's a 'natural' time event\n if (event.type === 'timeupdate') {\n ui.setRange.call(this, this.elements.inputs.seek, value);\n }\n\n break;\n\n // Check buffer status\n case 'playing':\n case 'progress':\n value = (() => {\n const { buffered } = this.media;\n\n if (buffered && buffered.length) {\n // HTML5\n return utils.getPercentage(buffered.end(0), this.duration);\n } else if (utils.is.number(buffered)) {\n // YouTube returns between 0 and 1\n return buffered * 100;\n }\n\n return 0;\n })();\n\n ui.setProgress.call(this, this.elements.display.buffer, value);\n\n break;\n\n default:\n break;\n }\n }\n },\n\n // Update the displayed time\n updateTimeDisplay(target = null, time = 0, inverted = false) {\n // Bail if there's no element to display or the value isn't a number\n if (!utils.is.htmlElement(target) || !utils.is.number(time)) {\n return;\n }\n\n // Format time component to add leading zero\n const format = value => `0${value}`.slice(-2);\n\n // Helpers\n const getHours = value => parseInt((value / 60 / 60) % 60, 10);\n const getMinutes = value => parseInt((value / 60) % 60, 10);\n const getSeconds = value => parseInt(value % 60, 10);\n\n // Breakdown to hours, mins, secs\n let hours = getHours(time);\n const mins = getMinutes(time);\n const secs = getSeconds(time);\n\n // Do we need to display hours?\n if (getHours(this.duration) > 0) {\n hours = `${hours}:`;\n } else {\n hours = '';\n }\n\n // Render\n // eslint-disable-next-line no-param-reassign\n target.textContent = `${inverted ? '-' : ''}${hours}${format(mins)}:${format(secs)}`;\n },\n\n // Handle time change event\n timeUpdate(event) {\n // Only invert if only one time element is displayed and used for both duration and currentTime\n const invert = !utils.is.htmlElement(this.elements.display.duration) && this.config.invertTime;\n\n // Duration\n ui.updateTimeDisplay.call(\n this,\n this.elements.display.currentTime,\n invert ? this.duration - this.currentTime : this.currentTime,\n invert\n );\n\n // Ignore updates while seeking\n if (event && event.type === 'timeupdate' && this.media.seeking) {\n return;\n }\n\n // Playing progress\n ui.updateProgress.call(this, event);\n },\n\n // Show the duration on metadataloaded\n durationUpdate() {\n if (!this.supported.ui) {\n return;\n }\n\n // If there's only one time display, display duration there\n if (!utils.is.htmlElement(this.elements.display.duration) && this.config.displayDuration && this.paused) {\n ui.updateTimeDisplay.call(this, this.elements.display.currentTime, this.duration);\n }\n\n // If there's a duration element, update content\n if (utils.is.htmlElement(this.elements.display.duration)) {\n ui.updateTimeDisplay.call(this, this.elements.display.duration, this.duration);\n }\n\n // Update the tooltip (if visible)\n controls.updateSeekTooltip.call(this);\n },\n};\n\nexport default ui;\n","// ==========================================================================\n// Plyr controls\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport ui from './ui';\n\n// Sniff out the browser\nconst browser = utils.getBrowser();\n\nconst controls = {\n // Webkit polyfill for lower fill range\n updateRangeFill(target) {\n // WebKit only\n if (!browser.isWebkit) {\n return;\n }\n\n // Get range from event if event passed\n const range = utils.is.event(target) ? target.target : target;\n\n // Needs to be a valid <input type='range'>\n if (!utils.is.htmlElement(range) || range.getAttribute('type') !== 'range') {\n return;\n }\n\n // Inject the stylesheet if needed\n if (!utils.is.htmlElement(this.elements.styleSheet)) {\n this.elements.styleSheet = utils.createElement('style');\n this.elements.container.appendChild(this.elements.styleSheet);\n }\n\n const styleSheet = this.elements.styleSheet.sheet;\n const percentage = range.value / range.max * 100;\n const selector = `#${range.id}::-webkit-slider-runnable-track`;\n const styles = `{ background-image: linear-gradient(to right, currentColor ${percentage}%, transparent ${percentage}%) }`;\n\n // Find old rule if it exists\n const index = Array.from(styleSheet.rules).findIndex(rule => rule.selectorText === selector);\n\n // Remove old rule\n if (index !== -1) {\n styleSheet.deleteRule(index);\n }\n\n // Insert new one\n styleSheet.insertRule([selector, styles].join(' '));\n },\n\n // Get icon URL\n getIconUrl() {\n return {\n url: this.config.iconUrl,\n absolute: this.config.iconUrl.indexOf('http') === 0 || (browser.isIE && !window.svg4everybody),\n };\n },\n\n // Create <svg> icon\n createIcon(type, attributes) {\n const namespace = 'http://www.w3.org/2000/svg';\n const iconUrl = controls.getIconUrl.call(this);\n const iconPath = `${!iconUrl.absolute ? iconUrl.url : ''}#${this.config.iconPrefix}`;\n\n // Create <svg>\n const icon = document.createElementNS(namespace, 'svg');\n utils.setAttributes(\n icon,\n utils.extend(attributes, {\n role: 'presentation',\n })\n );\n\n // Create the <use> to reference sprite\n const use = document.createElementNS(namespace, 'use');\n const path = `${iconPath}-${type}`;\n\n // Set `href` attributes\n // https://github.com/sampotts/plyr/issues/460\n // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', path);\n use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', path);\n\n // Add <use> to <svg>\n icon.appendChild(use);\n\n return icon;\n },\n\n // Create hidden text label\n createLabel(type) {\n let text = this.config.i18n[type];\n\n switch (type) {\n case 'pip':\n text = 'PIP';\n break;\n\n case 'airplay':\n text = 'AirPlay';\n break;\n\n default:\n break;\n }\n\n return utils.createElement(\n 'span',\n {\n class: this.config.classNames.hidden,\n },\n text\n );\n },\n\n // Create a badge\n createBadge(text) {\n if (utils.is.empty(text)) {\n return null;\n }\n\n const badge = utils.createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n badge.appendChild(\n utils.createElement(\n 'span',\n {\n class: this.config.classNames.menu.badge,\n },\n text\n )\n );\n\n return badge;\n },\n\n // Create a <button>\n createButton(buttonType, attr) {\n const button = utils.createElement('button');\n const attributes = Object.assign({}, attr);\n let type = buttonType;\n let iconDefault;\n let iconToggled;\n let labelKey;\n\n if (!('type' in attributes)) {\n attributes.type = 'button';\n }\n\n if ('class' in attributes) {\n if (attributes.class.indexOf(this.config.classNames.control) === -1) {\n attributes.class += ` ${this.config.classNames.control}`;\n }\n } else {\n attributes.class = this.config.classNames.control;\n }\n\n // Large play button\n switch (type) {\n case 'mute':\n labelKey = 'toggleMute';\n iconDefault = 'volume';\n iconToggled = 'muted';\n break;\n\n case 'captions':\n labelKey = 'toggleCaptions';\n iconDefault = 'captions-off';\n iconToggled = 'captions-on';\n break;\n\n case 'fullscreen':\n labelKey = 'toggleFullscreen';\n iconDefault = 'enter-fullscreen';\n iconToggled = 'exit-fullscreen';\n break;\n\n case 'play-large':\n attributes.class = 'plyr__play-large';\n type = 'play';\n labelKey = 'play';\n iconDefault = 'play';\n break;\n\n default:\n labelKey = type;\n iconDefault = type;\n }\n\n // Merge attributes\n utils.extend(attributes, utils.getAttributesFromSelector(this.config.selectors.buttons[type], attributes));\n\n // Add toggle icon if needed\n if (utils.is.string(iconToggled)) {\n button.appendChild(\n controls.createIcon.call(this, iconToggled, {\n class: 'icon--pressed',\n })\n );\n button.appendChild(\n controls.createIcon.call(this, iconDefault, {\n class: 'icon--not-pressed',\n })\n );\n } else {\n button.appendChild(controls.createIcon.call(this, iconDefault));\n }\n\n button.appendChild(controls.createLabel.call(this, labelKey));\n\n utils.setAttributes(button, attributes);\n\n this.elements.buttons[type] = button;\n\n return button;\n },\n\n // Create an <input type='range'>\n createRange(type, attributes) {\n // Seek label\n const label = utils.createElement(\n 'label',\n {\n for: attributes.id,\n class: this.config.classNames.hidden,\n },\n this.config.i18n[type]\n );\n\n // Seek input\n const input = utils.createElement(\n 'input',\n utils.extend(\n utils.getAttributesFromSelector(this.config.selectors.inputs[type]),\n {\n type: 'range',\n min: 0,\n max: 100,\n step: 0.01,\n value: 0,\n autocomplete: 'off',\n },\n attributes\n )\n );\n\n this.elements.inputs[type] = input;\n\n // Set the fill for webkit now\n controls.updateRangeFill.call(this, input);\n\n return {\n label,\n input,\n };\n },\n\n // Create a <progress>\n createProgress(type, attributes) {\n const progress = utils.createElement(\n 'progress',\n utils.extend(\n utils.getAttributesFromSelector(this.config.selectors.display[type]),\n {\n min: 0,\n max: 100,\n value: 0,\n },\n attributes\n )\n );\n\n // Create the label inside\n if (type !== 'volume') {\n progress.appendChild(utils.createElement('span', null, '0'));\n\n let suffix = '';\n switch (type) {\n case 'played':\n suffix = this.config.i18n.played;\n break;\n\n case 'buffer':\n suffix = this.config.i18n.buffered;\n break;\n\n default:\n break;\n }\n\n progress.textContent = `% ${suffix.toLowerCase()}`;\n }\n\n this.elements.display[type] = progress;\n\n return progress;\n },\n\n // Create time display\n createTime(type) {\n const container = utils.createElement('span', {\n class: 'plyr__time',\n });\n\n container.appendChild(\n utils.createElement(\n 'span',\n {\n class: this.config.classNames.hidden,\n },\n this.config.i18n[type]\n )\n );\n\n container.appendChild(\n utils.createElement('span', utils.getAttributesFromSelector(this.config.selectors.display[type]), '00:00')\n );\n\n this.elements.display[type] = container;\n\n return container;\n },\n\n // Create a settings menu item\n createMenuItem(value, list, type, title, badge = null, checked = false) {\n const item = utils.createElement('li');\n\n const label = utils.createElement('label', {\n class: this.config.classNames.control,\n });\n\n const radio = utils.createElement(\n 'input',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs[type]), {\n type: 'radio',\n name: `plyr-${type}`,\n value,\n checked,\n class: 'plyr__sr-only',\n })\n );\n\n const faux = utils.createElement('span', { 'aria-hidden': true });\n\n label.appendChild(radio);\n label.appendChild(faux);\n label.insertAdjacentHTML('beforeend', title);\n\n if (utils.is.htmlElement(badge)) {\n label.appendChild(badge);\n }\n\n item.appendChild(label);\n list.appendChild(item);\n },\n\n // Update hover tooltip for seeking\n updateSeekTooltip(event) {\n // Bail if setting not true\n if (\n !this.config.tooltips.seek ||\n !utils.is.htmlElement(this.elements.inputs.seek) ||\n !utils.is.htmlElement(this.elements.display.seekTooltip) ||\n this.duration === 0\n ) {\n return;\n }\n\n // Calculate percentage\n let percent = 0;\n const clientRect = this.elements.inputs.seek.getBoundingClientRect();\n const visible = `${this.config.classNames.tooltip}--visible`;\n\n // Determine percentage, if already visible\n if (utils.is.event(event)) {\n percent = 100 / clientRect.width * (event.pageX - clientRect.left);\n } else if (utils.hasClass(this.elements.display.seekTooltip, visible)) {\n percent = this.elements.display.seekTooltip.style.left.replace('%', '');\n } else {\n return;\n }\n\n // Set bounds\n if (percent < 0) {\n percent = 0;\n } else if (percent > 100) {\n percent = 100;\n }\n\n // Display the time a click would seek to\n ui.updateTimeDisplay.call(this, this.elements.display.seekTooltip, this.duration / 100 * percent);\n\n // Set position\n this.elements.display.seekTooltip.style.left = `${percent}%`;\n\n // Show/hide the tooltip\n // If the event is a moues in/out and percentage is inside bounds\n if (utils.is.event(event) && ['mouseenter', 'mouseleave'].includes(event.type)) {\n utils.toggleClass(this.elements.display.seekTooltip, visible, event.type === 'mouseenter');\n }\n },\n\n // Hide/show a tab\n toggleTab(setting, toggle) {\n const tab = this.elements.settings.tabs[setting];\n const pane = this.elements.settings.panes[setting];\n\n if (utils.is.htmlElement(tab)) {\n if (toggle) {\n tab.removeAttribute('hidden');\n } else {\n tab.setAttribute('hidden', '');\n }\n }\n\n if (utils.is.htmlElement(pane)) {\n if (toggle) {\n pane.removeAttribute('hidden');\n } else {\n pane.setAttribute('hidden', '');\n }\n }\n },\n\n // Set the YouTube quality menu\n // TODO: Support for HTML5\n setQualityMenu(options) {\n const type = 'quality';\n const list = this.elements.settings.panes.quality.querySelector('ul');\n\n // Set options if passed and filter based on config\n if (utils.is.array(options)) {\n this.options.quality = options.filter(quality => this.config.quality.options.includes(quality));\n } else {\n this.options.quality = this.config.quality.options;\n }\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.options.quality) && this.type === 'youtube';\n controls.toggleTab.call(this, type, toggle);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Empty the menu\n utils.emptyElement(list);\n\n // Get the badge HTML for HD, 4K etc\n const getBadge = quality => {\n let label = '';\n\n switch (quality) {\n case 'hd2160':\n label = '4K';\n break;\n\n case 'hd1440':\n label = 'WQHD';\n break;\n\n case 'hd1080':\n label = 'HD';\n break;\n\n case 'hd720':\n label = 'HD';\n break;\n\n default:\n break;\n }\n\n if (!label.length) {\n return null;\n }\n\n return controls.createBadge.call(this, label);\n };\n\n this.options.quality.forEach(quality =>\n controls.createMenuItem.call(\n this,\n quality,\n list,\n type,\n controls.getLabel.call(this, 'quality', quality),\n getBadge(quality)\n )\n );\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Translate a value into a nice label\n // TODO: Localisation\n getLabel(setting, value) {\n switch (setting) {\n case 'speed':\n return value === 1 ? 'Normal' : `${value}×`;\n\n case 'quality':\n switch (value) {\n case 'hd2160':\n return '2160P';\n case 'hd1440':\n return '1440P';\n case 'hd1080':\n return '1080P';\n case 'hd720':\n return '720P';\n case 'large':\n return '480P';\n case 'medium':\n return '360P';\n case 'small':\n return '240P';\n case 'tiny':\n return 'Tiny';\n case 'default':\n return 'Auto';\n default:\n return value;\n }\n\n case 'captions':\n return controls.getLanguage.call(this);\n\n default:\n return null;\n }\n },\n\n // Update the selected setting\n updateSetting(setting, container) {\n const pane = this.elements.settings.panes[setting];\n let value = null;\n let list = container;\n\n switch (setting) {\n case 'captions':\n value = this.captions.language;\n\n if (!this.captions.enabled) {\n value = '';\n }\n\n break;\n\n default:\n value = this[setting];\n\n // Get default\n if (utils.is.empty(value)) {\n value = this.config[setting].default;\n }\n\n // Unsupported value\n if (!this.options[setting].includes(value)) {\n this.console.warn(`Unsupported value of '${value}' for ${setting}`);\n return;\n }\n\n // Disabled value\n if (!this.config[setting].options.includes(value)) {\n this.console.warn(`Disabled value of '${value}' for ${setting}`);\n return;\n }\n\n break;\n }\n\n // Get the list if we need to\n if (!utils.is.htmlElement(list)) {\n list = pane && pane.querySelector('ul');\n }\n\n // Find the radio option\n const target = list && list.querySelector(`input[value=\"${value}\"]`);\n\n if (!utils.is.htmlElement(target)) {\n return;\n }\n\n // Check it\n target.checked = true;\n\n // Find the label\n const label = this.elements.settings.tabs[setting].querySelector(`.${this.config.classNames.menu.value}`);\n label.innerHTML = controls.getLabel.call(this, setting, value);\n },\n\n // Set the looping options\n /* setLoopMenu() {\n const options = ['start', 'end', 'all', 'reset'];\n const list = this.elements.settings.panes.loop.querySelector('ul');\n\n // Show the pane and tab\n this.elements.settings.tabs.loop.removeAttribute('hidden');\n this.elements.settings.panes.loop.removeAttribute('hidden');\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.loop.options);\n controls.toggleTab.call(this, 'loop', toggle);\n\n // Empty the menu\n utils.emptyElement(list);\n\n options.forEach(option => {\n const item = utils.createElement('li');\n\n const button = utils.createElement(\n 'button',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.buttons.loop), {\n type: 'button',\n class: this.config.classNames.control,\n 'data-plyr-loop-action': option,\n }),\n this.config.i18n[option]\n );\n\n if (['start', 'end'].includes(option)) {\n const badge = controls.createBadge.call(this, '00:00');\n button.appendChild(badge);\n }\n\n item.appendChild(button);\n list.appendChild(item);\n });\n }, */\n\n // Get current selected caption language\n // TODO: rework this to user the getter in the API?\n getLanguage() {\n if (!this.supported.ui) {\n return null;\n }\n\n if (!support.textTracks || utils.is.empty(this.captions.tracks)) {\n return this.config.i18n.none;\n }\n\n if (this.captions.enabled) {\n return this.captions.currentTrack.label;\n }\n\n return this.config.i18n.disabled;\n },\n\n // Set a list of available captions languages\n setCaptionsMenu() {\n // TODO: Captions or language? Currently it's mixed\n const type = 'captions';\n const list = this.elements.settings.panes.captions.querySelector('ul');\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.captions.tracks);\n controls.toggleTab.call(this, type, toggle);\n\n // Empty the menu\n utils.emptyElement(list);\n\n // If there's no captions, bail\n if (utils.is.empty(this.captions.tracks)) {\n return;\n }\n\n // Re-map the tracks into just the data we need\n const tracks = Array.from(this.captions.tracks).map(track => ({\n language: track.language,\n label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase(),\n }));\n\n // Add the \"None\" option to turn off captions\n tracks.unshift({\n language: '',\n label: this.config.i18n.none,\n });\n\n // Generate options\n tracks.forEach(track => {\n controls.createMenuItem.call(\n this,\n track.language,\n list,\n 'language',\n track.label || track.language,\n controls.createBadge.call(this, track.language.toUpperCase()),\n track.language.toLowerCase() === this.captions.language.toLowerCase()\n );\n });\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Set a list of available captions languages\n setSpeedMenu(options) {\n const type = 'speed';\n\n // Set options if passed and filter based on config\n if (utils.is.array(options)) {\n this.options.speed = options.filter(speed => this.config.speed.options.includes(speed));\n } else {\n this.options.speed = this.config.speed.options;\n }\n\n // Toggle the pane and tab\n const toggle = !utils.is.empty(this.options.speed);\n controls.toggleTab.call(this, type, toggle);\n\n // If we're hiding, nothing more to do\n if (!toggle) {\n return;\n }\n\n // Get the list to populate\n const list = this.elements.settings.panes.speed.querySelector('ul');\n\n // Show the pane and tab\n this.elements.settings.tabs.speed.removeAttribute('hidden');\n this.elements.settings.panes.speed.removeAttribute('hidden');\n\n // Empty the menu\n utils.emptyElement(list);\n\n // Create items\n this.options.speed.forEach(speed =>\n controls.createMenuItem.call(this, speed, list, type, controls.getLabel.call(this, 'speed', speed))\n );\n\n controls.updateSetting.call(this, type, list);\n },\n\n // Show/hide menu\n toggleMenu(event) {\n const { form } = this.elements.settings;\n const button = this.elements.buttons.settings;\n const show = utils.is.boolean(event)\n ? event\n : utils.is.htmlElement(form) && form.getAttribute('aria-hidden') === 'true';\n\n if (utils.is.event(event)) {\n const isMenuItem = utils.is.htmlElement(form) && form.contains(event.target);\n const isButton = event.target === this.elements.buttons.settings;\n\n // If the click was inside the form or if the click\n // wasn't the button or menu item and we're trying to\n // show the menu (a doc click shouldn't show the menu)\n if (isMenuItem || (!isMenuItem && !isButton && show)) {\n return;\n }\n\n // Prevent the toggle being caught by the doc listener\n if (isButton) {\n event.stopPropagation();\n }\n }\n\n // Set form and button attributes\n if (utils.is.htmlElement(button)) {\n button.setAttribute('aria-expanded', show);\n }\n\n if (utils.is.htmlElement(form)) {\n form.setAttribute('aria-hidden', !show);\n\n if (show) {\n form.removeAttribute('tabindex');\n } else {\n form.setAttribute('tabindex', -1);\n }\n }\n },\n\n // Get the natural size of a tab\n getTabSize(tab) {\n const clone = tab.cloneNode(true);\n clone.style.position = 'absolute';\n clone.style.opacity = 0;\n clone.setAttribute('aria-hidden', false);\n\n // Prevent input's being unchecked due to the name being identical\n Array.from(clone.querySelectorAll('input[name]')).forEach(input => {\n const name = input.getAttribute('name');\n input.setAttribute('name', `${name}-clone`);\n });\n\n // Append to parent so we get the \"real\" size\n tab.parentNode.appendChild(clone);\n\n // Get the sizes before we remove\n const width = clone.scrollWidth;\n const height = clone.scrollHeight;\n\n // Remove from the DOM\n utils.removeElement(clone);\n\n return {\n width,\n height,\n };\n },\n\n // Toggle Menu\n showTab(event) {\n const { menu } = this.elements.settings;\n const tab = event.target;\n const show = tab.getAttribute('aria-expanded') === 'false';\n const pane = document.getElementById(tab.getAttribute('aria-controls'));\n\n // Nothing to show, bail\n if (!utils.is.htmlElement(pane)) {\n return;\n }\n\n // Are we targetting a tab? If not, bail\n const isTab = pane.getAttribute('role') === 'tabpanel';\n if (!isTab) {\n return;\n }\n\n // Hide all other tabs\n // Get other tabs\n const current = menu.querySelector('[role=\"tabpanel\"][aria-hidden=\"false\"]');\n const container = current.parentNode;\n\n // Set other toggles to be expanded false\n Array.from(menu.querySelectorAll(`[aria-controls=\"${current.getAttribute('id')}\"]`)).forEach(toggle => {\n toggle.setAttribute('aria-expanded', false);\n });\n\n // If we can do fancy animations, we'll animate the height/width\n if (support.transitions && !support.reducedMotion) {\n // Set the current width as a base\n container.style.width = `${current.scrollWidth}px`;\n container.style.height = `${current.scrollHeight}px`;\n\n // Get potential sizes\n const size = controls.getTabSize.call(this, pane);\n\n // Restore auto height/width\n const restore = e => {\n // We're only bothered about height and width on the container\n if (e.target !== container || !['width', 'height'].includes(e.propertyName)) {\n return;\n }\n\n // Revert back to auto\n container.style.width = '';\n container.style.height = '';\n\n // Only listen once\n utils.off(container, utils.transitionEnd, restore);\n };\n\n // Listen for the transition finishing and restore auto height/width\n utils.on(container, utils.transitionEnd, restore);\n\n // Set dimensions to target\n container.style.width = `${size.width}px`;\n container.style.height = `${size.height}px`;\n }\n\n // Set attributes on current tab\n current.setAttribute('aria-hidden', true);\n current.setAttribute('tabindex', -1);\n\n // Set attributes on target\n pane.setAttribute('aria-hidden', !show);\n tab.setAttribute('aria-expanded', show);\n pane.removeAttribute('tabindex');\n\n // Focus the first item\n pane.querySelectorAll('button:not(:disabled), input:not(:disabled), [tabindex]')[0].focus();\n },\n\n // Build the default HTML\n // TODO: Set order based on order in the config.controls array?\n create(data) {\n // Do nothing if we want no controls\n if (utils.is.empty(this.config.controls)) {\n return null;\n }\n\n // Create the container\n const container = utils.createElement(\n 'div',\n utils.getAttributesFromSelector(this.config.selectors.controls.wrapper)\n );\n\n // Restart button\n if (this.config.controls.includes('restart')) {\n container.appendChild(controls.createButton.call(this, 'restart'));\n }\n\n // Rewind button\n if (this.config.controls.includes('rewind')) {\n container.appendChild(controls.createButton.call(this, 'rewind'));\n }\n\n // Play Pause button\n if (this.config.controls.includes('play')) {\n container.appendChild(controls.createButton.call(this, 'play'));\n container.appendChild(controls.createButton.call(this, 'pause'));\n }\n\n // Fast forward button\n if (this.config.controls.includes('fast-forward')) {\n container.appendChild(controls.createButton.call(this, 'fast-forward'));\n }\n\n // Progress\n if (this.config.controls.includes('progress')) {\n const progress = utils.createElement(\n 'span',\n utils.getAttributesFromSelector(this.config.selectors.progress)\n );\n\n // Seek range slider\n const seek = controls.createRange.call(this, 'seek', {\n id: `plyr-seek-${data.id}`,\n });\n progress.appendChild(seek.label);\n progress.appendChild(seek.input);\n\n // Buffer progress\n progress.appendChild(controls.createProgress.call(this, 'buffer'));\n\n // TODO: Add loop display indicator\n\n // Seek tooltip\n if (this.config.tooltips.seek) {\n const tooltip = utils.createElement(\n 'span',\n {\n role: 'tooltip',\n class: this.config.classNames.tooltip,\n },\n '00:00'\n );\n\n progress.appendChild(tooltip);\n this.elements.display.seekTooltip = tooltip;\n }\n\n this.elements.progress = progress;\n container.appendChild(this.elements.progress);\n }\n\n // Media current time display\n if (this.config.controls.includes('current-time')) {\n container.appendChild(controls.createTime.call(this, 'currentTime'));\n }\n\n // Media duration display\n if (this.config.controls.includes('duration')) {\n container.appendChild(controls.createTime.call(this, 'duration'));\n }\n\n // Toggle mute button\n if (this.config.controls.includes('mute')) {\n container.appendChild(controls.createButton.call(this, 'mute'));\n }\n\n // Volume range control\n if (this.config.controls.includes('volume')) {\n const volume = utils.createElement('span', {\n class: 'plyr__volume',\n });\n\n // Set the attributes\n const attributes = {\n max: 1,\n step: 0.05,\n value: this.config.volume,\n };\n\n // Create the volume range slider\n const range = controls.createRange.call(\n this,\n 'volume',\n utils.extend(attributes, {\n id: `plyr-volume-${data.id}`,\n })\n );\n volume.appendChild(range.label);\n volume.appendChild(range.input);\n\n container.appendChild(volume);\n }\n\n // Toggle captions button\n if (this.config.controls.includes('captions')) {\n container.appendChild(controls.createButton.call(this, 'captions'));\n }\n\n // Settings button / menu\n if (this.config.controls.includes('settings') && !utils.is.empty(this.config.settings)) {\n const menu = utils.createElement('div', {\n class: 'plyr__menu',\n });\n\n menu.appendChild(\n controls.createButton.call(this, 'settings', {\n id: `plyr-settings-toggle-${data.id}`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}`,\n 'aria-expanded': false,\n })\n );\n\n const form = utils.createElement('form', {\n class: 'plyr__menu__container',\n id: `plyr-settings-${data.id}`,\n 'aria-hidden': true,\n 'aria-labelled-by': `plyr-settings-toggle-${data.id}`,\n role: 'tablist',\n tabindex: -1,\n });\n\n const inner = utils.createElement('div');\n\n const home = utils.createElement('div', {\n id: `plyr-settings-${data.id}-home`,\n 'aria-hidden': false,\n 'aria-labelled-by': `plyr-settings-toggle-${data.id}`,\n role: 'tabpanel',\n });\n\n // Create the tab list\n const tabs = utils.createElement('ul', {\n role: 'tablist',\n });\n\n // Build the tabs\n this.config.settings.forEach(type => {\n const tab = utils.createElement('li', {\n role: 'tab',\n hidden: '',\n });\n\n const button = utils.createElement(\n 'button',\n utils.extend(utils.getAttributesFromSelector(this.config.selectors.buttons.settings), {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--forward`,\n id: `plyr-settings-${data.id}-${type}-tab`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}-${type}`,\n 'aria-expanded': false,\n }),\n this.config.i18n[type]\n );\n\n const value = utils.createElement('span', {\n class: this.config.classNames.menu.value,\n });\n\n // Speed contains HTML entities\n value.innerHTML = data[type];\n\n button.appendChild(value);\n tab.appendChild(button);\n tabs.appendChild(tab);\n\n this.elements.settings.tabs[type] = tab;\n });\n\n home.appendChild(tabs);\n inner.appendChild(home);\n\n // Build the panes\n this.config.settings.forEach(type => {\n const pane = utils.createElement('div', {\n id: `plyr-settings-${data.id}-${type}`,\n 'aria-hidden': true,\n 'aria-labelled-by': `plyr-settings-${data.id}-${type}-tab`,\n role: 'tabpanel',\n tabindex: -1,\n hidden: '',\n });\n\n const back = utils.createElement(\n 'button',\n {\n type: 'button',\n class: `${this.config.classNames.control} ${this.config.classNames.control}--back`,\n 'aria-haspopup': true,\n 'aria-controls': `plyr-settings-${data.id}-home`,\n 'aria-expanded': false,\n },\n this.config.i18n[type]\n );\n\n pane.appendChild(back);\n\n const options = utils.createElement('ul');\n\n pane.appendChild(options);\n inner.appendChild(pane);\n\n this.elements.settings.panes[type] = pane;\n });\n\n form.appendChild(inner);\n menu.appendChild(form);\n container.appendChild(menu);\n\n this.elements.settings.form = form;\n this.elements.settings.menu = menu;\n }\n\n // Picture in picture button\n if (this.config.controls.includes('pip') && support.pip) {\n container.appendChild(controls.createButton.call(this, 'pip'));\n }\n\n // Airplay button\n if (this.config.controls.includes('airplay') && support.airplay) {\n container.appendChild(controls.createButton.call(this, 'airplay'));\n }\n\n // Toggle fullscreen button\n if (this.config.controls.includes('fullscreen')) {\n container.appendChild(controls.createButton.call(this, 'fullscreen'));\n }\n\n // Larger overlaid play button\n if (this.config.controls.includes('play-large')) {\n this.elements.container.appendChild(controls.createButton.call(this, 'play-large'));\n }\n\n this.elements.controls = container;\n\n if (this.config.controls.includes('settings') && this.config.settings.includes('speed')) {\n controls.setSpeedMenu.call(this);\n }\n\n return container;\n },\n\n // Insert controls\n inject() {\n // Sprite\n if (this.config.loadSprite) {\n const icon = controls.getIconUrl.call(this);\n\n // Only load external sprite using AJAX\n if (icon.absolute) {\n utils.loadSprite(icon.url, 'sprite-plyr');\n }\n }\n\n // Create a unique ID\n this.id = Math.floor(Math.random() * 10000);\n\n // Null by default\n let container = null;\n\n // HTML passed as the option\n if (utils.is.string(this.config.controls)) {\n container = this.config.controls;\n } else if (utils.is.function(this.config.controls)) {\n // A custom function to build controls\n // The function can return a HTMLElement or String\n container = this.config.controls({\n id: this.id,\n seektime: this.config.seekTime,\n title: this.config.title,\n });\n } else {\n // Create controls\n container = controls.create.call(this, {\n id: this.id,\n seektime: this.config.seekTime,\n speed: this.speed,\n quality: this.quality,\n captions: controls.getLanguage.call(this),\n // TODO: Looping\n // loop: 'None',\n });\n }\n\n // Controls container\n let target;\n\n // Inject to custom location\n if (utils.is.string(this.config.selectors.controls.container)) {\n target = document.querySelector(this.config.selectors.controls.container);\n }\n\n // Inject into the container by default\n if (!utils.is.htmlElement(target)) {\n target = this.elements.container;\n }\n\n // Inject controls HTML\n if (utils.is.htmlElement(container)) {\n target.appendChild(container);\n } else {\n target.insertAdjacentHTML('beforeend', container);\n }\n\n // Find the elements if need be\n if (utils.is.htmlElement(this.elements.controls)) {\n utils.findElements.call(this);\n }\n\n // Setup tooltips\n if (this.config.tooltips.controls) {\n const labels = utils.getElements.call(\n this,\n [\n this.config.selectors.controls.wrapper,\n ' ',\n this.config.selectors.labels,\n ' .',\n this.config.classNames.hidden,\n ].join('')\n );\n\n Array.from(labels).forEach(label => {\n utils.toggleClass(label, this.config.classNames.hidden, false);\n utils.toggleClass(label, this.config.classNames.tooltip, true);\n });\n }\n },\n};\n\nexport default controls;\n","// ==========================================================================\n// Plyr Captions\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport controls from './controls';\nimport storage from './storage';\n\nconst captions = {\n // Setup captions\n setup() {\n // Requires UI support\n if (!this.supported.ui) {\n return;\n }\n\n // Set default language if not set\n if (!utils.is.empty(storage.get.call(this).language)) {\n this.captions.language = storage.get.call(this).language;\n } else if (utils.is.empty(this.captions.language)) {\n this.captions.language = this.config.captions.language.toLowerCase();\n }\n\n // Set captions enabled state if not set\n if (!utils.is.boolean(this.captions.enabled)) {\n if (!utils.is.empty(storage.get.call(this).language)) {\n this.captions.enabled = storage.get.call(this).captions;\n } else {\n this.captions.enabled = this.config.captions.active;\n }\n }\n\n // Only Vimeo and HTML5 video supported at this point\n if (!['video', 'vimeo'].includes(this.type) || (this.type === 'video' && !support.textTracks)) {\n this.captions.tracks = null;\n\n // Clear menu and hide\n if (this.config.controls.includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n\n return;\n }\n\n // Inject the container\n if (!utils.is.htmlElement(this.elements.captions)) {\n this.elements.captions = utils.createElement(\n 'div',\n utils.getAttributesFromSelector(this.config.selectors.captions)\n );\n utils.insertAfter(this.elements.captions, this.elements.wrapper);\n }\n\n // Get tracks from HTML5\n if (this.type === 'video') {\n this.captions.tracks = this.media.textTracks;\n }\n\n // Set the class hook\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.captions.enabled,\n !utils.is.empty(this.captions.tracks)\n );\n\n // If no caption file exists, hide container for caption text\n if (utils.is.empty(this.captions.tracks)) {\n return;\n }\n\n // Enable UI\n captions.show.call(this);\n\n // Get a track\n const setCurrentTrack = () => {\n // Reset by default\n this.captions.currentTrack = null;\n\n // Filter doesn't seem to work for a TextTrackList :-(\n Array.from(this.captions.tracks).forEach(track => {\n if (track.language.toLowerCase() === this.language.toLowerCase()) {\n this.captions.currentTrack = track;\n console.warn(`Set current track to ${this.language}`);\n }\n });\n };\n\n // Get current track\n setCurrentTrack();\n\n // If we couldn't get the requested language, revert to default\n if (!utils.is.track(this.captions.currentTrack)) {\n const { language } = this.config.captions;\n\n // Reset to default\n // We don't update user storage as the selected language could become available\n this.captions.language = language;\n\n // Get fallback track\n setCurrentTrack();\n\n // If no match, disable captions\n if (!utils.is.track(this.captions.currentTrack)) {\n this.toggleCaptions(false);\n }\n\n controls.updateSetting.call(this, 'captions');\n }\n\n // Setup HTML5 track rendering\n if (this.type === 'video') {\n // Turn off native caption rendering to avoid double captions\n Array.from(this.captions.tracks).forEach(track => {\n // Remove previous bindings (if we've changed source or language)\n utils.off(track, 'cuechange', event => captions.setCue.call(this, event));\n\n // Hide captions\n // eslint-disable-next-line\n track.mode = 'hidden';\n });\n\n // Check if suported kind\n const supported =\n this.captions.currentTrack && ['captions', 'subtitles'].includes(this.captions.currentTrack.kind);\n\n if (utils.is.track(this.captions.currentTrack) && supported) {\n utils.on(this.captions.currentTrack, 'cuechange', event => captions.setCue.call(this, event));\n\n // If we change the active track while a cue is already displayed we need to update it\n if (this.captions.currentTrack.activeCues && this.captions.currentTrack.activeCues.length > 0) {\n captions.setCue.call(this, this.captions.currentTrack);\n }\n }\n } else if (this.type === 'vimeo' && this.captions.active) {\n this.embed.enableTextTrack(this.captions.language);\n }\n\n // Set available languages in list\n if (this.config.controls.includes('settings') && this.config.settings.includes('captions')) {\n controls.setCaptionsMenu.call(this);\n }\n },\n\n // Display active caption if it contains text\n setCue(input) {\n // Get the track from the event if needed\n const track = utils.is.event(input) ? input.target : input;\n const active = track.activeCues[0];\n\n // Display a cue, if there is one\n if (utils.is.cue(active)) {\n captions.set.call(this, active.getCueAsHTML());\n } else {\n captions.set.call(this);\n }\n\n utils.dispatchEvent.call(this, this.media, 'cuechange');\n },\n\n // Set the current caption\n set(input) {\n // Requires UI\n if (!this.supported.ui) {\n return;\n }\n\n if (utils.is.htmlElement(this.elements.captions)) {\n const content = utils.createElement('span');\n\n // Empty the container\n utils.emptyElement(this.elements.captions);\n\n // Default to empty\n const caption = !utils.is.undefined(input) ? input : '';\n\n // Set the span content\n if (utils.is.string(caption)) {\n content.textContent = caption.trim();\n } else {\n content.appendChild(caption);\n }\n\n // Set new caption text\n this.elements.captions.appendChild(content);\n } else {\n this.console.warn('No captions element to render to');\n }\n },\n\n // Display captions container and button (for initialization)\n show() {\n // If there's no caption toggle, bail\n if (!utils.is.htmlElement(this.elements.buttons.captions)) {\n return;\n }\n\n // Try to load the value from storage\n let active = storage.get.call(this).captions;\n\n // Otherwise fall back to the default config\n if (!utils.is.boolean(active)) {\n ({ active } = this.config.captions);\n } else {\n this.captions.active = active;\n }\n\n if (active) {\n utils.toggleClass(this.elements.container, this.config.classNames.captions.active, true);\n utils.toggleState(this.elements.buttons.captions, true);\n }\n },\n};\n\nexport default captions;\n","// ==========================================================================\n// YouTube plugin\n// ==========================================================================\n\nimport utils from './../utils';\nimport controls from './../controls';\nimport ui from './../ui';\n\nconst youtube = {\n setup() {\n const videoId = utils.parseYouTubeId(this.embedId);\n\n // Remove old containers\n const containers = utils.getElements.call(this, `[id^=\"${this.type}-\"]`);\n Array.from(containers).forEach(utils.removeElement);\n\n // Add embed class for responsive\n utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true);\n\n // Set aspect ratio\n youtube.setAspectRatio.call(this);\n\n // Set ID\n this.media.setAttribute('id', utils.generateId(this.type));\n\n // Get the media title via Google API\n const key = this.config.keys.google;\n if (utils.is.string(key) && !utils.is.empty(key)) {\n const url = `https://www.googleapis.com/youtube/v3/videos?id=${videoId}&key=${key}&fields=items(snippet(title))&part=snippet`;\n\n fetch(url)\n .then(response => (response.ok ? response.json() : null))\n .then(result => {\n if (result !== null && utils.is.object(result)) {\n this.config.title = result.items[0].snippet.title;\n ui.setTitle.call(this);\n }\n })\n .catch(() => {});\n }\n\n // Setup API\n if (utils.is.object(window.YT)) {\n youtube.ready.call(this, videoId);\n } else {\n // Load the API\n utils.loadScript(this.config.urls.youtube.api);\n\n // Setup callback for the API\n window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];\n\n // Add to queue\n window.onYouTubeReadyCallbacks.push(() => {\n youtube.ready.call(this, videoId);\n });\n\n // Set callback to process queue\n window.onYouTubeIframeAPIReady = () => {\n window.onYouTubeReadyCallbacks.forEach(callback => {\n callback();\n });\n };\n }\n },\n\n // Set aspect ratio\n setAspectRatio() {\n const ratio = this.config.ratio.split(':');\n this.elements.wrapper.style.paddingBottom = `${100 / ratio[0] * ratio[1]}%`;\n },\n\n // API ready\n ready(videoId) {\n const player = this;\n\n // Setup instance\n // https://developers.google.com/youtube/iframe_api_reference\n player.embed = new window.YT.Player(player.media.id, {\n videoId,\n playerVars: {\n autoplay: player.config.autoplay ? 1 : 0, // Autoplay\n controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported\n rel: 0, // No related vids\n showinfo: 0, // Hide info\n iv_load_policy: 3, // Hide annotations\n modestbranding: 1, // Hide logos as much as possible (they still show one in the corner when paused)\n disablekb: 1, // Disable keyboard as we handle it\n playsinline: 1, // Allow iOS inline playback\n\n // Tracking for stats\n origin: window && window.location.hostname,\n widget_referrer: window && window.location.href,\n\n // Captions are flaky on YouTube\n cc_load_policy: this.captions.active ? 1 : 0,\n cc_lang_pref: this.config.captions.language,\n },\n events: {\n onError(event) {\n // If we've already fired an error, don't do it again\n // YouTube fires onError twice\n if (utils.is.object(player.media.error)) {\n return;\n }\n\n const detail = {\n code: event.data,\n };\n\n // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError\n switch (event.data) {\n case 2:\n detail.message =\n 'The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.';\n break;\n\n case 5:\n detail.message =\n 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.';\n break;\n\n case 100:\n detail.message =\n 'The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.';\n break;\n\n case 101:\n case 150:\n detail.message =\n 'The owner of the requested video does not allow it to be played in embedded players.';\n break;\n\n default:\n detail.message = 'An unknown error occured';\n break;\n }\n\n player.media.error = detail;\n\n utils.dispatchEvent.call(player, player.media, 'error');\n },\n onPlaybackQualityChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Get current quality\n player.media.quality = instance.getPlaybackQuality();\n\n utils.dispatchEvent.call(player, player.media, 'qualitychange');\n },\n onPlaybackRateChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Get current speed\n player.media.playbackRate = instance.getPlaybackRate();\n\n utils.dispatchEvent.call(player, player.media, 'ratechange');\n },\n onReady(event) {\n // Get the instance\n const instance = event.target;\n\n // Create a faux HTML5 API using the YouTube API\n player.media.play = () => {\n instance.playVideo();\n player.media.paused = false;\n };\n player.media.pause = () => {\n instance.pauseVideo();\n player.media.paused = true;\n };\n player.media.stop = () => {\n instance.stopVideo();\n player.media.paused = true;\n };\n player.media.duration = instance.getDuration();\n player.media.paused = true;\n\n // Seeking\n player.media.currentTime = 0;\n Object.defineProperty(player.media, 'currentTime', {\n get() {\n return Number(instance.getCurrentTime());\n },\n set(time) {\n // Set seeking flag\n player.media.seeking = true;\n\n // Trigger seeking\n utils.dispatchEvent.call(player, player.media, 'seeking');\n\n // Seek after events sent\n instance.seekTo(time);\n },\n });\n\n // Playback speed\n Object.defineProperty(player.media, 'playbackRate', {\n get() {\n return instance.getPlaybackRate();\n },\n set(input) {\n instance.setPlaybackRate(input);\n },\n });\n\n // Quality\n Object.defineProperty(player.media, 'quality', {\n get() {\n return instance.getPlaybackQuality();\n },\n set(input) {\n // Trigger request event\n utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {\n quality: input,\n });\n\n instance.setPlaybackQuality(input);\n },\n });\n\n // Volume\n let { volume } = player.config;\n Object.defineProperty(player.media, 'volume', {\n get() {\n return volume;\n },\n set(input) {\n volume = input;\n instance.setVolume(volume * 100);\n utils.dispatchEvent.call(player, player.media, 'volumechange');\n },\n });\n\n // Muted\n let { muted } = player.config;\n Object.defineProperty(player.media, 'muted', {\n get() {\n return muted;\n },\n set(input) {\n const toggle = utils.is.boolean(input) ? input : muted;\n muted = toggle;\n instance[toggle ? 'mute' : 'unMute']();\n utils.dispatchEvent.call(player, player.media, 'volumechange');\n },\n });\n\n // Source\n Object.defineProperty(player.media, 'currentSrc', {\n get() {\n return instance.getVideoUrl();\n },\n });\n\n // Get available speeds\n if (player.config.controls.includes('settings') && player.config.settings.includes('speed')) {\n controls.setSpeedMenu.call(player, instance.getAvailablePlaybackRates());\n }\n\n // Set title\n if (utils.is.function(instance.getVideoData)) {\n player.config.title = instance.getVideoData().title;\n }\n\n // Set the tabindex to avoid focus entering iframe\n if (player.supported.ui) {\n player.media.setAttribute('tabindex', -1);\n }\n\n utils.dispatchEvent.call(player, player.media, 'timeupdate');\n utils.dispatchEvent.call(player, player.media, 'durationchange');\n\n // Reset timer\n window.clearInterval(player.timers.buffering);\n\n // Setup buffering\n player.timers.buffering = window.setInterval(() => {\n // Get loaded % from YouTube\n player.media.buffered = instance.getVideoLoadedFraction();\n\n // Trigger progress only when we actually buffer something\n if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {\n utils.dispatchEvent.call(player, player.media, 'progress');\n }\n\n // Set last buffer point\n player.media.lastBuffered = player.media.buffered;\n\n // Bail if we're at 100%\n if (player.media.buffered === 1) {\n window.clearInterval(player.timers.buffering);\n\n // Trigger event\n utils.dispatchEvent.call(player, player.media, 'canplaythrough');\n }\n }, 200);\n\n // Rebuild UI\n window.setTimeout(() => ui.build.call(player), 50);\n },\n onStateChange(event) {\n // Get the instance\n const instance = event.target;\n\n // Reset timer\n window.clearInterval(player.timers.playing);\n\n // Handle events\n // -1 Unstarted\n // 0 Ended\n // 1 Playing\n // 2 Paused\n // 3 Buffering\n // 5 Video cued\n switch (event.data) {\n case 0:\n // YouTube doesn't support loop for a single video, so mimick it.\n if (player.media.loop) {\n // YouTube needs a call to `stopVideo` before playing again\n instance.stopVideo();\n instance.playVideo();\n } else {\n utils.dispatchEvent.call(player, player.media, 'ended');\n player.media.paused = true;\n }\n\n break;\n\n case 1:\n player.media.paused = false;\n\n // If we were seeking, fire seeked event\n if (player.media.seeking) {\n utils.dispatchEvent.call(player, player.media, 'seeked');\n }\n\n player.media.seeking = false;\n\n utils.dispatchEvent.call(player, player.media, 'play');\n utils.dispatchEvent.call(player, player.media, 'playing');\n\n // Poll to get playback progress\n player.timers.playing = window.setInterval(() => {\n utils.dispatchEvent.call(player, player.media, 'timeupdate');\n }, 50);\n\n // Check duration again due to YouTube bug\n // https://github.com/sampotts/plyr/issues/374\n // https://code.google.com/p/gdata-issues/issues/detail?id=8690\n if (player.media.duration !== instance.getDuration()) {\n player.media.duration = instance.getDuration();\n utils.dispatchEvent.call(player, player.media, 'durationchange');\n }\n\n // Get quality\n controls.setQualityMenu.call(player, instance.getAvailableQualityLevels());\n\n break;\n\n case 2:\n player.media.paused = true;\n\n utils.dispatchEvent.call(player, player.media, 'pause');\n\n break;\n\n default:\n break;\n }\n\n utils.dispatchEvent.call(player, player.elements.container, 'statechange', false, {\n code: event.data,\n });\n },\n },\n });\n },\n};\n\nexport default youtube;\n","// ==========================================================================\n// Vimeo plugin\n// ==========================================================================\n\nimport utils from './../utils';\nimport captions from './../captions';\nimport controls from './../controls';\nimport ui from './../ui';\n\nconst vimeo = {\n setup() {\n // Remove old containers\n const containers = utils.getElements.call(this, `[id^=\"${this.type}-\"]`);\n Array.from(containers).forEach(utils.removeElement);\n\n // Add embed class for responsive\n utils.toggleClass(this.elements.wrapper, this.config.classNames.embed, true);\n\n // Set intial ratio\n vimeo.setAspectRatio.call(this);\n\n // Set ID\n this.media.setAttribute('id', utils.generateId(this.type));\n\n // Load the API if not already\n if (!utils.is.object(window.Vimeo)) {\n utils.loadScript(this.config.urls.vimeo.api, () => {\n vimeo.ready.call(this);\n });\n } else {\n vimeo.ready.call(this);\n }\n },\n\n // Set aspect ratio\n // For Vimeo we have an extra 300% height <div> to hide the standard controls and UI\n setAspectRatio(input) {\n const ratio = utils.is.string(input) ? input.split(':') : this.config.ratio.split(':');\n const padding = 100 / ratio[0] * ratio[1];\n const height = 200;\n const offset = (height - padding) / (height / 50);\n this.elements.wrapper.style.paddingBottom = `${padding}%`;\n this.media.style.transform = `translateY(-${offset}%)`;\n },\n\n // API Ready\n ready() {\n const player = this;\n\n // Get Vimeo params for the iframe\n const options = {\n loop: player.config.loop.active,\n autoplay: player.autoplay,\n byline: false,\n portrait: false,\n title: false,\n speed: true,\n transparent: 0,\n gesture: 'media',\n };\n const params = utils.buildUrlParameters(options);\n const id = utils.parseVimeoId(player.embedId);\n\n // Build an iframe\n const iframe = utils.createElement('iframe');\n const src = `https://player.vimeo.com/video/${id}?${params}`;\n iframe.setAttribute('src', src);\n iframe.setAttribute('allowfullscreen', '');\n player.media.appendChild(iframe);\n\n // Setup instance\n // https://github.com/vimeo/player.js\n player.embed = new window.Vimeo.Player(iframe);\n\n player.media.paused = true;\n player.media.currentTime = 0;\n\n // Create a faux HTML5 API using the Vimeo API\n player.media.play = () => {\n player.embed.play().then(() => {\n player.media.paused = false;\n });\n };\n player.media.pause = () => {\n player.embed.pause().then(() => {\n player.media.paused = true;\n });\n };\n player.media.stop = () => {\n player.embed.stop().then(() => {\n player.media.paused = true;\n player.currentTime = 0;\n });\n };\n\n // Seeking\n let { currentTime } = player.media;\n Object.defineProperty(player.media, 'currentTime', {\n get() {\n return currentTime;\n },\n set(time) {\n // Get current paused state\n // Vimeo will automatically play on seek\n const { paused } = player.media;\n\n // Set seeking flag\n player.media.seeking = true;\n\n // Trigger seeking\n utils.dispatchEvent.call(player, player.media, 'seeking');\n\n // Seek after events\n player.embed.setCurrentTime(time);\n\n // Restore pause state\n if (paused) {\n player.pause();\n }\n },\n });\n\n // Playback speed\n let speed = player.config.speed.selected;\n Object.defineProperty(player.media, 'playbackRate', {\n get() {\n return speed;\n },\n set(input) {\n player.embed.setPlaybackRate(input).then(() => {\n speed = input;\n utils.dispatchEvent.call(player, player.media, 'ratechange');\n });\n },\n });\n\n // Volume\n let { volume } = player.config;\n Object.defineProperty(player.media, 'volume', {\n get() {\n return volume;\n },\n set(input) {\n player.embed.setVolume(input).then(() => {\n volume = input;\n utils.dispatchEvent.call(player, player.media, 'volumechange');\n });\n },\n });\n\n // Muted\n let { muted } = player.config;\n Object.defineProperty(player.media, 'muted', {\n get() {\n return muted;\n },\n set(input) {\n const toggle = utils.is.boolean(input) ? input : false;\n\n player.embed.setVolume(toggle ? 0 : player.config.volume).then(() => {\n muted = toggle;\n utils.dispatchEvent.call(player, player.media, 'volumechange');\n });\n },\n });\n\n // Loop\n let { loop } = player.config;\n Object.defineProperty(player.media, 'loop', {\n get() {\n return loop;\n },\n set(input) {\n const toggle = utils.is.boolean(input) ? input : player.config.loop.active;\n\n player.embed.setLoop(toggle).then(() => {\n loop = toggle;\n });\n },\n });\n\n // Source\n let currentSrc;\n player.embed.getVideoUrl().then(value => {\n currentSrc = value;\n });\n Object.defineProperty(player.media, 'currentSrc', {\n get() {\n return currentSrc;\n },\n });\n\n // Set aspect ratio based on video size\n Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then(dimensions => {\n const ratio = utils.getAspectRatio(dimensions[0], dimensions[1]);\n vimeo.setAspectRatio.call(this, ratio);\n });\n\n // Get available speeds\n if (player.config.controls.includes('settings') && player.config.settings.includes('speed')) {\n controls.setSpeedMenu.call(player);\n }\n\n // Get title\n player.embed.getVideoTitle().then(title => {\n player.config.title = title;\n ui.setTitle.call(this);\n });\n\n // Get current time\n player.embed.getCurrentTime().then(value => {\n currentTime = value;\n utils.dispatchEvent.call(player, player.media, 'timeupdate');\n });\n\n // Get duration\n player.embed.getDuration().then(value => {\n player.media.duration = value;\n utils.dispatchEvent.call(player, player.media, 'durationchange');\n });\n\n // Get captions\n player.embed.getTextTracks().then(tracks => {\n player.captions.tracks = tracks;\n captions.setup.call(player);\n });\n\n player.embed.on('cuechange', data => {\n let cue = null;\n\n if (data.cues.length) {\n cue = utils.stripHTML(data.cues[0].text);\n }\n\n captions.set.call(player, cue);\n });\n\n player.embed.on('loaded', () => {\n if (utils.is.htmlElement(player.embed.element) && player.supported.ui) {\n const frame = player.embed.element;\n\n // Fix keyboard focus issues\n // https://github.com/sampotts/plyr/issues/317\n frame.setAttribute('tabindex', -1);\n }\n });\n\n player.embed.on('play', () => {\n player.media.paused = false;\n utils.dispatchEvent.call(player, player.media, 'play');\n utils.dispatchEvent.call(player, player.media, 'playing');\n });\n\n player.embed.on('pause', () => {\n player.media.paused = true;\n utils.dispatchEvent.call(player, player.media, 'pause');\n });\n\n player.embed.on('timeupdate', data => {\n player.media.seeking = false;\n currentTime = data.seconds;\n utils.dispatchEvent.call(player, player.media, 'timeupdate');\n });\n\n player.embed.on('progress', data => {\n player.media.buffered = data.percent;\n utils.dispatchEvent.call(player, player.media, 'progress');\n\n if (parseInt(data.percent, 10) === 1) {\n // Trigger event\n utils.dispatchEvent.call(player, player.media, 'canplaythrough');\n }\n });\n\n player.embed.on('seeked', () => {\n player.media.seeking = false;\n utils.dispatchEvent.call(player, player.media, 'seeked');\n utils.dispatchEvent.call(player, player.media, 'play');\n });\n\n player.embed.on('ended', () => {\n player.media.paused = true;\n utils.dispatchEvent.call(player, player.media, 'ended');\n });\n\n player.embed.on('error', detail => {\n player.media.error = detail;\n utils.dispatchEvent.call(player, player.media, 'error');\n });\n\n // Rebuild UI\n window.setTimeout(() => ui.build.call(player), 0);\n },\n};\n\nexport default vimeo;\n","// ==========================================================================\n// Plyr Media\n// ==========================================================================\n\nimport support from './support';\nimport utils from './utils';\nimport youtube from './plugins/youtube';\nimport vimeo from './plugins/vimeo';\nimport ui from './ui';\n\n// Sniff out the browser\nconst browser = utils.getBrowser();\n\nconst media = {\n // Setup media\n setup() {\n // If there's no media, bail\n if (!this.media) {\n this.console.warn('No media element found!');\n return;\n }\n\n // Add type class\n utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', this.type), true);\n\n // Add video class for embeds\n // This will require changes if audio embeds are added\n if (this.isEmbed) {\n utils.toggleClass(this.elements.container, this.config.classNames.type.replace('{0}', 'video'), true);\n }\n\n if (this.supported.ui) {\n // Check for picture-in-picture support\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.pip.supported,\n support.pip && this.type === 'video'\n );\n\n // Check for airplay support\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.airplay.supported,\n support.airplay && this.isHTML5\n );\n\n // If there's no autoplay attribute, assume the video is stopped and add state class\n utils.toggleClass(this.elements.container, this.config.classNames.stopped, this.config.autoplay);\n\n // Add iOS class\n utils.toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos);\n\n // Add touch class\n utils.toggleClass(this.elements.container, this.config.classNames.isTouch, support.touch);\n }\n\n // Inject the player wrapper\n if (['video', 'youtube', 'vimeo'].includes(this.type)) {\n // Create the wrapper div\n this.elements.wrapper = utils.createElement('div', {\n class: this.config.classNames.video,\n });\n\n // Wrap the video in a container\n utils.wrap(this.media, this.elements.wrapper);\n }\n\n if (this.isEmbed) {\n switch (this.type) {\n case 'youtube':\n youtube.setup.call(this);\n break;\n\n case 'vimeo':\n vimeo.setup.call(this);\n break;\n\n default:\n break;\n }\n } else {\n ui.setTitle.call(this);\n }\n },\n\n // Cancel current network requests\n // See https://github.com/sampotts/plyr/issues/174\n cancelRequests() {\n if (!this.isHTML5) {\n return;\n }\n\n // Remove child sources\n Array.from(this.media.querySelectorAll('source')).forEach(utils.removeElement);\n\n // Set blank video src attribute\n // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error\n // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection\n this.media.setAttribute('src', this.config.blankVideo);\n\n // Load the new empty source\n // This will cancel existing requests\n // See https://github.com/sampotts/plyr/issues/174\n this.media.load();\n\n // Debugging\n this.console.log('Cancelled network requests');\n },\n};\n\nexport default media;\n","// ==========================================================================\n// Plyr source update\n// ==========================================================================\n\nimport types from './types';\nimport utils from './utils';\nimport media from './media';\nimport ui from './ui';\nimport support from './support';\n\nconst source = {\n // Add elements to HTML5 media (source, tracks, etc)\n insertElements(type, attributes) {\n if (utils.is.string(attributes)) {\n utils.insertElement(type, this.media, {\n src: attributes,\n });\n } else if (utils.is.array(attributes)) {\n attributes.forEach(attribute => {\n utils.insertElement(type, this.media, attribute);\n });\n }\n },\n\n // Update source\n // Sources are not checked for support so be careful\n change(input) {\n if (!utils.is.object(input) || !('sources' in input) || !input.sources.length) {\n this.console.warn('Invalid source format');\n return;\n }\n\n // Cancel current network requests\n media.cancelRequests.call(this);\n\n // Destroy instance and re-setup\n this.destroy.call(\n this,\n () => {\n // TODO: Reset menus here\n\n // Remove elements\n utils.removeElement(this.media);\n this.media = null;\n\n // Reset class name\n if (utils.is.htmlElement(this.elements.container)) {\n this.elements.container.removeAttribute('class');\n }\n\n // Set the type\n if ('type' in input) {\n this.type = input.type;\n\n // Get child type for video (it might be an embed)\n if (this.type === 'video') {\n const firstSource = input.sources[0];\n\n if ('type' in firstSource && types.embed.includes(firstSource.type)) {\n this.type = firstSource.type;\n }\n }\n }\n\n // Check for support\n this.supported = support.check(this.type, this.config.inline);\n\n // Create new markup\n switch (this.type) {\n case 'video':\n this.media = utils.createElement('video');\n break;\n\n case 'audio':\n this.media = utils.createElement('audio');\n break;\n\n case 'youtube':\n case 'vimeo':\n this.media = utils.createElement('div');\n this.embedId = input.sources[0].src;\n break;\n\n default:\n break;\n }\n\n // Inject the new element\n this.elements.container.appendChild(this.media);\n\n // Autoplay the new source?\n if (utils.is.boolean(input.autoplay)) {\n this.config.autoplay = input.autoplay;\n }\n\n // Set attributes for audio and video\n if (this.isHTML5) {\n if (this.config.crossorigin) {\n this.media.setAttribute('crossorigin', '');\n }\n if (this.config.autoplay) {\n this.media.setAttribute('autoplay', '');\n }\n if ('poster' in input) {\n this.media.setAttribute('poster', input.poster);\n }\n if (this.config.loop.active) {\n this.media.setAttribute('loop', '');\n }\n if (this.config.muted) {\n this.media.setAttribute('muted', '');\n }\n if (this.config.inline) {\n this.media.setAttribute('playsinline', '');\n }\n }\n\n // Restore class hooks\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.captions.active,\n this.supported.ui && this.captions.enabled\n );\n\n ui.addStyleHook.call(this);\n\n // Set new sources for html5\n if (this.isHTML5) {\n source.insertElements.call(this, 'source', input.sources);\n }\n\n // Set video title\n this.config.title = input.title;\n\n // Set up from scratch\n media.setup.call(this);\n\n // HTML5 stuff\n if (this.isHTML5) {\n // Setup captions\n if ('tracks' in input) {\n source.insertElements.call(this, 'track', input.tracks);\n }\n\n // Load HTML5 sources\n this.media.load();\n }\n\n // If HTML5 or embed but not fully supported, setupInterface and call ready now\n if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) {\n // Setup interface\n ui.build.call(this);\n }\n },\n true\n );\n },\n};\n\nexport default source;\n","// ==========================================================================\n// Plyr\n// plyr.js v3.0.0\n// https://github.com/sampotts/plyr\n// License: The MIT License (MIT)\n// ==========================================================================\n\nimport defaults from './defaults';\nimport types from './types';\nimport support from './support';\nimport utils from './utils';\n\nimport captions from './captions';\nimport controls from './controls';\nimport fullscreen from './fullscreen';\nimport listeners from './listeners';\nimport media from './media';\nimport storage from './storage';\nimport source from './source';\nimport ui from './ui';\n\n// Globals\nlet scrollPosition = {\n x: 0,\n y: 0,\n};\n\n// Plyr instance\nclass Plyr {\n constructor(target, options) {\n this.timers = {};\n this.ready = false;\n\n // Set the media element\n this.media = target;\n\n // String selector passed\n if (utils.is.string(this.media)) {\n this.media = document.querySelectorAll(this.media);\n }\n\n // jQuery, NodeList or Array passed, use first element\n if (\n (window.jQuery && this.media instanceof jQuery) ||\n utils.is.nodeList(this.media) ||\n utils.is.array(this.media)\n ) {\n // eslint-disable-next-line\n this.media = this.media[0];\n }\n\n // Set config\n this.config = utils.extend(\n {},\n defaults,\n options,\n (() => {\n try {\n return JSON.parse(this.media.getAttribute('data-plyr'));\n } catch (e) {\n return null;\n }\n })()\n );\n\n // Elements cache\n this.elements = {\n container: null,\n buttons: {},\n display: {},\n progress: {},\n inputs: {},\n settings: {\n menu: null,\n panes: {},\n tabs: {},\n },\n captions: null,\n };\n\n // Captions\n this.captions = {\n enabled: null,\n tracks: null,\n currentTrack: null,\n };\n\n // Fullscreen\n this.fullscreen = {\n active: false,\n };\n\n // Options\n this.options = {\n speed: [],\n quality: [],\n };\n\n // Debugging\n this.console = {\n log() {},\n warn() {},\n error() {},\n };\n if (this.config.debug && 'console' in window) {\n this.console = {\n log: console.log, // eslint-disable-line\n warn: console.warn, // eslint-disable-line\n error: console.error, // eslint-disable-line\n };\n this.console.log('Debugging enabled');\n }\n\n // Log config options and support\n this.console.log('Config', this.config);\n this.console.log('Support', support);\n\n // We need an element to setup\n if (this.media === null || utils.is.undefined(this.media) || !utils.is.htmlElement(this.media)) {\n this.console.error('Setup failed: no suitable element passed');\n return;\n }\n\n // Bail if the element is initialized\n if (this.media.plyr) {\n this.console.warn('Target already setup');\n return;\n }\n\n // Bail if not enabled\n if (!this.config.enabled) {\n this.console.error('Setup failed: disabled by config');\n return;\n }\n\n // Bail if disabled or no basic support\n // You may want to disable certain UAs etc\n if (!support.check().api) {\n this.console.error('Setup failed: no support');\n return;\n }\n\n // Cache original element state for .destroy()\n this.elements.original = this.media.cloneNode(true);\n\n // Set media type based on tag or data attribute\n // Supported: video, audio, vimeo, youtube\n const type = this.media.tagName.toLowerCase();\n\n // Different setup based on type\n switch (type) {\n // TODO: Handle passing an iframe for true progressive enhancement\n // case 'iframe':\n case 'div':\n this.type = this.media.getAttribute('data-type');\n this.embedId = this.media.getAttribute('data-video-id');\n\n if (utils.is.empty(this.type)) {\n this.console.error('Setup failed: embed type missing');\n return;\n }\n\n if (utils.is.empty(this.embedId)) {\n this.console.error('Setup failed: video id missing');\n return;\n }\n\n // Clean up\n this.media.removeAttribute('data-type');\n this.media.removeAttribute('data-video-id');\n break;\n\n case 'video':\n case 'audio':\n this.type = type;\n\n if (this.media.hasAttribute('crossorigin')) {\n this.config.crossorigin = true;\n }\n if (this.media.hasAttribute('autoplay')) {\n this.config.autoplay = true;\n }\n if (this.media.hasAttribute('playsinline')) {\n this.config.inline = true;\n }\n if (this.media.hasAttribute('muted')) {\n this.config.muted = true;\n }\n if (this.media.hasAttribute('loop')) {\n this.config.loop.active = true;\n }\n\n break;\n\n default:\n this.console.error('Setup failed: unsupported type');\n return;\n }\n\n // Setup local storage for user settings\n storage.setup.call(this);\n\n // Check for support again but with type\n this.supported = support.check(this.type, this.config.inline);\n\n // If no support for even API, bail\n if (!this.supported.api) {\n this.console.error('Setup failed: no support');\n return;\n }\n\n // Store reference\n this.media.plyr = this;\n\n // Wrap media\n this.elements.container = utils.createElement('div');\n utils.wrap(this.media, this.elements.container);\n\n // Allow focus to be captured\n this.elements.container.setAttribute('tabindex', 0);\n\n // Global listeners\n listeners.global.call(this);\n\n // Add style hook\n ui.addStyleHook.call(this);\n\n // Setup media\n media.setup.call(this);\n\n // Listen for events if debugging\n if (this.config.debug) {\n utils.on(this.elements.container, this.config.events.join(' '), event => {\n this.console.log(`event: ${event.type}`);\n });\n }\n\n // Setup interface\n // If embed but not fully supported, build interface now to avoid flash of controls\n if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) {\n ui.build.call(this);\n }\n }\n\n // ---------------------------------------\n // API\n // ---------------------------------------\n\n /**\n * If the player is HTML5\n */\n get isHTML5() {\n return types.html5.includes(this.type);\n }\n\n /**\n * If the player is an embed - e.g. YouTube or Vimeo\n */\n get isEmbed() {\n return types.embed.includes(this.type);\n }\n\n /**\n * Play the media\n */\n play() {\n if ('play' in this.media) {\n this.media.play();\n }\n return this;\n }\n\n /**\n * Pause the media\n */\n pause() {\n if ('pause' in this.media) {\n this.media.pause();\n }\n return this;\n }\n\n get paused() {\n return this.media.paused;\n }\n\n /**\n * Toggle playback based on current status\n * @param {boolean} toggle\n */\n togglePlay(toggle) {\n // True toggle if nothing passed\n if ((!utils.is.boolean(toggle) && this.media.paused) || toggle) {\n return this.play();\n }\n\n return this.pause();\n }\n\n /**\n * Stop playback\n */\n stop() {\n return this.restart().pause();\n }\n\n /**\n * Restart playback\n */\n restart() {\n this.currentTime = 0;\n return this;\n }\n\n /**\n * Rewind\n * @param {number} seekTime - how far to rewind in seconds. Defaults to the config.seekTime\n */\n rewind(seekTime) {\n this.currentTime = this.currentTime - (utils.is.number(seekTime) ? seekTime : this.config.seekTime);\n return this;\n }\n\n /**\n * Fast forward\n * @param {number} seekTime - how far to fast forward in seconds. Defaults to the config.seekTime\n */\n forward(seekTime) {\n this.currentTime = this.currentTime + (utils.is.number(seekTime) ? seekTime : this.config.seekTime);\n return this;\n }\n\n /**\n * Seek to a time\n * @param {number} input - where to seek to in seconds. Defaults to 0 (the start)\n */\n set currentTime(input) {\n let targetTime = 0;\n\n if (utils.is.number(input)) {\n targetTime = input;\n }\n\n // Normalise targetTime\n if (targetTime < 0) {\n targetTime = 0;\n } else if (targetTime > this.duration) {\n targetTime = this.duration;\n }\n\n // Set\n this.media.currentTime = targetTime.toFixed(4);\n\n // Logging\n this.console.log(`Seeking to ${this.currentTime} seconds`);\n }\n\n get currentTime() {\n return Number(this.media.currentTime);\n }\n\n get seeking() {\n return this.media.seeking;\n }\n\n /**\n * Get the duration of the current media\n */\n get duration() {\n // Faux duration set via config\n const fauxDuration = parseInt(this.config.duration, 10);\n\n // True duration\n const realDuration = Number(this.media.duration);\n\n // If custom duration is funky, use regular duration\n return !Number.isNaN(fauxDuration) ? fauxDuration : realDuration;\n }\n\n /**\n * Set the player volume\n * @param {number} value - must be between 0 and 1. Defaults to the value from local storage and config.volume if not set in storage\n */\n set volume(value) {\n let volume = value;\n const max = 1;\n const min = 0;\n\n if (utils.is.string(volume)) {\n volume = Number(volume);\n }\n\n // Load volume from storage if no value specified\n if (!utils.is.number(volume)) {\n ({ volume } = storage.get.call(this));\n }\n\n // Use config if all else fails\n if (!utils.is.number(volume)) {\n ({ volume } = this.config);\n }\n\n // Maximum is volumeMax\n if (volume > max) {\n volume = max;\n }\n // Minimum is volumeMin\n if (volume < min) {\n volume = min;\n }\n\n // Update config\n this.config.volume = volume;\n\n // Set the player volume\n this.media.volume = volume;\n\n // If muted, and we're increasing volume, reset muted state\n if (this.muted && volume > 0) {\n this.muted = false;\n }\n }\n\n /**\n * Get the current player volume\n */\n get volume() {\n return this.media.volume;\n }\n\n // Increase volume\n increaseVolume(step) {\n const volume = this.media.muted ? 0 : this.volume;\n this.volume = volume + utils.is.number(step) ? step : 1;\n return this;\n }\n\n // Decrease volume\n decreaseVolume(step) {\n const volume = this.media.muted ? 0 : this.volume;\n this.volume = volume - utils.is.number(step) ? step : 1;\n return this;\n }\n\n // Toggle mute\n set muted(mute) {\n let toggle = mute;\n\n // Load muted state from storage\n if (!utils.is.boolean(toggle)) {\n toggle = storage.get.call(this).muted;\n }\n\n // Use config if all else fails\n if (!utils.is.boolean(toggle)) {\n toggle = this.config.muted;\n }\n\n // Update config\n this.config.muted = toggle;\n\n // Set mute on the player\n this.media.muted = toggle;\n }\n\n get muted() {\n return this.media.muted;\n }\n\n // Playback speed\n set speed(input) {\n let speed = null;\n\n if (utils.is.number(input)) {\n speed = input;\n } else if (utils.is.number(storage.get.call(this).speed)) {\n ({ speed } = storage.get.call(this));\n } else {\n speed = this.config.speed.selected;\n }\n\n // Set min/max\n if (speed < 0.1) {\n speed = 0.1;\n }\n if (speed > 2.0) {\n speed = 2.0;\n }\n\n if (!this.config.speed.options.includes(speed)) {\n this.console.warn(`Unsupported speed (${speed})`);\n return;\n }\n\n // Update config\n this.config.speed.selected = speed;\n\n // Set media speed\n this.media.playbackRate = speed;\n }\n\n get speed() {\n return this.media.playbackRate;\n }\n\n // Set playback quality\n set quality(input) {\n let quality = null;\n\n if (utils.is.string(input)) {\n quality = input;\n } else if (utils.is.number(storage.get.call(this).speed)) {\n ({ quality } = storage.get.call(this));\n } else {\n quality = this.config.quality.selected;\n }\n\n if (!this.options.quality.includes(quality)) {\n this.console.warn(`Unsupported quality option (${quality})`);\n return;\n }\n\n // Update config\n this.config.quality.selected = quality;\n\n // Set quality\n this.media.quality = quality;\n }\n\n get quality() {\n return this.media.quality;\n }\n\n // Toggle loop\n // TODO: Finish fancy new logic. Set the indicator on load as user may pass loop as config\n set loop(input) {\n const toggle = utils.is.boolean(input) ? input : this.config.loop.active;\n this.config.loop.active = toggle;\n this.media.loop = toggle;\n\n // Set default to be a true toggle\n /* const type = ['start', 'end', 'all', 'none', 'toggle'].includes(input) ? input : 'toggle';\n\n switch (type) {\n case 'start':\n if (this.config.loop.end && this.config.loop.end <= this.currentTime) {\n this.config.loop.end = null;\n }\n this.config.loop.start = this.currentTime;\n // this.config.loop.indicator.start = this.elements.display.played.value;\n break;\n\n case 'end':\n if (this.config.loop.start >= this.currentTime) {\n return this;\n }\n this.config.loop.end = this.currentTime;\n // this.config.loop.indicator.end = this.elements.display.played.value;\n break;\n\n case 'all':\n this.config.loop.start = 0;\n this.config.loop.end = this.duration - 2;\n this.config.loop.indicator.start = 0;\n this.config.loop.indicator.end = 100;\n break;\n\n case 'toggle':\n if (this.config.loop.active) {\n this.config.loop.start = 0;\n this.config.loop.end = null;\n } else {\n this.config.loop.start = 0;\n this.config.loop.end = this.duration - 2;\n }\n break;\n\n default:\n this.config.loop.start = 0;\n this.config.loop.end = null;\n break;\n } */\n }\n\n get loop() {\n return this.media.loop;\n }\n\n // Media source\n set source(input) {\n source.change.call(this, input);\n }\n\n get source() {\n return this.media.currentSrc;\n }\n\n // Poster image\n set poster(input) {\n if (this.type !== 'video') {\n this.console.warn('Poster can only be set on HTML5 video');\n return;\n }\n\n if (utils.is.string(input)) {\n this.media.setAttribute('poster', input);\n }\n }\n\n get poster() {\n if (this.type !== 'video') {\n return null;\n }\n\n return this.media.getAttribute('poster');\n }\n\n // Autoplay\n get autoplay() {\n return this.config.autoplay;\n }\n\n set autoplay(input) {\n const toggle = utils.is.boolean(input) ? input : this.config.autoplay;\n this.config.autoplay = toggle;\n }\n\n // Toggle captions\n toggleCaptions(input) {\n // If there's no full support, or there's no caption toggle\n if (!this.supported.ui || !utils.is.htmlElement(this.elements.buttons.captions)) {\n return this;\n }\n\n // If the method is called without parameter, toggle based on current value\n const show = utils.is.boolean(input)\n ? input\n : this.elements.container.className.indexOf(this.config.classNames.captions.active) === -1;\n\n // Nothing to change...\n if (this.captions.enabled === show) {\n return this;\n }\n\n // Set global\n this.captions.enabled = show;\n\n // Toggle state\n utils.toggleState(this.elements.buttons.captions, this.captions.enabled);\n\n // Add class hook\n utils.toggleClass(this.elements.container, this.config.classNames.captions.active, this.captions.enabled);\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, this.captions.enabled ? 'captionsenabled' : 'captionsdisabled');\n\n // Allow chaining\n return this;\n }\n\n // Caption language\n set language(input) {\n // Nothing specified\n if (!utils.is.string(input)) {\n return;\n }\n\n // Normalize\n const language = input.toLowerCase();\n\n // If nothing to change, bail\n if (this.language === language) {\n return;\n }\n\n // Reset UI\n this.toggleCaptions(true);\n\n // Update config\n this.captions.language = language;\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, 'languagechange');\n\n // Clear caption\n captions.set.call(this);\n\n // Re-run setup\n captions.setup.call(this);\n }\n\n get language() {\n return this.captions.language;\n }\n\n // Toggle fullscreen\n // Requires user input event\n toggleFullscreen(event) {\n // Check for native support\n if (fullscreen.enabled) {\n // If it's a fullscreen change event, update the UI\n if (utils.is.event(event) && event.type === fullscreen.eventType) {\n this.fullscreen.active = fullscreen.isFullScreen(this.elements.container);\n } else {\n // Else it's a user request to enter or exit\n if (!this.fullscreen.active) {\n // Request full screen\n fullscreen.requestFullScreen(this.elements.container);\n } else {\n // Bail from fullscreen\n fullscreen.cancelFullScreen();\n }\n\n // Check if we're actually full screen (it could fail)\n this.fullscreen.active = fullscreen.isFullScreen(this.elements.container);\n\n return this;\n }\n } else {\n // Otherwise, it's a simple toggle\n this.fullscreen.active = !this.fullscreen.active;\n\n // Add class hook\n utils.toggleClass(\n this.elements.container,\n this.config.classNames.fullscreen.fallback,\n this.fullscreen.active\n );\n\n // Make sure we don't lose scroll position\n if (this.fullscreen.active) {\n scrollPosition = {\n x: window.pageXOffset || 0,\n y: window.pageYOffset || 0,\n };\n } else {\n window.scrollTo(scrollPosition.x, scrollPosition.y);\n }\n\n // Bind/unbind escape key\n document.body.style.overflow = this.fullscreen.active ? 'hidden' : '';\n }\n\n // Set button state\n if (this.elements.buttons && this.elements.buttons.fullscreen) {\n utils.toggleState(this.elements.buttons.fullscreen, this.fullscreen.active);\n }\n\n // Trigger an event\n utils.dispatchEvent.call(this, this.media, this.fullscreen.active ? 'enterfullscreen' : 'exitfullscreen');\n\n return this;\n }\n\n // Toggle picture-in-picture\n // TODO: update player with state, support, enabled\n // TODO: detect outside changes\n set pip(input) {\n const states = {\n pip: 'picture-in-picture',\n inline: 'inline',\n };\n\n // Bail if no support\n if (!support.pip) {\n return;\n }\n\n // Toggle based on current state if not passed\n const toggle = utils.is.boolean(input) ? input : this.pip === states.inline;\n\n // Toggle based on current state\n this.media.webkitSetPresentationMode(toggle ? states.pip : states.inline);\n }\n\n get pip() {\n if (!support.pip) {\n return null;\n }\n\n return this.media.webkitPresentationMode;\n }\n\n // Trigger airplay\n // TODO: update player with state, support, enabled\n airplay() {\n // Bail if no support\n if (!support.airplay) {\n return this;\n }\n\n // Show dialog\n this.media.webkitShowPlaybackTargetPicker();\n\n return this;\n }\n\n // Show the player controls in fullscreen mode\n toggleControls(toggle) {\n // We need controls of course...\n if (!utils.is.htmlElement(this.elements.controls)) {\n return this;\n }\n\n // Don't hide if config says not to, it's audio, or not ready or loading\n if (!this.supported.ui || !this.config.hideControls || this.type === 'audio') {\n return this;\n }\n\n let delay = 0;\n let show = toggle;\n let isEnterFullscreen = false;\n\n // Get toggle state if not set\n if (!utils.is.boolean(toggle)) {\n if (utils.is.event(toggle)) {\n // Is the enter fullscreen event\n isEnterFullscreen = toggle.type === 'enterfullscreen';\n\n // Whether to show controls\n show = ['click', 'mousemove', 'touchmove', 'mouseenter', 'focusin'].includes(toggle.type);\n\n // Delay hiding on move events\n if (['mousemove', 'touchmove'].includes(toggle.type)) {\n delay = 2000;\n }\n\n // Delay a little more for keyboard users\n if (toggle.type === 'focusin') {\n delay = 3000;\n utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, true);\n }\n } else {\n show = utils.hasClass(this.elements.container, this.config.classNames.hideControls);\n }\n }\n\n // Clear timer every movement\n window.clearTimeout(this.timers.hover);\n\n // If the mouse is not over the controls, set a timeout to hide them\n if (show || this.media.paused || this.loading) {\n // Check if controls toggled\n const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, false);\n\n // Trigger event\n if (toggled) {\n utils.dispatchEvent.call(this, this.media, 'controlsshown');\n }\n\n // Always show controls when paused or if touch\n if (this.media.paused || this.loading) {\n return this;\n }\n\n // Delay for hiding on touch\n if (support.touch) {\n delay = 3000;\n }\n }\n\n // If toggle is false or if we're playing (regardless of toggle),\n // then set the timer to hide the controls\n if (!show || !this.media.paused) {\n this.timers.hover = window.setTimeout(() => {\n // If the mouse is over the controls (and not entering fullscreen), bail\n if ((this.elements.controls.pressed || this.elements.controls.hover) && !isEnterFullscreen) {\n return;\n }\n\n // Restore transition behaviour\n if (!utils.hasClass(this.elements.container, this.config.classNames.hideControls)) {\n utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, false);\n }\n\n // Check if controls toggled\n const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, true);\n\n // Trigger event and close menu\n if (toggled) {\n utils.dispatchEvent.call(this, this.media, 'controlshidden');\n\n if (this.config.controls.includes('settings') && !utils.is.empty(this.config.settings)) {\n controls.toggleMenu.call(this, false);\n }\n }\n }, delay);\n }\n\n return this;\n }\n\n // Event listeners\n on(event, callback) {\n utils.on(this.elements.container, event, callback);\n return this;\n }\n\n off(event, callback) {\n utils.off(this.elements.container, event, callback);\n return this;\n }\n\n // Check for support\n supports(type) {\n return support.mime.call(this, type);\n }\n\n // Destroy an instance\n // Event listeners are removed when elements are removed\n // http://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory\n destroy(callback, soft = false) {\n const done = () => {\n // Reset overflow (incase destroyed while in fullscreen)\n document.body.style.overflow = '';\n\n // GC for embed\n this.embed = null;\n this.embedId = null;\n\n // If it's a soft destroy, make minimal changes\n if (soft) {\n if (Object.keys(this.elements).length) {\n // Remove buttons\n if (this.elements.buttons && this.elements.buttons.play) {\n Array.from(this.elements.buttons.play).forEach(button => utils.removeElement(button));\n }\n\n // Remove others\n utils.removeElement(this.elements.captions);\n utils.removeElement(this.elements.controls);\n utils.removeElement(this.elements.wrapper);\n\n // Clear for GC\n this.elements.buttons.play = null;\n this.elements.captions = null;\n this.elements.controls = null;\n this.elements.wrapper = null;\n }\n\n // Callback\n if (utils.is.function(callback)) {\n callback();\n }\n } else {\n // Replace the container with the original element provided\n const parent = this.elements.container.parentNode;\n\n if (utils.is.htmlElement(parent)) {\n parent.replaceChild(this.elements.original, this.elements.container);\n }\n\n // Event\n utils.dispatchEvent.call(this, this.elements.original, 'destroyed', true);\n\n // Callback\n if (utils.is.function(callback)) {\n callback.call(this.elements.original);\n }\n\n // Clear for GC\n this.elements = null;\n }\n };\n\n // Type specific stuff\n switch (this.type) {\n case 'youtube':\n // Clear timers\n window.clearInterval(this.timers.buffering);\n window.clearInterval(this.timers.playing);\n\n // Destroy YouTube API\n this.embed.destroy();\n\n // Clean up\n done();\n\n break;\n\n case 'vimeo':\n // Destroy Vimeo API\n // then clean up (wait, to prevent postmessage errors)\n this.embed.unload().then(done);\n\n // Vimeo does not always return\n window.setTimeout(done, 200);\n\n break;\n\n case 'video':\n case 'audio':\n // Restore native video controls\n ui.toggleNativeControls.call(this, true);\n\n // Clean up\n done();\n\n break;\n\n default:\n break;\n }\n }\n}\n\nexport default Plyr;\n"],"names":["get","store","window","localStorage","getItem","this","config","storage","key","utils","is","empty","JSON","parse","set","object","support","enabled","call","extend","setItem","stringify","defaults","navigator","language","split","types","input","getConstructor","Object","Number","isNaN","String","Boolean","Function","undefined","Array","isArray","NodeList","HTMLElement","Text","Event","instanceOf","TextTrackCue","VTTCue","TextTrack","kind","string","array","nodeList","length","keys","constructor","document","documentMode","documentElement","style","test","userAgent","platform","url","callback","querySelectorAll","element","createElement","src","first","getElementsByTagName","function","addEventListener","event","parentNode","insertBefore","id","updateSprite","data","innerHTML","body","childNodes","hasId","container","setAttribute","cached","content","then","response","ok","text","catch","prefix","Math","floor","random","self","top","e","elements","wrapper","targets","from","reverse","forEach","index","child","cloneNode","parent","sibling","nextSibling","appendChild","type","attributes","setAttributes","textContent","target","htmlElement","removeChild","lastChild","sel","existingAttributes","existing","selector","s","trim","className","replace","parts","value","charAt","class","toggle","contains","classList","prototype","Element","matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","includes","querySelector","controls","getElement","selectors","buttons","getElements","play","pause","restart","rewind","forward","mute","pip","airplay","settings","captions","fullscreen","progress","inputs","seek","volume","display","buffer","duration","currentTime","seekTooltip","classNames","tooltip","error","console","warn","toggleNativeControls","focused","activeElement","focusable","last","on","keyCode","_this","active","getFocusElement","shiftKey","focus","preventDefault","passive","capture","Node","toggleListener","events","options","boolean","passiveListeners","bubbles","detail","CustomEvent","assign","Plyr","dispatchEvent","state","getAttribute","current","max","toFixed","objects","destination","shift","source","property","match","RegExp","$2","number","map","encodeURIComponent","join","fragment","createDocumentFragment","firstChild","innerText","width","height","ratio","getRatio","w","h","find","inline","api","ui","browser","getBrowser","playsInline","isIPhone","video","rangeInput","audio","removeItem","webkitSetPresentationMode","WebKitPlaybackTargetAvailabilityEvent","media","canPlayType","supported","defineProperty","range","transitionEnd","matchMedia","cancelFullScreen","some","pre","msExitFullscreen","msFullscreenEnabled","fullscreenEnabled","webkitFullscreenEnabled","mozFullScreenEnabled","fullscreenElement","mozFullScreenElement","requestFullScreen","nativeSupport","fallback","inFrame","log","toggleClass","toggleState","trapFocus","setup","parseFloat","listeners","getKeyCode","which","handleKey","code","pressed","held","editable","stopPropagation","togglePlay","increaseVolume","decreaseVolume","muted","toggleFullscreen","toggleCaptions","loop","keyboard","global","tabFocus","setTimeout","hideControls","toggleControls","timeUpdate","durationUpdate","_this2","showPosterOnEnd","load","updateProgress","updateVolume","checkPlaying","checkLoading","clickToPlay","cursor","touch","paused","ended","disableContextMenu","updateSetting","speed","quality","concat","inputEvent","isIE","proxy","handlerKey","defaultHandler","customHandler","_this3","defaultPrevented","airPlay","toggleMenu","form","showTab","toLowerCase","toggleInvert","invertTime","isWebkit","updateRangeFill","updateSeekTooltip","hover","inverted","webkitDirectionInvertedFromDevice","direction","deltaY","deltaX","uiSupported","isHTML5","removeAttribute","removeElement","inject","ready","setTitle","label","i18n","title","isEmbed","iframe","frameTitle","playing","stopped","loading","timers","setRange","nodeValue","getPercentage","buffered","end","setProgress","time","format","slice","getHours","parseInt","hours","mins","getMinutes","secs","getSeconds","invert","updateTimeDisplay","seeking","displayDuration","styleSheet","sheet","percentage","styles","rules","findIndex","rule","selectorText","deleteRule","insertRule","iconUrl","indexOf","svg4everybody","getIconUrl","iconPath","absolute","iconPrefix","icon","createElementNS","use","path","setAttributeNS","hidden","badge","menu","buttonType","attr","button","iconDefault","iconToggled","labelKey","control","getAttributesFromSelector","createIcon","createLabel","suffix","played","list","checked","item","radio","faux","aria-hidden","insertAdjacentHTML","tooltips","percent","clientRect","getBoundingClientRect","visible","pageX","left","hasClass","setting","tab","tabs","pane","panes","filter","toggleTab","emptyElement","getBadge","createBadge","createMenuItem","getLabel","getLanguage","default","textTracks","tracks","none","currentTrack","disabled","track","toUpperCase","unshift","show","isMenuItem","isButton","clone","position","opacity","name","scrollWidth","scrollHeight","getElementById","transitions","reducedMotion","size","getTabSize","restore","propertyName","off","createButton","createRange","createProgress","createTime","inner","home","_this4","back","setSpeedMenu","loadSprite","seekTime","create","findElements","labels","_this5","setCaptionsMenu","insertAfter","setCurrentTrack","setCue","mode","activeCues","embed","enableTextTrack","cue","getCueAsHTML","caption","youtube","videoId","parseYouTubeId","embedId","containers","setAspectRatio","generateId","google","json","result","items","snippet","YT","loadScript","urls","onYouTubeReadyCallbacks","push","onYouTubeIframeAPIReady","paddingBottom","player","Player","autoplay","location","hostname","href","message","instance","getPlaybackQuality","playbackRate","getPlaybackRate","playVideo","pauseVideo","stop","stopVideo","getDuration","getCurrentTime","seekTo","setPlaybackRate","setPlaybackQuality","setVolume","getVideoUrl","getAvailablePlaybackRates","getVideoData","clearInterval","buffering","setInterval","getVideoLoadedFraction","lastBuffered","build","setQualityMenu","getAvailableQualityLevels","vimeo","Vimeo","padding","offset","transform","params","buildUrlParameters","parseVimeoId","setCurrentTime","selected","setLoop","currentSrc","all","getVideoWidth","getVideoHeight","getAspectRatio","dimensions","getVideoTitle","getTextTracks","cues","stripHTML","seconds","isIos","isTouch","wrap","blankVideo","insertElement","attribute","sources","cancelRequests","destroy","firstSource","check","crossorigin","poster","addStyleHook","insertElements","scrollPosition","jQuery","debug","plyr","original","tagName","hasAttribute","step","eventType","isFullScreen","pageXOffset","pageYOffset","scrollTo","x","y","overflow","webkitShowPlaybackTargetPicker","delay","isEnterFullscreen","noTransition","clearTimeout","mime","soft","done","replaceChild","unload","html5","targetTime","fauxDuration","realDuration","change","states","webkitPresentationMode"],"mappings":"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"}
\ No newline at end of file @@ -233,7 +233,7 @@ Option | Type | Default | Description `seekTime` | Number | `10` | The time, in seconds, to seek when a user hits fast forward or rewind. `volume` | Number | `1` | A number, between 0 and 1, representing the initial volume of the player. `muted` | Boolean | `false` | Whether to start playback muted. If the `muted` attribute is present on a `<video>` or `<audio>` element, this will be automatically set to true. -`clickToPlay` | Boolean | `true` | Click (or tap) of the video container will toggle pause/play. +`clickToPlay` | Boolean | `true` | Click (or tap) of the video container will toggle play/pause. `disableContextMenu` | Boolean | `true` | Disable right click menu on video to <em>help</em> as very primitive obfuscation to prevent downloads of content. `hideControls` | Boolean | `true` | Hide video controls automatically after 2s of no mouse or focus movement, on control element blur (tab out), on playback start or entering fullscreen. As soon as the mouse is moved, a control element is focused or playback is paused, the controls reappear instantly. `showPosterOnEnd` | Boolean | false | This will restore and *reload* HTML5 video once playback is complete. Note: depending on the browser caching, this may result in the video downloading again (or parts of it). Use with caution. @@ -241,9 +241,12 @@ Option | Type | Default | Description `tooltips` | Object | `{ controls: false, seek: true }` | `controls`: Display control labels as tooltips on `:hover` & `:focus` (by default, the labels are screen reader only). `seek`: Display a seek tooltip to indicate on click where the media would seek to. `duration` | Number | `null` | Specify a custom duration for media. `displayDuration` | Boolean | `true` | Displays the duration of the media on the "metadataloaded" event (on startup) in the current time display. This will only work if the `preload` attribute is not set to `none` (or is not set at all) and you choose not to display the duration (see `controls` option). +`invertTime` | Boolean | `true` | Display the current time as a countdown rather than an incremental counter. +`toggleInvert` | Boolean | `true` | Allow users to click to toggle the above. `listeners` | Object | `null` | Allows binding of event listeners to the controls before the default handlers. See the `defaults.js` for available listeners. IF your handler prevents default on the event, the default handler will not fire. `captions` | Object | `{ active: false, language: window.navigator.language.split('-')[0] }` | `active`: Toggles if captions should be active by default. `language`: Sets the default language to load (if available). `fullscreen` | Object | `{ enabled: true, fallback: true }` | `enabled`: Toggles whether fullscreen should be enabled. `fallback`: Allow fallback to a full-window solution. +`ratio` | String | `16:9` | The aspect ratio you want to use for embedded players. `storage` | Object | `{ enabled: true, key: 'plyr' }` | `enabled`: Allow use of local storage to store user settings. `key`: The key name to use. `speed` | Object | `{ selected: 1, options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2] }` | `selected`: The default speed for playback. `options`: Options to display in the menu. Most browsers will refuse to play slower than 0.5. `quality` | Object | `{ default: 'default', options: ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny', 'default'] }` | Currently only supported by YouTube. `default` is the default quality level, determined by YouTube. `options` are the options to display. diff --git a/src/js/captions.js b/src/js/captions.js index 247bf5db..2cab9414 100644 --- a/src/js/captions.js +++ b/src/js/captions.js @@ -79,8 +79,9 @@ const captions = { // Filter doesn't seem to work for a TextTrackList :-( Array.from(this.captions.tracks).forEach(track => { - if (track.language === this.captions.language.toLowerCase()) { + if (track.language.toLowerCase() === this.language.toLowerCase()) { this.captions.currentTrack = track; + console.warn(`Set current track to ${this.language}`); } }); }; diff --git a/src/js/controls.js b/src/js/controls.js index 022fab0d..7df41371 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -115,6 +115,10 @@ const controls = { // Create a badge createBadge(text) { + if (utils.is.empty(text)) { + return null; + } + const badge = utils.createElement('span', { class: this.config.classNames.menu.value, }); @@ -319,6 +323,39 @@ const controls = { return container; }, + // Create a settings menu item + createMenuItem(value, list, type, title, badge = null, checked = false) { + const item = utils.createElement('li'); + + const label = utils.createElement('label', { + class: this.config.classNames.control, + }); + + const radio = utils.createElement( + 'input', + utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs[type]), { + type: 'radio', + name: `plyr-${type}`, + value, + checked, + class: 'plyr__sr-only', + }) + ); + + const faux = utils.createElement('span', { 'aria-hidden': true }); + + label.appendChild(radio); + label.appendChild(faux); + label.insertAdjacentHTML('beforeend', title); + + if (utils.is.htmlElement(badge)) { + label.appendChild(badge); + } + + item.appendChild(label); + list.appendChild(item); + }, + // Update hover tooltip for seeking updateSeekTooltip(event) { // Bail if setting not true @@ -353,7 +390,7 @@ const controls = { } // Display the time a click would seek to - ui.updateTimeDisplay.call(this, this.duration / 100 * percent, this.elements.display.seekTooltip); + ui.updateTimeDisplay.call(this, this.elements.display.seekTooltip, this.duration / 100 * percent); // Set position this.elements.display.seekTooltip.style.left = `${percent}%`; @@ -390,6 +427,7 @@ const controls = { // Set the YouTube quality menu // TODO: Support for HTML5 setQualityMenu(options) { + const type = 'quality'; const list = this.elements.settings.panes.quality.querySelector('ul'); // Set options if passed and filter based on config @@ -401,7 +439,7 @@ const controls = { // Toggle the pane and tab const toggle = !utils.is.empty(this.options.quality) && this.type === 'youtube'; - controls.toggleTab.call(this, 'quality', toggle); + controls.toggleTab.call(this, type, toggle); // If we're hiding, nothing more to do if (!toggle) { @@ -443,35 +481,18 @@ const controls = { return controls.createBadge.call(this, label); }; - this.options.quality.forEach(quality => { - const item = utils.createElement('li'); - - const label = utils.createElement('label', { - class: this.config.classNames.control, - }); - - const radio = utils.createElement( - 'input', - utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs.quality), { - type: 'radio', - name: 'plyr-quality', - value: quality, - }) - ); - - label.appendChild(radio); - label.appendChild(document.createTextNode(controls.getLabel.call(this, 'quality', quality))); - - const badge = getBadge(quality); - if (utils.is.htmlElement(badge)) { - label.appendChild(badge); - } - - item.appendChild(label); - list.appendChild(item); - }); + this.options.quality.forEach(quality => + controls.createMenuItem.call( + this, + quality, + list, + type, + controls.getLabel.call(this, 'quality', quality), + getBadge(quality) + ) + ); - controls.updateSetting.call(this, 'quality', list); + controls.updateSetting.call(this, type, list); }, // Translate a value into a nice label @@ -573,7 +594,7 @@ const controls = { }, // Set the looping options - setLoopMenu() { + /* setLoopMenu() { const options = ['start', 'end', 'all', 'reset']; const list = this.elements.settings.panes.loop.querySelector('ul'); @@ -609,7 +630,7 @@ const controls = { item.appendChild(button); list.appendChild(item); }); - }, + }, */ // Get current selected caption language // TODO: rework this to user the getter in the API? @@ -631,11 +652,13 @@ const controls = { // Set a list of available captions languages setCaptionsMenu() { + // TODO: Captions or language? Currently it's mixed + const type = 'captions'; const list = this.elements.settings.panes.captions.querySelector('ul'); // Toggle the pane and tab const toggle = !utils.is.empty(this.captions.tracks); - controls.toggleTab.call(this, 'captions', toggle); + controls.toggleTab.call(this, type, toggle); // Empty the menu utils.emptyElement(list); @@ -648,7 +671,6 @@ const controls = { // Re-map the tracks into just the data we need const tracks = Array.from(this.captions.tracks).map(track => ({ language: track.language, - badge: true, label: !utils.is.empty(track.label) ? track.label : track.language.toUpperCase(), })); @@ -660,41 +682,24 @@ const controls = { // Generate options tracks.forEach(track => { - const item = utils.createElement('li'); - - const label = utils.createElement('label', { - class: this.config.classNames.control, - }); - - const radio = utils.createElement( - 'input', - utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs.language), { - type: 'radio', - name: 'plyr-language', - value: track.language, - }) + controls.createMenuItem.call( + this, + track.language, + list, + 'language', + track.label || track.language, + controls.createBadge.call(this, track.language.toUpperCase()), + track.language.toLowerCase() === this.captions.language.toLowerCase() ); - - if (track.language.toLowerCase() === this.captions.language.toLowerCase()) { - radio.checked = true; - } - - label.appendChild(radio); - label.appendChild(document.createTextNode(track.label || track.language)); - - if (track.badge) { - label.appendChild(controls.createBadge.call(this, track.language.toUpperCase())); - } - - item.appendChild(label); - list.appendChild(item); }); - controls.updateSetting.call(this, 'captions', list); + controls.updateSetting.call(this, type, list); }, // Set a list of available captions languages setSpeedMenu(options) { + const type = 'speed'; + // Set options if passed and filter based on config if (utils.is.array(options)) { this.options.speed = options.filter(speed => this.config.speed.options.includes(speed)); @@ -704,7 +709,7 @@ const controls = { // Toggle the pane and tab const toggle = !utils.is.empty(this.options.speed); - controls.toggleTab.call(this, 'speed', toggle); + controls.toggleTab.call(this, type, toggle); // If we're hiding, nothing more to do if (!toggle) { @@ -722,39 +727,23 @@ const controls = { utils.emptyElement(list); // Create items - this.options.speed.forEach(speed => { - const item = utils.createElement('li'); - - const label = utils.createElement('label', { - class: this.config.classNames.control, - }); - - const radio = utils.createElement( - 'input', - utils.extend(utils.getAttributesFromSelector(this.config.selectors.inputs.speed), { - type: 'radio', - name: 'plyr-speed', - value: speed, - }) - ); - - label.appendChild(radio); - label.insertAdjacentHTML('beforeend', controls.getLabel.call(this, 'speed', speed)); - item.appendChild(label); - list.appendChild(item); - }); + this.options.speed.forEach(speed => + controls.createMenuItem.call(this, speed, list, type, controls.getLabel.call(this, 'speed', speed)) + ); - controls.updateSetting.call(this, 'speed', list); + controls.updateSetting.call(this, type, list); }, // Show/hide menu toggleMenu(event) { const { form } = this.elements.settings; const button = this.elements.buttons.settings; - const show = utils.is.boolean(event) ? event : form && form.getAttribute('aria-hidden') === 'true'; + const show = utils.is.boolean(event) + ? event + : utils.is.htmlElement(form) && form.getAttribute('aria-hidden') === 'true'; if (utils.is.event(event)) { - const isMenuItem = form && form.contains(event.target); + const isMenuItem = utils.is.htmlElement(form) && form.contains(event.target); const isButton = event.target === this.elements.buttons.settings; // If the click was inside the form or if the click @@ -771,10 +760,11 @@ const controls = { } // Set form and button attributes - if (button) { + if (utils.is.htmlElement(button)) { button.setAttribute('aria-expanded', show); } - if (form) { + + if (utils.is.htmlElement(form)) { form.setAttribute('aria-hidden', !show); if (show) { @@ -882,6 +872,9 @@ const controls = { pane.setAttribute('aria-hidden', !show); tab.setAttribute('aria-expanded', show); pane.removeAttribute('tabindex'); + + // Focus the first item + pane.querySelectorAll('button:not(:disabled), input:not(:disabled), [tabindex]')[0].focus(); }, // Build the default HTML diff --git a/src/js/defaults.js b/src/js/defaults.js index 14c7204d..c9a81842 100644 --- a/src/js/defaults.js +++ b/src/js/defaults.js @@ -22,13 +22,20 @@ const defaults = { // Pass a custom duration duration: null, - // Display the media duration + // Display the media duration on load in the current time position + // If you have opted to display both duration and currentTime, this is ignored displayDuration: true, + // Invert the current time to be a countdown + invertTime: true, + + // Clicking the currentTime inverts it's value to show time left rather than elapsed + toggleInvert: true, + // Aspect ratio (for embeds) ratio: '16:9', - // Click video to play + // Click video container to play/pause clickToPlay: true, // Auto hide the controls @@ -276,6 +283,7 @@ const defaults = { isIos: 'plyr--is-ios', isTouch: 'plyr--is-touch', uiSupported: 'plyr--full-ui', + noTransition: 'plyr--no-transition', menu: { value: 'plyr__menu__value', badge: 'plyr__badge', @@ -298,6 +306,11 @@ const defaults = { }, tabFocus: 'plyr__tab-focus', }, + + // API keys + keys: { + google: null, + }, }; export default defaults; diff --git a/src/js/listeners.js b/src/js/listeners.js index 5c366803..61df32aa 100644 --- a/src/js/listeners.js +++ b/src/js/listeners.js @@ -209,7 +209,7 @@ const listeners = { // Toggle controls on mouse events and entering fullscreen utils.on( this.elements.container, - 'mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen', + 'click mouseenter mouseleave mousemove touchmove enterfullscreen exitfullscreen', event => { this.toggleControls(event); } @@ -217,11 +217,11 @@ const listeners = { } // Handle user exiting fullscreen by escaping etc - if (fullscreen.enabled) { + /* if (fullscreen.enabled) { utils.on(document, fullscreen.eventType, event => { this.toggleFullscreen(event); }); - } + } */ }, // Listen for media events @@ -230,7 +230,7 @@ const listeners = { utils.on(this.media, 'timeupdate seeking', event => ui.timeUpdate.call(this, event)); // Display duration - utils.on(this.media, 'durationchange loadedmetadata', event => ui.displayDuration.call(this, event)); + utils.on(this.media, 'durationchange loadedmetadata', event => ui.durationUpdate.call(this, event)); // Handle the media finishing utils.on(this.media, 'ended', () => { @@ -463,11 +463,16 @@ const listeners = { controls.showTab.call(this, event); // Settings menu items - use event delegation as items are added/removed - // Settings - Language if (utils.matches(event.target, this.config.selectors.inputs.language)) { + // Settings - Language proxy(event, 'language', () => { - this.toggleCaptions(true); - this.language = event.target.value.toLowerCase(); + const language = event.target.value; + + this.toggleCaptions(!utils.is.empty(language)); + + if (!utils.is.empty(language)) { + this.language = event.target.value.toLowerCase(); + } }); } else if (utils.matches(event.target, this.config.selectors.inputs.quality)) { // Settings - Quality @@ -479,7 +484,7 @@ const listeners = { proxy(event, 'speed', () => { this.speed = parseFloat(event.target.value); }); - } else if (utils.matches(event.target, this.config.selectors.buttons.loop)) { + } /* else if (utils.matches(event.target, this.config.selectors.buttons.loop)) { // Settings - Looping // TODO: use toggle buttons proxy(event, 'loop', () => { @@ -488,7 +493,7 @@ const listeners = { this.console.warn('Set loop'); }); - } + } */ }); // Seek @@ -498,6 +503,20 @@ const listeners = { }) ); + // Current time invert + // Only if one time element is used for both currentTime and duration + if (this.config.toggleInvert && !utils.is.htmlElement(this.elements.display.duration)) { + utils.on(this.elements.display.currentTime, 'click', () => { + // Do nothing if we're at the start + if (this.currentTime === 0) { + return; + } + + this.config.invertTime = !this.config.invertTime; + ui.timeUpdate.call(this); + }); + } + // Volume utils.on(this.elements.inputs.volume, inputEvent, event => proxy(event, 'volume', () => { @@ -533,7 +552,7 @@ const listeners = { // TODO: Check we need capture here utils.on( this.elements.controls, - 'focus blur', + 'focusin focusout', event => { this.toggleControls(event); }, diff --git a/src/js/plugins/youtube.js b/src/js/plugins/youtube.js index 6b70af4c..a46773a0 100644 --- a/src/js/plugins/youtube.js +++ b/src/js/plugins/youtube.js @@ -23,19 +23,21 @@ const youtube = { // Set ID this.media.setAttribute('id', utils.generateId(this.type)); - // Get the title - const key = 'AIzaSyDrNwtN3nLH_8rjCmu5Wq3ZCm4MNAVdc0c'; - const url = `https://www.googleapis.com/youtube/v3/videos?id=${videoId}&fields=items(snippet(title))&part=snippet&key=${key}`; - - fetch(url) - .then(response => response.json()) - .then(obj => { - if (utils.is.object(obj)) { - this.config.title = obj.items[0].snippet.title; - ui.setTitle.call(this); - } - }) - .catch(() => {}); + // Get the media title via Google API + const key = this.config.keys.google; + if (utils.is.string(key) && !utils.is.empty(key)) { + const url = `https://www.googleapis.com/youtube/v3/videos?id=${videoId}&key=${key}&fields=items(snippet(title))&part=snippet`; + + fetch(url) + .then(response => (response.ok ? response.json() : null)) + .then(result => { + if (result !== null && utils.is.object(result)) { + this.config.title = result.items[0].snippet.title; + ui.setTitle.call(this); + } + }) + .catch(() => {}); + } // Setup API if (utils.is.object(window.YT)) { diff --git a/src/js/plyr.js b/src/js/plyr.js index df751efe..87fb014a 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -669,7 +669,7 @@ class Plyr { const language = input.toLowerCase(); // If nothing to change, bail - if (this.captions.language === language) { + if (this.language === language) { return; } @@ -797,31 +797,28 @@ class Plyr { // Show the player controls in fullscreen mode toggleControls(toggle) { - const player = this; - // We need controls of course... if (!utils.is.htmlElement(this.elements.controls)) { - return player; + return this; } // Don't hide if config says not to, it's audio, or not ready or loading if (!this.supported.ui || !this.config.hideControls || this.type === 'audio') { - return player; + return this; } let delay = 0; let show = toggle; let isEnterFullscreen = false; - const loading = utils.hasClass(this.elements.container, this.config.classNames.loading); - // Default to false if no boolean + // Get toggle state if not set if (!utils.is.boolean(toggle)) { if (utils.is.event(toggle)) { // Is the enter fullscreen event isEnterFullscreen = toggle.type === 'enterfullscreen'; // Whether to show controls - show = ['mousemove', 'touchstart', 'mouseenter', 'focus'].includes(toggle.type); + show = ['click', 'mousemove', 'touchmove', 'mouseenter', 'focusin'].includes(toggle.type); // Delay hiding on move events if (['mousemove', 'touchmove'].includes(toggle.type)) { @@ -829,8 +826,9 @@ class Plyr { } // Delay a little more for keyboard users - if (toggle.type === 'focus') { + if (toggle.type === 'focusin') { delay = 3000; + utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, true); } } else { show = utils.hasClass(this.elements.container, this.config.classNames.hideControls); @@ -841,7 +839,7 @@ class Plyr { window.clearTimeout(this.timers.hover); // If the mouse is not over the controls, set a timeout to hide them - if (show || this.media.paused || loading) { + if (show || this.media.paused || this.loading) { // Check if controls toggled const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, false); @@ -851,8 +849,8 @@ class Plyr { } // Always show controls when paused or if touch - if (this.media.paused || loading) { - return player; + if (this.media.paused || this.loading) { + return this; } // Delay for hiding on touch @@ -870,6 +868,11 @@ class Plyr { return; } + // Restore transition behaviour + if (!utils.hasClass(this.elements.container, this.config.classNames.hideControls)) { + utils.toggleClass(this.elements.controls, this.config.classNames.noTransition, false); + } + // Check if controls toggled const toggled = utils.toggleClass(this.elements.container, this.config.classNames.hideControls, true); diff --git a/src/js/ui.js b/src/js/ui.js index b9328888..fe8fac0f 100644 --- a/src/js/ui.js +++ b/src/js/ui.js @@ -15,7 +15,7 @@ const ui = { }, // Toggle native HTML5 media controls - toggleNativeControls(toggle) { + toggleNativeControls(toggle = false) { if (toggle && this.isHTML5) { this.media.setAttribute('controls', ''); } else { @@ -100,26 +100,6 @@ const ui = { ui.setTitle.call(this); }, - // Show the duration on metadataloaded - displayDuration() { - if (!this.supported.ui) { - return; - } - - // If there's only one time display, display duration there - if (!this.elements.display.duration && this.config.displayDuration && this.paused) { - ui.updateTimeDisplay.call(this, this.duration, this.elements.display.currentTime); - } - - // If there's a duration element, update content - if (this.elements.display.duration) { - ui.updateTimeDisplay.call(this, this.duration, this.elements.display.duration); - } - - // Update the tooltip (if visible) - controls.updateSeekTooltip.call(this); - }, - // Setup aria attribute for play and iframe title setTitle() { // Find the current text @@ -165,23 +145,6 @@ const ui = { this.toggleControls(this.paused); }, - // Update volume UI and storage - updateVolume() { - if (!this.supported.ui) { - return; - } - - // Update range - if (utils.is.htmlElement(this.elements.inputs.volume)) { - ui.setRange.call(this, this.elements.inputs.volume, this.muted ? 0 : this.volume); - } - - // Update checkbox for mute state - if (utils.is.htmlElement(this.elements.buttons.mute)) { - utils.toggleState(this.elements.buttons.mute, this.muted || this.volume === 0); - } - }, - // Check if media is loading checkLoading(event) { this.loading = event.type === 'waiting'; @@ -199,8 +162,25 @@ const ui = { }, this.loading ? 250 : 0); }, + // Update volume UI and storage + updateVolume() { + if (!this.supported.ui) { + return; + } + + // Update range + if (utils.is.htmlElement(this.elements.inputs.volume)) { + ui.setRange.call(this, this.elements.inputs.volume, this.muted ? 0 : this.volume); + } + + // Update checkbox for mute state + if (utils.is.htmlElement(this.elements.buttons.mute)) { + utils.toggleState(this.elements.buttons.mute, this.muted || this.volume === 0); + } + }, + // Update seek value and lower fill - setRange(target, value) { + setRange(target, value = 0) { if (!utils.is.htmlElement(target)) { return; } @@ -214,9 +194,8 @@ const ui = { // Set <progress> value setProgress(target, input) { - // Default to 0 - const value = !utils.is.undefined(input) ? input : 0; - const progress = !utils.is.undefined(target) ? target : this.elements.display.buffer; + const value = utils.is.number(input) ? input : 0; + const progress = utils.is.htmlElement(target) ? target : this.elements.display.buffer; // Update value and label if (utils.is.htmlElement(progress)) { @@ -232,7 +211,7 @@ const ui = { // Update <progress> elements updateProgress(event) { - if (!this.supported.ui) { + if (!this.supported.ui || !utils.is.event(event)) { return; } @@ -280,41 +259,49 @@ const ui = { }, // Update the displayed time - updateTimeDisplay(value, element) { - // Bail if there's no duration display - if (!utils.is.htmlElement(element)) { - return null; + updateTimeDisplay(target = null, time = 0, inverted = false) { + // Bail if there's no element to display or the value isn't a number + if (!utils.is.htmlElement(target) || !utils.is.number(time)) { + return; } - // Fallback to 0 - const time = !Number.isNaN(value) ? value : 0; + // Format time component to add leading zero + const format = value => `0${value}`.slice(-2); - let secs = parseInt(time % 60, 10); - let mins = parseInt((time / 60) % 60, 10); - const hours = parseInt((time / 60 / 60) % 60, 10); + // Helpers + const getHours = value => parseInt((value / 60 / 60) % 60, 10); + const getMinutes = value => parseInt((value / 60) % 60, 10); + const getSeconds = value => parseInt(value % 60, 10); - // Do we need to display hours? - const displayHours = parseInt((this.duration / 60 / 60) % 60, 10) > 0; + // Breakdown to hours, mins, secs + let hours = getHours(time); + const mins = getMinutes(time); + const secs = getSeconds(time); - // Ensure it's two digits. For example, 03 rather than 3. - secs = `0${secs}`.slice(-2); - mins = `0${mins}`.slice(-2); - - // Generate display - const display = `${(displayHours ? `${hours}:` : '') + mins}:${secs}`; + // Do we need to display hours? + if (getHours(this.duration) > 0) { + hours = `${hours}:`; + } else { + hours = ''; + } // Render - // eslint-disable-next-line - element.textContent = display; - - // Return for looping - return display; + // eslint-disable-next-line no-param-reassign + target.textContent = `${inverted ? '-' : ''}${hours}${format(mins)}:${format(secs)}`; }, // Handle time change event timeUpdate(event) { + // Only invert if only one time element is displayed and used for both duration and currentTime + const invert = !utils.is.htmlElement(this.elements.display.duration) && this.config.invertTime; + // Duration - ui.updateTimeDisplay.call(this, this.currentTime, this.elements.display.currentTime); + ui.updateTimeDisplay.call( + this, + this.elements.display.currentTime, + invert ? this.duration - this.currentTime : this.currentTime, + invert + ); // Ignore updates while seeking if (event && event.type === 'timeupdate' && this.media.seeking) { @@ -324,6 +311,26 @@ const ui = { // Playing progress ui.updateProgress.call(this, event); }, + + // Show the duration on metadataloaded + durationUpdate() { + if (!this.supported.ui) { + return; + } + + // If there's only one time display, display duration there + if (!utils.is.htmlElement(this.elements.display.duration) && this.config.displayDuration && this.paused) { + ui.updateTimeDisplay.call(this, this.elements.display.currentTime, this.duration); + } + + // If there's a duration element, update content + if (utils.is.htmlElement(this.elements.display.duration)) { + ui.updateTimeDisplay.call(this, this.elements.display.duration, this.duration); + } + + // Update the tooltip (if visible) + controls.updateSeekTooltip.call(this); + }, }; export default ui; diff --git a/src/js/utils.js b/src/js/utils.js index 53a16e4b..bb576576 100644 --- a/src/js/utils.js +++ b/src/js/utils.js @@ -31,6 +31,9 @@ const utils = { htmlElement(input) { return !this.undefined(input) && input instanceof HTMLElement; }, + textNode(input) { + return this.getConstructor(input) === Text; + }, event(input) { return !this.undefined(input) && input instanceof Event; }, @@ -49,8 +52,8 @@ const utils = { return ( input === null || typeof input === 'undefined' || - ((this.string(input) || this.array(input) || this.nodeList(input)) && input.length === 0) || - (this.object(input) && Object.keys(input).length === 0) + ((this.string(input) || this.array(input) || this.nodeList(input)) && !input.length) || + (this.object(input) && !Object.keys(input).length) ); }, getConstructor(input) { @@ -140,8 +143,12 @@ const utils = { // Get the sprite fetch(url) - .then(response => response.text()) + .then(response => (response.ok ? response.text() : null)) .then(text => { + if (text === null) { + return; + } + if (support.storage) { window.localStorage.setItem( prefix + id, @@ -152,7 +159,8 @@ const utils = { } updateSprite.call(container, text); - }); + }) + .catch(() => {}); } }, @@ -201,22 +209,6 @@ const utils = { }); }, - // Remove an element - removeElement(element) { - if (!utils.is.htmlElement(element) || !utils.is.htmlElement(element.parentNode)) { - return null; - } - - element.parentNode.removeChild(element); - - return element; - }, - - // Inaert an element after another - insertAfter(element, target) { - target.parentNode.insertBefore(element, target.nextSibling); - }, - // Create a DocumentFragment createElement(type, attributes, text) { // Create a new <element> @@ -236,12 +228,28 @@ const utils = { return element; }, + // Inaert an element after another + insertAfter(element, target) { + target.parentNode.insertBefore(element, target.nextSibling); + }, + // Insert a DocumentFragment insertElement(type, parent, attributes, text) { // Inject the new <element> parent.appendChild(utils.createElement(type, attributes, text)); }, + // Remove an element + removeElement(element) { + if (!utils.is.htmlElement(element) || !utils.is.htmlElement(element.parentNode)) { + return null; + } + + element.parentNode.removeChild(element); + + return element; + }, + // Remove all child elements emptyElement(element) { let { length } = element.childNodes; @@ -433,9 +441,9 @@ const utils = { // Trap focus inside container trapFocus() { - const tabbables = utils.getElements.call(this, 'button:not(:disabled), input:not(:disabled), [tabindex]'); - const first = tabbables[0]; - const last = tabbables[tabbables.length - 1]; + const focusable = utils.getElements.call(this, 'button:not(:disabled), input:not(:disabled), [tabindex]'); + const first = focusable[0]; + const last = focusable[focusable.length - 1]; utils.on( this.elements.container, diff --git a/src/less/base.less b/src/less/base.less index c4158186..0fb14bd8 100644 --- a/src/less/base.less +++ b/src/less/base.less @@ -12,6 +12,7 @@ line-height: @plyr-line-height; direction: ltr; text-shadow: none; + transition: box-shadow 0.3s ease; .plyr-font-smoothing(off); // Media elements @@ -22,6 +23,11 @@ vertical-align: middle; border-radius: inherit; } + + &:focus { + outline: 0; + box-shadow: 0 0 0 3px fade(#000, 10%); + } } // Full UI only diff --git a/src/less/bundle.less b/src/less/bundle.less index bff7fdec..231210c8 100644 --- a/src/less/bundle.less +++ b/src/less/bundle.less @@ -26,4 +26,5 @@ @import 'states/fullscreen'; +@import 'utils/animation'; @import 'utils/hidden'; diff --git a/src/less/components/badges.less b/src/less/components/badges.less index 94035e9b..d87706df 100644 --- a/src/less/components/badges.less +++ b/src/less/components/badges.less @@ -3,11 +3,11 @@ // -------------------------------------------------------------- .plyr__badge { - padding: 0 4px; + padding: 3px 4px; border-radius: 2px; background: @plyr-menu-color; color: @plyr-menu-bg; font-size: @plyr-font-size-tiny; - line-height: 1.5; + line-height: 1; .plyr-font-smoothing(on); } diff --git a/src/less/components/buttons.less b/src/less/components/buttons.less index a7f0ba0a..3a9057c6 100644 --- a/src/less/components/buttons.less +++ b/src/less/components/buttons.less @@ -57,9 +57,9 @@ top: 50%; left: 50%; transform: translate(-50%, -50%); - padding: ceil(@plyr-control-spacing * 1.25); + padding: ceil(@plyr-control-spacing * 1.5); background: fade(@plyr-video-control-bg-hover, 80%); - border: 3px solid currentColor; + border: 0; border-radius: 100%; box-shadow: 0 1px 1px fade(#000, 15%); color: @plyr-video-control-color; @@ -81,7 +81,12 @@ } &:focus { - outline: 1px dotted fade(@plyr-video-control-color, 50%); + outline: 0; + } + + &.plyr__tab-focus { + outline: 0; + box-shadow: 0 0 0 3px fade(@plyr-video-control-color, 50%); } } diff --git a/src/less/components/menus.less b/src/less/components/menus.less index a679e69b..f96393e0 100644 --- a/src/less/components/menus.less +++ b/src/less/components/menus.less @@ -129,11 +129,45 @@ } label.plyr__control { - padding-left: ceil(@plyr-control-padding * 2.5); + padding-left: @plyr-control-padding; - input[type='radio'] { + /*input[type='radio'] { position: relative; left: -@plyr-control-padding; + }*/ + + input[type='radio'] + span { + position: relative; + display: block; + height: 14px; + width: 14px; + border-radius: 100%; + background: fade(#000, 10%); + margin-right: @plyr-control-spacing; + box-shadow: inset 0 1px 1px fade(#000, 15%); + + &::after { + content: ''; + position: absolute; + height: 6px; + width: 6px; + top: 4px; + left: 4px; + transform: scale(0); + opacity: 0; + background: #fff; + border-radius: 100%; + transition: transform 0.3s ease, opacity 0.3s ease; + } + } + + input[type='radio']:checked + span { + background: @plyr-color-main; + + &::after { + transform: scale(1); + opacity: 1; + } } } diff --git a/src/less/components/sliders.less b/src/less/components/sliders.less index d075d69f..dff1da8b 100644 --- a/src/less/components/sliders.less +++ b/src/less/components/sliders.less @@ -12,6 +12,8 @@ cursor: pointer; border: none; background: transparent; + transition: box-shadow 0.3s ease; + border-radius: (@plyr-range-thumb-height * 2); // Used in JS to populate lower fill for WebKit color: @plyr-range-selected-bg; @@ -79,10 +81,6 @@ border: 0; } - &.plyr__tab-focus { - outline-offset: 3px; - } - // Pressed styles &:active { &::-webkit-slider-thumb { @@ -114,7 +112,7 @@ } &.plyr__tab-focus { - outline: 1px dotted fade(@plyr-video-control-color, 50%); + box-shadow: 0 0 0 3px fade(@plyr-video-control-color, 50%); } } @@ -133,6 +131,6 @@ } &.plyr__tab-focus { - outline: 1px dotted fade(@plyr-audio-control-color, 50%); + box-shadow: 0 0 0 3px fade(@plyr-audio-control-color, 50%); } } diff --git a/src/less/utils/animation.less b/src/less/utils/animation.less new file mode 100644 index 00000000..4a5b6b90 --- /dev/null +++ b/src/less/utils/animation.less @@ -0,0 +1,7 @@ +// -------------------------------------------------------------- +// Animation utils +// -------------------------------------------------------------- + +.plyr--no-transition { + transition: none !important; +} |