aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Potts <me@sampotts.me>2017-06-04 15:27:37 +1000
committerSam Potts <me@sampotts.me>2017-06-04 15:27:37 +1000
commit7daa08c32f9a85512e4ff946fcbb572bf4bb1c7b (patch)
treef8598af3a2e2c03382a3bd0addee82a0338da2a9
parentaaab9ad0829d2fff895316797826d23f294ac966 (diff)
downloadplyr-7daa08c32f9a85512e4ff946fcbb572bf4bb1c7b.tar.lz
plyr-7daa08c32f9a85512e4ff946fcbb572bf4bb1c7b.tar.xz
plyr-7daa08c32f9a85512e4ff946fcbb572bf4bb1c7b.zip
Change to proper constructor + prototypes
-rw-r--r--demo/dist/demo.js2
-rw-r--r--demo/src/js/main.js4
-rw-r--r--dist/plyr.js4
-rw-r--r--notes.md30
-rw-r--r--src/js/plyr.js2485
5 files changed, 1343 insertions, 1182 deletions
diff --git a/demo/dist/demo.js b/demo/dist/demo.js
index 322d73bc..bf26da52 100644
--- a/demo/dist/demo.js
+++ b/demo/dist/demo.js
@@ -1 +1 @@
-"document"in self&&("classList"in document.createElement("_")?!function(){"use strict";var e=document.createElement("_");if(e.classList.add("c1","c2"),!e.classList.contains("c2")){var t=function(e){var t=DOMTokenList.prototype[e];DOMTokenList.prototype[e]=function(e){var i,n=arguments.length;for(i=0;i<n;i++)e=arguments[i],t.call(this,e)}};t("add"),t("remove")}if(e.classList.toggle("c3",!1),e.classList.contains("c3")){var i=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(e,t){return 1 in arguments&&!this.contains(e)==!t?t:i.call(this,e)}}e=null}():!function(e){"use strict";if("Element"in e){var t="classList",i="prototype",n=e.Element[i],o=Object,r=String[i].trim||function(){return this.replace(/^\s+|\s+$/g,"")},s=Array[i].indexOf||function(e){for(var t=0,i=this.length;t<i;t++)if(t in this&&this[t]===e)return t;return-1},a=function(e,t){this.name=e,this.code=DOMException[e],this.message=t},c=function(e,t){if(""===t)throw new a("SYNTAX_ERR","An invalid or illegal string was specified");if(/\s/.test(t))throw new a("INVALID_CHARACTER_ERR","String contains an invalid character");return s.call(e,t)},l=function(e){for(var t=r.call(e.getAttribute("class")||""),i=t?t.split(/\s+/):[],n=0,o=i.length;n<o;n++)this.push(i[n]);this._updateClassName=function(){e.setAttribute("class",this.toString())}},u=l[i]=[],d=function(){return new l(this)};if(a[i]=Error[i],u.item=function(e){return this[e]||null},u.contains=function(e){return e+="",c(this,e)!==-1},u.add=function(){var e,t=arguments,i=0,n=t.length,o=!1;do e=t[i]+"",c(this,e)===-1&&(this.push(e),o=!0);while(++i<n);o&&this._updateClassName()},u.remove=function(){var e,t,i=arguments,n=0,o=i.length,r=!1;do for(e=i[n]+"",t=c(this,e);t!==-1;)this.splice(t,1),r=!0,t=c(this,e);while(++n<o);r&&this._updateClassName()},u.toggle=function(e,t){e+="";var i=this.contains(e),n=i?t!==!0&&"remove":t!==!1&&"add";return n&&this[n](e),t===!0||t===!1?t:!i},u.toString=function(){return this.join(" ")},o.defineProperty){var p={get:d,enumerable:!0,configurable:!0};try{o.defineProperty(n,t,p)}catch(e){e.number===-2146823252&&(p.enumerable=!1,o.defineProperty(n,t,p))}}else o[i].__defineGetter__&&n.__defineGetter__(t,d)}}(self)),function(){window.loadSprite=function(e,t){function i(e,t){e.innerHTML=t,n.insertBefore(e,n.childNodes[0])}if("string"==typeof e){var n=document.body,o="cache-",r="string"==typeof t,s=!1,a=function(){if(!r)return!1;var e="___test";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(e){return!1}}();if(!r||0===document.querySelectorAll("#"+t).length){var c=document.createElement("div");if(c.setAttribute("hidden",""),r&&c.setAttribute("id",t),a){var l=localStorage.getItem(o+t);if(s=null!==l){var u=JSON.parse(l);i(c,u.content)}}var d=new XMLHttpRequest;if(!("withCredentials"in d))return;d.open("GET",e,!0),d.onload=function(){a&&localStorage.setItem(o+t,JSON.stringify({content:d.responseText})),i(c,d.responseText)},d.send()}}}}(),function(){function e(e,t,i){if(e)if(e.classList)e.classList[i?"add":"remove"](t);else{var n=(" "+e.className+" ").replace(/\s+/g," ").replace(" "+t+" ","");e.className=n+(i?" "+t:"")}}function t(t,s){if(t in o&&(s||t!==r)&&(r.length||t!==o.video)){switch(t){case o.video:i.source({type:"video",title:"View From A Blue Moon",sources:[{src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4",type:"video/mp4"}],poster:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg",tracks:[{kind:"captions",label:"English",srclang:"en",src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt",default:!0}]});break;case o.audio:i.source({type:"audio",title:"Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;",sources:[{src:"https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3",type:"audio/mp3"},{src:"https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg",type:"audio/ogg"}]});break;case o.youtube:i.source({type:"video",title:"View From A Blue Moon",sources:[{src:"https://www.youtube.com/watch?v=bTqVqk7FSmY",type:"youtube"}]});break;case o.vimeo:i.source({type:"video",title:"View From A Blue Moon",sources:[{src:"https://vimeo.com/76979871",type:"vimeo"}]})}r=t;for(var a=n.length-1;a>=0;a--)e(n[a].parentElement,"active",!1);e(document.querySelector('[data-source="'+t+'"]').parentElement,"active",!0)}}var i=new Plyr("#player",{debug:!0,title:"View From A Blue Moon",iconUrl:"../dist/plyr.svg",tooltips:{controls:!0},captions:{defaultActive:!0},controls:["play-large","play","progress","current-time","mute","volume","captions","settings","fullscreen","pip","airplay"]});window.loadSprite("dist/demo.svg","demo-sprite");var n=document.querySelectorAll("[data-source]"),o={video:"video",audio:"audio",youtube:"youtube",vimeo:"vimeo"},r=window.location.hash.replace("#",""),s=window.history&&window.history.pushState;if([].forEach.call(n,function(e){e.addEventListener("click",function(){var e=this.getAttribute("data-source");t(e),s&&history.pushState({type:e},"","#"+e)})}),window.addEventListener("popstate",function(e){e.state&&"type"in e.state&&t(e.state.type)}),s){var a=!r.length;a&&(r=o.video),r in o&&history.replaceState({type:r},"",a?"":"#"+r),r!==o.video&&t(r,!0)}}(),"plyr.io"===window.location.host&&(!function(e,t,i,n,o,r,s){e.GoogleAnalyticsObject=o,e[o]=e[o]||function(){(e[o].q=e[o].q||[]).push(arguments)},e[o].l=1*new Date,r=t.createElement(i),s=t.getElementsByTagName(i)[0],r.async=1,r.src=n,s.parentNode.insertBefore(r,s)}(window,document,"script","//www.google-analytics.com/analytics.js","ga"),window.ga("create","UA-40881672-11","auto"),window.ga("send","pageview")); \ No newline at end of file
+"document"in self&&("classList"in document.createElement("_")?!function(){"use strict";var e=document.createElement("_");if(e.classList.add("c1","c2"),!e.classList.contains("c2")){var t=function(e){var t=DOMTokenList.prototype[e];DOMTokenList.prototype[e]=function(e){var i,n=arguments.length;for(i=0;i<n;i++)e=arguments[i],t.call(this,e)}};t("add"),t("remove")}if(e.classList.toggle("c3",!1),e.classList.contains("c3")){var i=DOMTokenList.prototype.toggle;DOMTokenList.prototype.toggle=function(e,t){return 1 in arguments&&!this.contains(e)==!t?t:i.call(this,e)}}e=null}():!function(e){"use strict";if("Element"in e){var t="classList",i="prototype",n=e.Element[i],o=Object,r=String[i].trim||function(){return this.replace(/^\s+|\s+$/g,"")},s=Array[i].indexOf||function(e){for(var t=0,i=this.length;t<i;t++)if(t in this&&this[t]===e)return t;return-1},a=function(e,t){this.name=e,this.code=DOMException[e],this.message=t},c=function(e,t){if(""===t)throw new a("SYNTAX_ERR","An invalid or illegal string was specified");if(/\s/.test(t))throw new a("INVALID_CHARACTER_ERR","String contains an invalid character");return s.call(e,t)},l=function(e){for(var t=r.call(e.getAttribute("class")||""),i=t?t.split(/\s+/):[],n=0,o=i.length;n<o;n++)this.push(i[n]);this._updateClassName=function(){e.setAttribute("class",this.toString())}},u=l[i]=[],d=function(){return new l(this)};if(a[i]=Error[i],u.item=function(e){return this[e]||null},u.contains=function(e){return e+="",c(this,e)!==-1},u.add=function(){var e,t=arguments,i=0,n=t.length,o=!1;do e=t[i]+"",c(this,e)===-1&&(this.push(e),o=!0);while(++i<n);o&&this._updateClassName()},u.remove=function(){var e,t,i=arguments,n=0,o=i.length,r=!1;do for(e=i[n]+"",t=c(this,e);t!==-1;)this.splice(t,1),r=!0,t=c(this,e);while(++n<o);r&&this._updateClassName()},u.toggle=function(e,t){e+="";var i=this.contains(e),n=i?t!==!0&&"remove":t!==!1&&"add";return n&&this[n](e),t===!0||t===!1?t:!i},u.toString=function(){return this.join(" ")},o.defineProperty){var p={get:d,enumerable:!0,configurable:!0};try{o.defineProperty(n,t,p)}catch(e){e.number===-2146823252&&(p.enumerable=!1,o.defineProperty(n,t,p))}}else o[i].__defineGetter__&&n.__defineGetter__(t,d)}}(self)),function(){window.loadSprite=function(e,t){function i(e,t){e.innerHTML=t,n.insertBefore(e,n.childNodes[0])}if("string"==typeof e){var n=document.body,o="cache-",r="string"==typeof t,s=!1,a=function(){if(!r)return!1;var e="___test";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(e){return!1}}();if(!r||0===document.querySelectorAll("#"+t).length){var c=document.createElement("div");if(c.setAttribute("hidden",""),r&&c.setAttribute("id",t),a){var l=localStorage.getItem(o+t);if(s=null!==l){var u=JSON.parse(l);i(c,u.content)}}var d=new XMLHttpRequest;if(!("withCredentials"in d))return;d.open("GET",e,!0),d.onload=function(){a&&localStorage.setItem(o+t,JSON.stringify({content:d.responseText})),i(c,d.responseText)},d.send()}}}}(),function(){function e(e,t,i){if(e)if(e.classList)e.classList[i?"add":"remove"](t);else{var n=(" "+e.className+" ").replace(/\s+/g," ").replace(" "+t+" ","");e.className=n+(i?" "+t:"")}}function t(t,s){if(t in o&&(s||t!==r)&&(r.length||t!==o.video)){switch(t){case o.video:i.source({type:"video",title:"View From A Blue Moon",sources:[{src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.mp4",type:"video/mp4"}],poster:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.jpg",tracks:[{kind:"captions",label:"English",srclang:"en",src:"https://cdn.selz.com/plyr/1.5/View_From_A_Blue_Moon_Trailer-HD.en.vtt",default:!0}]});break;case o.audio:i.source({type:"audio",title:"Kishi Bashi &ndash; &ldquo;It All Began With A Burst&rdquo;",sources:[{src:"https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.mp3",type:"audio/mp3"},{src:"https://cdn.selz.com/plyr/1.5/Kishi_Bashi_-_It_All_Began_With_a_Burst.ogg",type:"audio/ogg"}]});break;case o.youtube:i.source({type:"video",title:"View From A Blue Moon",sources:[{src:"https://www.youtube.com/watch?v=bTqVqk7FSmY",type:"youtube"}]});break;case o.vimeo:i.source({type:"video",title:"View From A Blue Moon",sources:[{src:"https://vimeo.com/76979871",type:"vimeo"}]})}r=t;for(var a=n.length-1;a>=0;a--)e(n[a].parentElement,"active",!1);e(document.querySelector('[data-source="'+t+'"]').parentElement,"active",!0)}}var i=new Plyr("#player",{debug:!0,title:"View From A Blue Moon",iconUrl:"../dist/plyr.svg",tooltips:{controls:!0},captions:{defaultActive:!0},controls:["play-large","play","progress","current-time","mute","volume","captions","settings","fullscreen","pip","airplay"]});window.player=i,window.loadSprite("dist/demo.svg","demo-sprite");var n=document.querySelectorAll("[data-source]"),o={video:"video",audio:"audio",youtube:"youtube",vimeo:"vimeo"},r=window.location.hash.replace("#",""),s=window.history&&window.history.pushState;if([].forEach.call(n,function(e){e.addEventListener("click",function(){var e=this.getAttribute("data-source");t(e),s&&history.pushState({type:e},"","#"+e)})}),window.addEventListener("popstate",function(e){e.state&&"type"in e.state&&t(e.state.type)}),s){var a=!r.length;a&&(r=o.video),r in o&&history.replaceState({type:r},"",a?"":"#"+r),r!==o.video&&t(r,!0)}}(),"plyr.io"===window.location.host&&(!function(e,t,i,n,o,r,s){e.GoogleAnalyticsObject=o,e[o]=e[o]||function(){(e[o].q=e[o].q||[]).push(arguments)},e[o].l=1*new Date,r=t.createElement(i),s=t.getElementsByTagName(i)[0],r.async=1,r.src=n,s.parentNode.insertBefore(r,s)}(window,document,"script","//www.google-analytics.com/analytics.js","ga"),window.ga("create","UA-40881672-11","auto"),window.ga("send","pageview")); \ No newline at end of file
diff --git a/demo/src/js/main.js b/demo/src/js/main.js
index 87c71756..ee45d118 100644
--- a/demo/src/js/main.js
+++ b/demo/src/js/main.js
@@ -37,6 +37,10 @@
]
});
+ // Expose for testing
+ window.player = player;
+
+ // Load demo sprite
window.loadSprite('dist/demo.svg', 'demo-sprite');
// Setup type toggle
diff --git a/dist/plyr.js b/dist/plyr.js
index 36a8f22c..16e19d21 100644
--- a/dist/plyr.js
+++ b/dist/plyr.js
@@ -1,2 +1,2 @@
-!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=t(e,document):"function"==typeof define&&define.amd?define([],function(){return t(e,document)}):e.Plyr=t(e,document)}("undefined"!=typeof window?window:this,function(e,t){"use strict";function n(n,u){function c(e,t,n,s){i.event(e,t,n,i.extend({},s,{plyr:De}))}function d(e){return je.elements.container.querySelectorAll(e)}function p(e){return d(e)[0]}function m(e){i.is.string(e)?(i.removeElement(je.elements[e]),je.elements[e]=null):i.removeElement(e)}function f(){function e(e){9===e.which&&je.fullscreen.active&&(e.target!==s||e.shiftKey?e.target===n&&e.shiftKey&&(e.preventDefault(),s.focus()):(e.preventDefault(),n.focus()))}var t=d("input:not([disabled]), button:not([disabled])"),n=t[0],s=t[t.length-1];i.on(je.elements.container,"keydown",e,!1)}function y(e,t){i.is.string(t)?i.insertElement(e,je.elements.media,{src:t}):i.is.array(t)&&t.forEach(function(t){i.insertElement(e,je.elements.media,t)})}function g(){return{url:Re.iconUrl,absolute:0===Re.iconUrl.indexOf("http")||je.browser.isIE}}function b(e,n){var s="http://www.w3.org/2000/svg",a=g(),l=(a.absolute?"":a.url)+"#"+Re.iconPrefix,r=t.createElementNS(s,"svg");i.setAttributes(r,i.extend(n,{role:"presentation"}));var o=t.createElementNS(s,"use");return o.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",l+"-"+e),r.appendChild(o),r}function v(e){var t=Re.i18n[e];switch(e){case"pip":t="PIP";break;case"airplay":t="AirPlay"}return i.createElement("span",{class:Re.classes.hidden},t)}function h(e){var t=i.createElement("span",{class:Re.classes.menu.value});return t.appendChild(i.createElement("span",{class:Re.classes.menu.badge},e)),t}function k(e,t){var n,s,a,l=i.createElement("button");switch(i.is.object(t)||(t={}),"class"in t?t.class.indexOf(Re.classes.control)===-1&&(t.class+=" "+Re.classes.control):t.class=Re.classes.control,e){case"mute":a="toggleMute",n="volume",s="muted";break;case"captions":a="toggleCaptions",n="captions-off",s="captions-on";break;case"fullscreen":a="toggleFullscreen",n="enter-fullscreen",s="exit-fullscreen";break;case"play-large":t.class="plyr__play-large",e="play",a="play",n="play";break;default:a=e,n=e}return i.extend(t,i.getAttributesFromSelector(Re.selectors.buttons[e],t)),i.is.string(s)&&l.appendChild(b(s,{class:"icon--"+s})),l.appendChild(b(n)),l.appendChild(v(a)),i.setAttributes(l,t),je.elements.buttons[e]=l,l}function C(e,t){var n=i.createElement("label",{for:t.id,class:Re.classes.hidden},Re.i18n[e]),s=i.createElement("input",i.extend(i.getAttributesFromSelector(Re.selectors.inputs[e]),{type:"range",min:0,max:100,step:.1,value:0,autocomplete:"off"},t));return je.elements.inputs[e]=s,{label:n,input:s}}function E(e,t){var n=i.createElement("progress",i.extend(i.getAttributesFromSelector(Re.selectors.display[e]),{min:0,max:100,value:0},t));if("volume"!==e){n.appendChild(i.createElement("span",null,"0"));var s="";switch(e){case"played":s=Re.i18n.played;break;case"buffer":s=Re.i18n.buffered}n.textContent="% "+s.toLowerCase()}return je.elements.display[e]=n,n}function A(e){var t=i.createElement("span",{class:"plyr__time"});return t.appendChild(i.createElement("span",{class:Re.classes.hidden},Re.i18n[e])),t.appendChild(i.createElement("span",i.getAttributesFromSelector(Re.selectors.display[e]),"00:00")),je.elements.display[e]=t,t}function w(e){var t=i.createElement("div",i.getAttributesFromSelector(Re.selectors.controls.wrapper));if(i.inArray(Re.controls,"restart")&&t.appendChild(k("restart")),i.inArray(Re.controls,"rewind")&&t.appendChild(k("rewind")),i.inArray(Re.controls,"play")&&(t.appendChild(k("play")),t.appendChild(k("pause"))),i.inArray(Re.controls,"fast-forward")&&t.appendChild(k("fast-forward")),i.inArray(Re.controls,"progress")){var n=i.createElement("span",i.getAttributesFromSelector(Re.selectors.progress)),s=C("seek",{id:"plyr-seek-"+e.id});if(n.appendChild(s.label),n.appendChild(s.input),n.appendChild(E("played")),n.appendChild(E("buffer")),Re.tooltips.seek){var a=i.createElement("span",{role:"tooltip",class:Re.classes.tooltip},"00:00");n.appendChild(a),je.elements.display.seekTooltip=a}je.elements.progress=n,t.appendChild(je.elements.progress)}if(i.inArray(Re.controls,"current-time")&&t.appendChild(A("currentTime")),i.inArray(Re.controls,"duration")&&t.appendChild(A("duration")),i.inArray(Re.controls,"mute")&&t.appendChild(k("mute")),i.inArray(Re.controls,"volume")){var l=i.createElement("span",{class:"plyr__volume"}),r={max:10,value:Re.volume},u=C("volume",i.extend(r,{id:"plyr-volume-"+e.id}));l.appendChild(u.label),l.appendChild(u.input);var c=E("volume",r);l.appendChild(c),t.appendChild(l)}if(i.inArray(Re.controls,"captions")&&t.appendChild(k("captions")),i.inArray(Re.controls,"settings")){var d=i.createElement("div",{class:"plyr__menu"});d.appendChild(k("settings",{id:"plyr-settings-toggle-"+e.id,"aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id,"aria-expanded":!1}));var p=i.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=i.createElement("div"),f=i.createElement("div",{id:"plyr-settings-"+e.id+"-home","aria-hidden":!1,"aria-labelled-by":"plyr-settings-toggle-"+e.id,role:"tabpanel"}),y=i.createElement("ul",{role:"tablist"});Re.settings.forEach(function(t){var n=i.createElement("li",{role:"tab",hidden:""}),s=i.createElement("button",i.extend(i.getAttributesFromSelector(Re.selectors.buttons.settings),{type:"button",class:Re.classes.control+" "+Re.classes.control+"--forward",id:"plyr-settings-"+e.id+"-"+t+"-tab","aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id+"-"+t,"aria-expanded":!1}),Re.i18n[t]),a=i.createElement("span",{class:Re.classes.menu.value});a.innerHTML=e[t],s.appendChild(a),n.appendChild(s),y.appendChild(n),je.elements.settings.tabs[t]=n}),f.appendChild(y),m.appendChild(f),Re.settings.forEach(function(t){var n=i.createElement("div",{id:"plyr-settings-"+e.id+"-"+t,"aria-hidden":!0,"aria-labelled-by":"plyr-settings-"+e.id+"-"+t+"-tab",role:"tabpanel",tabindex:-1,hidden:""}),s=i.createElement("button",{type:"button",class:Re.classes.control+" "+Re.classes.control+"--back","aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id+"-home","aria-expanded":!1},Re.i18n[t]);n.appendChild(s);var a=i.createElement("ul");n.appendChild(a),m.appendChild(n),je.elements.settings.panes[t]=n}),p.appendChild(m),d.appendChild(p),t.appendChild(d),je.elements.settings.form=p,je.elements.settings.menu=d}return i.inArray(Re.controls,"pip")&&o.pip&&t.appendChild(k("pip")),i.inArray(Re.controls,"airplay")&&o.airplay&&t.appendChild(k("airplay")),i.inArray(Re.controls,"fullscreen")&&t.appendChild(k("fullscreen")),je.elements.controls=t,S(),F(),t}function T(e,n){function s(e){var t="";switch(e){case"hd2160":t="4K";break;case"hd1440":t="WQHD";break;case"hd1080":t="HD";break;case"hd720":t="HD"}return t.length?h(t):null}function a(e){switch(e){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";default:return"Auto"}}var l=je.elements.settings.panes.quality.querySelector("ul");je.elements.settings.tabs.quality.removeAttribute("hidden"),je.elements.settings.panes.quality.removeAttribute("hidden"),i.emptyElement(l),i.is.array(e)&&!i.is.empty(e)&&e.filter(function(e){return!i.inArray(["tiny","small"],e)}).forEach(function(e){var n=i.createElement("li"),r=i.createElement("label",{class:Re.classes.control}),o=i.createElement("input",i.extend(i.getAttributesFromSelector(Re.selectors.inputs.quality),{type:"radio",name:"plyr-quality",value:e}));e===Re.quality.selected&&(o.setAttribute("checked",""),o.checked=!0),r.appendChild(o),r.appendChild(t.createTextNode(a(e)));var u=s(e);i.is.htmlElement(u)&&r.appendChild(u),n.appendChild(r),l.appendChild(n)})}function S(){var e=["start","end","all","reset"],t=je.elements.settings.panes.loop.querySelector("ul");je.elements.settings.tabs.loop.removeAttribute("hidden"),je.elements.settings.panes.loop.removeAttribute("hidden"),i.emptyElement(t),e.forEach(function(e){var n=i.createElement("li"),s=i.createElement("button",i.extend(i.getAttributesFromSelector(Re.selectors.buttons.loop),{type:"button",class:Re.classes.control,"data-plyr-loop-action":e}),Re.i18n[e]);if(i.inArray(["start","end"],e)){var a=h("00:00");s.appendChild(a)}n.appendChild(s),t.appendChild(n)})}function x(){var e=je.elements.settings.panes.captions.querySelector("ul");if(je.elements.settings.tabs.captions.removeAttribute("hidden"),je.elements.settings.panes.captions.removeAttribute("hidden"),i.emptyElement(e),!i.is.empty(je.captions.tracks)){var n=[].map.call(je.captions.tracks,function(e){return{language:e.language,badge:!0,label:i.is.empty(e.label)?e.language.toUpperCase():e.label}});n.unshift({language:"off",label:Re.i18n.none}),n.forEach(function(n){var s=i.createElement("li"),a=i.createElement("label",{class:Re.classes.control}),l=i.createElement("input",i.extend(i.getAttributesFromSelector(Re.selectors.inputs.language),{type:"radio",name:"plyr-language",value:n.language}));n.language.toLowerCase()===Re.captions.language.toLowerCase()&&(l.setAttribute("checked",""),l.checked=!0),a.appendChild(l),a.appendChild(t.createTextNode(n.label||n.language)),n.badge&&a.appendChild(h(n.language.toUpperCase())),s.appendChild(a),e.appendChild(s)})}}function F(e){var t=je.elements.settings.panes.speed.querySelector("ul");je.elements.settings.tabs.speed.removeAttribute("hidden"),je.elements.settings.panes.speed.removeAttribute("hidden"),i.emptyElement(t),i.is.array(e)||(e=Re.speed.options),e.forEach(function(e){var n=i.createElement("li"),s=i.createElement("label",{class:Re.classes.control}),a=i.createElement("input",i.extend(i.getAttributesFromSelector(Re.selectors.inputs.speed),{type:"radio",name:"plyr-speed",value:e}));e===Re.speed.selected&&(a.setAttribute("checked",""),a.checked=!0),s.appendChild(a),s.insertAdjacentHTML("beforeend",te(e)),n.appendChild(s),t.appendChild(n)})}function I(){if(je.supported.full&&("audio"!==je.type||Re.fullscreen.allowAudio)&&Re.fullscreen.enabled){var e=o.fullscreen;e||Re.fullscreen.fallback&&!i.inFrame()?(Be((e?"Native":"Fallback")+" fullscreen enabled"),i.toggleClass(je.elements.container,Re.classes.fullscreen.enabled,!0)):Be("Fullscreen not supported and fallback disabled"),je.elements.buttons&&je.elements.buttons.fullscreen&&i.toggleState(je.elements.buttons.fullscreen,!1),f()}}function P(e){if(i.inArray(["video","vimeo"],je.type)&&("video"!==je.type||o.textTracks)&&(i.is.htmlElement(je.elements.captions)||(je.elements.captions=i.createElement("div",i.getAttributesFromSelector(Re.selectors.captions)),i.insertAfter(je.elements.captions,je.elements.wrapper)),je.captions.tracks=i.is.array(e)?e:je.elements.media.textTracks,i.toggleClass(je.elements.container,Re.classes.captions.enabled,!i.is.empty(je.captions.tracks)),!i.is.empty(je.captions.tracks))){if(O(),"video"===je.type){var t=Re.captions.language.toLowerCase();[].forEach.call(je.captions.tracks,function(e){i.off(e,"cuechange",N),e.mode="hidden",e.language===t&&(je.captions.currentTrack=e)}),i.is.track(je.captions.currentTrack)||(He("No language found to match "+t+" in tracks"),je.captions.currentTrack=je.captions.tracks[0]);var n=je.captions.currentTrack;i.is.track(n)&&i.inArray(["captions","subtitles"],n.kind)&&(i.on(n,"cuechange",N),n.activeCues&&n.activeCues.length>0&&N(n))}x()}}function _(){return!o.textTracks||i.is.empty(je.captions.tracks)?"No Subs":je.captions.enabled?je.captions.currentTrack.label:"Disabled"}function N(e){i.is.event(e)&&(e=e.target);var t=e.activeCues[0];i.is.cue(t)?q(t.getCueAsHTML()):q()}function L(e){i.is.string(e)?Re.captions.language=e.toLowerCase():i.is.event(e)&&(Re.captions.language=e.target.value.toLowerCase()),q(),P()}function q(e){if(i.is.htmlElement(je.elements.captions)){var t=i.createElement("span");i.emptyElement(je.elements.captions),i.is.undefined(e)&&(e=""),i.is.string(e)?t.textContent=e.trim():t.appendChild(e),je.elements.captions.appendChild(t)}else He("No captions element to render to")}function O(){if(je.elements.buttons.captions){var e=je.storage.captions;i.is.boolean(e)?Re.captions.active=e:e=Re.captions.active,e&&(i.toggleClass(je.elements.container,Re.classes.captions.active,!0),i.toggleState(je.elements.buttons.captions,!0))}}function M(e){je.supported.full&&je.elements.buttons.captions&&(i.is.boolean(e)||(e=je.elements.container.className.indexOf(Re.classes.captions.active)===-1),je.captions.enabled=e,i.toggleState(je.elements.buttons.captions,je.captions.enabled),i.toggleClass(je.elements.container,Re.classes.captions.active,je.captions.enabled),c(je.elements.container,je.captions.enabled?"captionsenabled":"captionsdisabled",!0),W({captions:je.captions.enabled}))}function j(){if(Re.loadSprite){var e=g();e.absolute?(Be("AJAX loading absolute SVG sprite"+(je.browser.isIE?" (due to IE)":"")),i.loadSprite(e.url,"sprite-plyr")):Be("Sprite will be used as external resource directly")}i.inArray(Re.controls,"play-large")&&(je.elements.buttons.playLarge=k("play-large"),je.elements.container.appendChild(je.elements.buttons.playLarge)),je.id=Math.floor(1e4*Math.random());var n=null;n=i.is.string(Re.controls)?Re.controls:i.is.function(Re.controls)?Re.controls({id:je.id,seektime:Re.seekTime}):w({id:je.id,seektime:Re.seekTime,speed:te(),quality:"HD",captions:_(),loop:"None"});var s;if(i.is.string(Re.selectors.controls.container)&&(s=t.querySelector(Re.selectors.controls.container)),i.is.htmlElement(s)||(s=je.elements.container),i.is.htmlElement(n)?s.appendChild(n):s.insertAdjacentHTML("beforeend",n),i.is.htmlElement(je.elements.controls)&&V(),Re.tooltips.controls)for(var a=d([Re.selectors.controls.wrapper," ",Re.selectors.labels," .",Re.classes.hidden].join("")),l=a.length-1;l>=0;l--){var r=a[l];i.toggleClass(r,Re.classes.hidden,!1),i.toggleClass(r,Re.classes.tooltip,!0)}}function V(){try{return je.elements.controls=p(Re.selectors.controls.wrapper),je.elements.buttons={play:d(Re.selectors.buttons.play),pause:p(Re.selectors.buttons.pause),restart:p(Re.selectors.buttons.restart),rewind:p(Re.selectors.buttons.rewind),forward:p(Re.selectors.buttons.forward),mute:p(Re.selectors.buttons.mute),pip:p(Re.selectors.buttons.pip),airplay:p(Re.selectors.buttons.airplay),settings:p(Re.selectors.buttons.settings),captions:p(Re.selectors.buttons.captions),fullscreen:p(Re.selectors.buttons.fullscreen)},je.elements.progress=p(Re.selectors.progress),je.elements.inputs={seek:p(Re.selectors.inputs.seek),volume:p(Re.selectors.inputs.volume)},je.elements.display={buffer:p(Re.selectors.display.buffer),played:p(Re.selectors.display.played),volume:p(Re.selectors.display.volume),duration:p(Re.selectors.display.duration),currentTime:p(Re.selectors.display.currentTime)},i.is.htmlElement(je.elements.progress)&&(je.elements.display.seekTooltip=je.elements.progress.querySelector("."+Re.classes.tooltip)),!0}catch(e){return He("It looks like there is a problem with your custom controls HTML",e),R(!0),!1}}function D(){i.toggleClass(je.elements.container,Re.selectors.container.replace(".",""),je.supported.full)}function R(e){e&&i.inArray(l.html5,je.type)?je.elements.media.setAttribute("controls",""):je.elements.media.removeAttribute("controls")}function B(e){var t=Re.i18n.play;if(i.is.string(Re.title)&&!i.is.empty(Re.title)&&(t+=", "+Re.title,je.elements.container.setAttribute("aria-label",Re.title)),je.supported.full&&(i.is.htmlElement(je.elements.buttons.play)&&je.elements.buttons.play.setAttribute("aria-label",t),i.is.htmlElement(je.elements.buttons.playLarge)&&je.elements.buttons.playLarge.setAttribute("aria-label",t)),i.is.htmlElement(e)){var n=i.is.string(Re.title)&&!i.is.empty(Re.title)?Re.title:"video";e.setAttribute("title",Re.i18n.frameTitle.replace("{title}",n))}}function H(){var t=null;je.storage={},o.storage&&Re.storage.enabled&&(e.localStorage.removeItem("plyr-volume"),t=e.localStorage.getItem(Re.storage.key),t&&(/^\d+(\.\d+)?$/.test(t)?W({volume:parseFloat(t)}):je.storage=JSON.parse(t)))}function W(t){o.storage&&Re.storage.enabled&&(i.extend(je.storage,t),e.localStorage.setItem(Re.storage.key,JSON.stringify(je.storage)))}function Y(){return je.elements.media?(je.supported.full&&(i.toggleClass(je.elements.container,Re.classes.type.replace("{0}",je.type),!0),i.inArray(l.embed,je.type)&&i.toggleClass(je.elements.container,Re.classes.type.replace("{0}","video"),!0),i.toggleClass(je.elements.container,Re.classes.pip.enabled,o.pip&&"video"===je.type),i.toggleClass(je.elements.container,Re.classes.airplay.enabled,o.airplay&&i.inArray(l.html5,je.type)),i.toggleClass(je.elements.container,Re.classes.stopped,Re.autoplay),i.toggleClass(je.elements.container,Re.classes.isIos,je.browser.isIos),i.toggleClass(je.elements.container,Re.classes.isTouch,o.touch)),i.inArray(["video","youtube","vimeo"],je.type)&&(je.elements.wrapper=i.createElement("div",{class:Re.classes.videoWrapper}),i.wrap(je.elements.media,je.elements.wrapper)),void(i.inArray(l.embed,je.type)&&U())):void He("No media element found!")}function U(){var t,n=je.type+"-"+Math.floor(1e4*Math.random());switch(je.type){case"youtube":t=i.parseYouTubeId(je.embedId);break;default:t=je.embedId}for(var s=d('[id^="'+je.type+'-"]'),a=s.length-1;a>=0;a--)i.removeElement(s[a]);if(i.toggleClass(je.elements.wrapper,Re.classes.embedWrapper,!0),"youtube"===je.type)je.elements.media.setAttribute("id",n),i.is.object(e.YT)?z(t):(i.injectScript(Re.urls.youtube.api),e.onYouTubeReadyCallbacks=e.onYouTubeReadyCallbacks||[],e.onYouTubeReadyCallbacks.push(function(){z(t)}),e.onYouTubeIframeAPIReady=function(){e.onYouTubeReadyCallbacks.forEach(function(e){e()})});else if("vimeo"===je.type)if(je.elements.media.setAttribute("id",n),i.is.object(e.Vimeo))J(t);else{i.injectScript(Re.urls.vimeo.api);var l=e.setInterval(function(){i.is.object(e.Vimeo)&&(e.clearInterval(l),J(t))},50)}else if("soundcloud"===je.type){var r=i.createElement("iframe");r.loaded=!1,i.on(r,"load",function(){r.loaded=!0}),i.setAttributes(r,{src:"https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/"+t,id:n}),je.elements.media.appendChild(r),e.SC||i.injectScript(Re.urls.soundcloud.api);var o=e.setInterval(function(){e.SC&&r.loaded&&(e.clearInterval(o),X.call(r))},50)}}function Q(){je.supported.full&&(qe(),Oe()),B(p("iframe"))}function z(t){je.embed=new e.YT.Player(je.elements.media.id,{videoId:t,playerVars:{autoplay:Re.autoplay?1:0,controls:je.supported.full?0:1,rel:0,showinfo:0,iv_load_policy:3,cc_load_policy:Re.captions.active?1:0,cc_lang_pref:"en",wmode:"transparent",modestbranding:1,disablekb:1,playsinline:1,origin:e.location.href},events:{onError:function(e){c(je.elements.container,"error",!0,{code:e.data,embed:e.target})},onPlaybackQualityChange:function(e){var t=e.target,n=t.getPlaybackQuality();console.warn(n)},onReady:function(t){var n=t.target;je.elements.media.play=function(){n.playVideo(),je.elements.media.paused=!1},je.elements.media.pause=function(){n.pauseVideo(),je.elements.media.paused=!0},je.elements.media.stop=function(){n.stopVideo(),je.elements.media.paused=!0},je.elements.media.duration=n.getDuration(),je.elements.media.paused=!0,je.elements.media.currentTime=0,je.elements.media.muted=n.isMuted();var s=n.getPlaybackRate(),a=n.getAvailablePlaybackRates();console.warn(s,a),Re.title=n.getVideoData().title,je.supported.full&&je.elements.media.setAttribute("tabindex",-1),Q(),c(je.elements.media,"timeupdate"),c(je.elements.media,"durationchange"),e.clearInterval(Ve.buffering),Ve.buffering=e.setInterval(function(){je.elements.media.buffered=n.getVideoLoadedFraction(),(null===je.elements.media.lastBuffered||je.elements.media.lastBuffered<je.elements.media.buffered)&&c(je.elements.media,"progress"),je.elements.media.lastBuffered=je.elements.media.buffered,1===je.elements.media.buffered&&(e.clearInterval(Ve.buffering),c(je.elements.media,"canplaythrough"))},200)},onStateChange:function(t){var n=t.target;switch(e.clearInterval(Ve.playing),t.data){case 0:if(Re.loop.active){n.stopVideo(),n.playVideo();break}je.elements.media.paused=!0,c(je.elements.media,"ended");break;case 1:je.elements.media.paused=!1,je.elements.media.seeking&&c(je.elements.media,"seeked"),je.elements.media.seeking=!1,c(je.elements.media,"play"),c(je.elements.media,"playing"),Ve.playing=e.setInterval(function(){je.elements.media.currentTime=n.getCurrentTime(),c(je.elements.media,"timeupdate")},100),je.elements.media.duration!==n.getDuration()&&(je.elements.media.duration=n.getDuration(),c(je.elements.media,"durationchange"));var s=n.getAvailableQualityLevels(),a=n.getPlaybackQuality();T(s,a);break;case 2:je.elements.media.paused=!0,c(je.elements.media,"pause")}c(je.elements.container,"statechange",!1,{code:t.data})}}})}function J(t){je.embed=new e.Vimeo.Player(je.elements.media,{id:t,loop:Re.loop.active,autoplay:Re.autoplay,byline:!1,portrait:!1,title:!1}),je.elements.media.play=function(){je.embed.play(),je.elements.media.paused=!1},je.elements.media.pause=function(){je.embed.pause(),je.elements.media.paused=!0},je.elements.media.stop=function(){je.embed.stop(),je.elements.media.paused=!0},je.elements.media.paused=!0,je.elements.media.currentTime=0,Q(),je.embed.getCurrentTime().then(function(e){je.elements.media.currentTime=e,c(je.elements.media,"timeupdate")}),je.embed.getDuration().then(function(e){je.elements.media.duration=e,c(je.elements.media,"durationchange")}),je.embed.getTextTracks().then(function(e){P(e),Re.captions.active&&je.embed.enableTextTrack(Re.captions.language.toLowerCase())}),je.embed.on("cuechange",function(e){var t=null;e.cues.length&&(t=i.stripHTML(e.cues[0].text)),q(t)}),je.embed.on("loaded",function(){i.is.htmlElement(je.embed.element)&&je.supported.full&&je.embed.element.setAttribute("tabindex",-1)}),je.embed.on("play",function(){je.elements.media.paused=!1,c(je.elements.media,"play"),c(je.elements.media,"playing")}),je.embed.on("pause",function(){je.elements.media.paused=!0,c(je.elements.media,"pause")}),je.embed.on("timeupdate",function(e){je.elements.media.seeking=!1,je.elements.media.currentTime=e.seconds,c(je.elements.media,"timeupdate")}),je.embed.on("progress",function(e){je.elements.media.buffered=e.percent,c(je.elements.media,"progress"),1===parseInt(e.percent)&&c(je.elements.media,"canplaythrough")}),je.embed.on("seeked",function(){je.elements.media.seeking=!1,c(je.elements.media,"seeked"),c(je.elements.media,"play")}),je.embed.on("ended",function(){je.elements.media.paused=!0,c(je.elements.media,"ended")})}function X(){je.embed=e.SC.Widget(this),je.embed.bind(e.SC.Widget.Events.READY,function(){je.elements.media.play=function(){je.embed.play(),je.elements.media.paused=!1},je.elements.media.pause=function(){je.embed.pause(),je.elements.media.paused=!0},je.elements.media.stop=function(){je.embed.seekTo(0),je.embed.pause(),je.elements.media.paused=!0},je.elements.media.paused=!0,je.elements.media.currentTime=0,je.embed.getDuration(function(e){je.elements.media.duration=e/1e3,Q()}),je.embed.getPosition(function(e){je.elements.media.currentTime=e,c(je.elements.media,"timeupdate")}),je.embed.bind(e.SC.Widget.Events.PLAY,function(){je.elements.media.paused=!1,c(je.elements.media,"play"),c(je.elements.media,"playing")}),je.embed.bind(e.SC.Widget.Events.PAUSE,function(){je.elements.media.paused=!0,c(je.elements.media,"pause")}),je.embed.bind(e.SC.Widget.Events.PLAY_PROGRESS,function(e){je.elements.media.seeking=!1,je.elements.media.currentTime=e.currentPosition/1e3,c(je.elements.media,"timeupdate")}),je.embed.bind(e.SC.Widget.Events.LOAD_PROGRESS,function(e){je.elements.media.buffered=e.loadProgress,c(je.elements.media,"progress"),1===parseInt(e.loadProgress)&&c(je.elements.media,"canplaythrough")}),je.embed.bind(e.SC.Widget.Events.FINISH,function(){je.elements.media.paused=!0,c(je.elements.media,"ended")})})}function $(){"play"in je.elements.media&&je.elements.media.play()}function G(){"pause"in je.elements.media&&je.elements.media.pause()}function K(e){return i.is.boolean(e)||(e=je.elements.media.paused),e?$():G(),e}function Z(e){i.inArray(["start","end","all","none","toggle"],e)||(e="toggle");var n=Number(je.elements.media.currentTime);switch(e){case"start":Re.loop.end&&Re.loop.end<=n&&(Re.loop.end=null),Re.loop.start=n,Re.loop.indicator.start=je.elements.display.played.value;break;case"end":if(Re.loop.start>=n)return;Re.loop.end=n,Re.loop.indicator.end=je.elements.display.played.value;break;case"all":Re.loop.start=0,Re.loop.end=je.elements.media.duration-2,Re.loop.indicator.start=0,Re.loop.indicator.end=100;break;case"toggle":Re.loop.active?(Re.loop.start=0,Re.loop.end=null):(Re.loop.start=0,Re.loop.end=je.elements.media.duration-2);break;default:Re.loop.start=0,Re.loop.end=null}Re.loop.active=i.is.number(Re.loop.start)&&i.is.number(Re.loop.end);var s=(Ce(Re.loop.start,p('[data-plyr-loop="start"]')),null);i.is.number(Re.loop.end)&&(s=Ce(Re.loop.end,t.querySelector('[data-loop__value="loopout"]'))),Re.loop.active}function ee(e){return i.is.event(e)?e=parseFloat(e.target.value):i.is.number(e)||(e=parseFloat(je.storage.speed||Re.speed.selected)),e<.1&&(e=.1),e>2&&(e=2),i.is.array(Re.speed.options)?(Re.speed.selected=e,je.elements.media.playbackRate=e,void W({speed:e})):void He("Invalid speeds format")}function te(e){return i.is.number(e)||(e=Re.speed.selected),1===e?"Normal":e+"&times;"}function ne(e){i.is.number(e)||(e=Re.seekTime),ae(je.elements.media.currentTime-e)}function se(e){i.is.number(e)||(e=Re.seekTime),ae(je.elements.media.currentTime+e)}function ae(e){var t=0,n=je.elements.media.paused,s=le();i.is.number(e)?t=e:i.is.event(e)&&i.inArray(["input","change"],e.type)&&(t=e.target.value/e.target.max*s),t<0?t=0:t>s&&(t=s),we(t);try{je.elements.media.currentTime=t.toFixed(4)}catch(e){}if(i.inArray(l.embed,je.type)){switch(je.type){case"youtube":je.embed.seekTo(t);break;case"vimeo":je.embed.setCurrentTime(t.toFixed(0));break;case"soundcloud":je.embed.seekTo(1e3*t)}n&&G(),c(je.elements.media,"timeupdate"),je.elements.media.seeking=!0,c(je.elements.media,"seeking")}Be("Seeking to "+je.elements.media.currentTime+" seconds")}function le(){var e=parseInt(Re.duration),t=0;return null===je.elements.media.duration||isNaN(je.elements.media.duration)||(t=je.elements.media.duration),isNaN(e)?t:e}function ie(){i.toggleClass(je.elements.container,Re.classes.playing,!je.elements.media.paused),i.toggleClass(je.elements.container,Re.classes.stopped,je.elements.media.paused),Se(je.elements.media.paused)}function re(){s={x:e.pageXOffset||0,y:e.pageYOffset||0}}function oe(){e.scrollTo(s.x,s.y)}function ue(e){var n=o.fullscreen;if(n){if(!e||e.type!==r.eventType)return r.isFullScreen(je.elements.container)?r.cancelFullScreen():(re(),r.requestFullScreen(je.elements.container)),void(je.fullscreen.active=r.isFullScreen(je.elements.container));je.fullscreen.active=r.isFullScreen(je.elements.container)}else je.fullscreen.active=!je.fullscreen.active,t.body.style.overflow=je.fullscreen.active?"hidden":"";i.toggleClass(je.elements.container,Re.classes.fullscreen.active,je.fullscreen.active),f(je.fullscreen.active),je.elements.buttons&&je.elements.buttons.fullscreen&&i.toggleState(je.elements.buttons.fullscreen,je.fullscreen.active),c(je.elements.container,je.fullscreen.active?"enterfullscreen":"exitfullscreen",!0),!je.fullscreen.active&&n&&oe()}function ce(e){var t=je.elements.settings.form,n=je.elements.buttons.settings,s=i.is.boolean(e)?e:"true"===t.getAttribute("aria-hidden");if(i.is.event(e)){var a=t.contains(e.target),l=e.target===je.elements.buttons.settings;if(a||!a&&!l&&s)return;l&&e.stopPropagation()}t.setAttribute("aria-hidden",!s),n.setAttribute("aria-expanded",s),s?t.removeAttribute("tabindex"):t.setAttribute("tabindex",-1)}function de(e){var t,n,s=e.cloneNode(!0);return s.style.position="absolute",s.style.opacity=0,s.setAttribute("aria-hidden",!1),[].forEach.call(s.querySelectorAll("input[name]"),function(e){var t=e.getAttribute("name");e.setAttribute("name",t+"-clone")}),e.parentNode.appendChild(s),t=s.scrollWidth,n=s.scrollHeight,i.removeElement(s),{width:t,height:n}}function pe(e){var n=je.elements.settings.menu,s=e.target,a="false"===s.getAttribute("aria-expanded"),l=t.getElementById(s.getAttribute("aria-controls"));if(i.is.htmlElement(l)){var r="tabpanel"===l.getAttribute("role");if(r){var u=n.querySelector('[role="tabpanel"][aria-hidden="false"]'),c=u.parentNode;if([].forEach.call(n.querySelectorAll('[aria-controls="'+u.getAttribute("id")+'"]'),function(e){e.setAttribute("aria-expanded",!1)}),o.transitions){c.style.width=u.scrollWidth+"px",c.style.height=u.scrollHeight+"px";var d=de(l),p=function(e){e.target===c&&i.inArray(["width","height"],e.propertyName)&&(c.style.width="",c.style.height="",i.off(c,i.transitionEnd,p))};i.on(c,i.transitionEnd,p),c.style.width=d.width+"px",c.style.height=d.height+"px"}u.setAttribute("aria-hidden",!0),u.setAttribute("tabindex",-1),l.setAttribute("aria-hidden",!a),s.setAttribute("aria-expanded",a),l.removeAttribute("tabindex")}}}function me(e){if(i.is.boolean(e)||(e=!je.elements.media.muted),i.toggleState(je.elements.buttons.mute,e),je.elements.media.muted=e,0===je.elements.media.volume&&fe(Re.volume),i.inArray(l.embed,je.type)){switch(je.type){case"youtube":je.embed[je.elements.media.muted?"mute":"unMute"]();break;case"vimeo":case"soundcloud":je.embed.setVolume(je.elements.media.muted?0:parseFloat(Re.volume/10))}c(je.elements.media,"volumechange")}}function fe(e){var t=10,n=0;if(i.is.event(e)&&(e=e.target.value),i.is.undefined(e)&&(e=je.storage.volume),(null===e||isNaN(e))&&(e=Re.volume),e>t&&(e=t),e<n&&(e=n),je.elements.media.volume=parseFloat(e/t),je.elements.display.volume&&(je.elements.display.volume.value=e),i.inArray(l.embed,je.type)){switch(je.type){case"youtube":je.embed.setVolume(100*je.elements.media.volume);break;case"vimeo":case"soundcloud":je.embed.setVolume(je.elements.media.volume)}c(je.elements.media,"volumechange")}0===e?je.elements.media.muted=!0:je.elements.media.muted&&e>0&&me()}function ye(e){var t=je.elements.media.muted?0:10*je.elements.media.volume;i.is.number(e)||(e=1),fe(t+e)}function ge(e){var t=je.elements.media.muted?0:10*je.elements.media.volume;i.is.number(e)||(e=1),fe(t-e)}function be(){var e=je.elements.media.muted?0:10*je.elements.media.volume;je.supported.full&&(je.elements.inputs.volume&&(je.elements.inputs.volume.value=e),je.elements.display.volume&&(je.elements.display.volume.value=e)),W({volume:e}),i.toggleClass(je.elements.container,Re.classes.muted,0===e),je.supported.full&&je.elements.buttons.mute&&i.toggleState(je.elements.buttons.mute,0===e)}function ve(e){var t="waiting"===e.type;clearTimeout(Ve.loading),Ve.loading=setTimeout(function(){i.toggleClass(je.elements.container,Re.classes.loading,t),Se(t)},t?250:0)}function he(e){if(je.supported.full){var t=je.elements.display.played,n=0,s=le();if(e)switch(e.type){case"timeupdate":case"seeking":if(je.elements.controls.pressed)return;n=i.getPercentage(je.elements.media.currentTime,s),"timeupdate"===e.type&&je.elements.inputs.seek&&(je.elements.inputs.seek.value=n);break;case"playing":case"progress":t=je.elements.display.buffer,n=function(){var e=je.elements.media.buffered;return e&&e.length?i.getPercentage(e.end(0),s):i.is.number(e)?100*e:0}()}i.is.number(Re.loop.start)&&i.is.number(Re.loop.end)&&je.elements.media.currentTime>=Re.loop.end&&ae(Re.loop.start),ke(t,n)}}function ke(e,t){if(je.supported.full){if(i.is.undefined(t)&&(t=0),i.is.undefined(e)){if(!i.is.htmlElement(je.elements.display.buffer))return;e=je.elements.display.buffer}if(i.is.htmlElement(e)){e.value=t;var n=e.getElementsByTagName("span")[0];i.is.htmlElement(n)&&(n.childNodes[0].nodeValue=t)}}}function Ce(e,t){if(t){isNaN(e)&&(e=0);var n=parseInt(e%60),s=parseInt(e/60%60),a=parseInt(e/60/60%60),l=parseInt(le()/60/60%60)>0;n=("0"+n).slice(-2),s=("0"+s).slice(-2);var i=(l?a+":":"")+s+":"+n;return t.textContent=i,i}}function Ee(){if(je.supported.full){var e=le()||0;
-!je.elements.display.duration&&Re.displayDuration&&je.elements.media.paused&&Ce(e,je.elements.display.currentTime),je.elements.display.duration&&Ce(e,je.elements.display.duration),Te()}}function Ae(e){Ce(je.elements.media.currentTime,je.elements.display.currentTime),e&&"timeupdate"===e.type&&je.elements.media.seeking||he(e)}function we(e){i.is.number(e)||(e=0);var t=le(),n=i.getPercentage(e,t);je.elements.progress&&je.elements.display.played&&(je.elements.display.played.value=n),je.elements.buttons&&je.elements.inputs.seek&&(je.elements.inputs.seek.value=n)}function Te(e){var t=le();if(Re.tooltips.seek&&i.is.htmlElement(je.elements.inputs.seek)&&i.is.htmlElement(je.elements.display.seekTooltip)&&0!==t){var n=je.elements.inputs.seek.getBoundingClientRect(),s=0,a=Re.classes.tooltip+"--visible";if(i.is.event(e))s=100/n.width*(e.pageX-n.left);else{if(!i.hasClass(je.elements.display.seekTooltip,a))return;s=je.elements.display.seekTooltip.style.left.replace("%","")}s<0?s=0:s>100&&(s=100),Ce(t/100*s,je.elements.display.seekTooltip),je.elements.display.seekTooltip.style.left=s+"%",i.is.event(e)&&i.inArray(["mouseenter","mouseleave"],e.type)&&i.toggleClass(je.elements.display.seekTooltip,a,"mouseenter"===e.type)}}function Se(t){if(Re.hideControls&&"audio"!==je.type){var n=0,s=!1,a=t,l=i.hasClass(je.elements.container,Re.classes.loading);if(i.is.boolean(t)||(t&&t.type?(s="enterfullscreen"===t.type,a=i.inArray(["mousemove","touchstart","mouseenter","focus"],t.type),i.inArray(["mousemove","touchmove"],t.type)&&(n=2e3),"focus"===t.type&&(n=3e3)):a=i.hasClass(je.elements.container,Re.classes.hideControls)),e.clearTimeout(Ve.hover),a||je.elements.media.paused||l){if(i.toggleClass(je.elements.container,Re.classes.hideControls,!1),je.elements.media.paused||l)return;o.touch&&(n=3e3)}a&&je.elements.media.paused||(Ve.hover=e.setTimeout(function(){(!je.elements.controls.pressed&&!je.elements.controls.hover||s)&&i.toggleClass(je.elements.container,Re.classes.hideControls,!0)},n))}}function xe(e){if(!i.is.undefined(e))return void Fe(e);var t;switch(je.type){case"youtube":t=je.embed.getVideoUrl();break;case"vimeo":je.embed.getVideoUrl.then(function(e){t=e});break;case"soundcloud":je.embed.getCurrentSound(function(e){t=e.permalink_url});break;default:t=je.elements.media.currentSrc}return t||""}function Fe(e){function t(){if(je.embed=null,m("media"),m("captions"),m("wrapper"),je.elements.container&&je.elements.container.removeAttribute("class"),"type"in e&&(je.type=e.type,"video"===je.type)){var t=e.sources[0];"type"in t&&i.inArray(l.embed,t.type)&&(je.type=t.type)}switch(je.supported=i.checkSupport(je.type,Re.inline),je.type){case"video":je.elements.media=i.createElement("video");break;case"audio":je.elements.media=i.createElement("audio");break;case"youtube":case"vimeo":case"soundcloud":je.elements.media=i.createElement("div"),je.embedId=e.sources[0].src}i.prependChild(je.elements.container,je.elements.media),i.is.boolean(e.autoplay)&&(Re.autoplay=e.autoplay),i.inArray(l.html5,je.type)&&(Re.crossorigin&&je.elements.media.setAttribute("crossorigin",""),Re.autoplay&&je.elements.media.setAttribute("autoplay",""),"poster"in e&&je.elements.media.setAttribute("poster",e.poster),Re.loop.active&&je.elements.media.setAttribute("loop",""),Re.inline&&je.elements.media.setAttribute("playsinline","")),i.toggleClass(je.elements.container,Re.classes.fullscreen.active,je.fullscreen.active),i.toggleClass(je.elements.container,Re.classes.captions.active,je.captions.enabled),D(),i.inArray(l.html5,je.type)&&y("source",e.sources),Y(),i.inArray(l.html5,je.type)&&("tracks"in e&&y("track",e.tracks),je.elements.media.load()),(i.inArray(l.html5,je.type)||i.inArray(l.embed,je.type)&&!je.supported.full)&&(qe(),Oe()),Re.title=e.title,B()}return i.is.object(e)&&"sources"in e&&e.sources.length?(i.toggleClass(je.elements.container,Re.classes.ready,!1),G(),we(),ke(),Ne(),void Le(t,!1)):void He("Invalid source format")}function Ie(e){"video"===je.type&&je.elements.media.setAttribute("poster",e)}function Pe(){function n(){var e=K(),t=je.elements.buttons[e?"play":"pause"],n=je.elements.buttons[e?"pause":"play"];if(n){var s=i.hasClass(t,Re.classes.tabFocus);setTimeout(function(){i.is.htmlElement(n)&&n.focus(),s&&(i.toggleClass(t,Re.classes.tabFocus,!1),i.toggleClass(n,Re.classes.tabFocus,!0))},100)}}function s(e){return e.keyCode?e.keyCode:e.which}function a(e){i.toggleClass(d("."+Re.classes.tabFocus),Re.classes.tabFocus,!1),je.elements.container.contains(e)&&i.toggleClass(e,Re.classes.tabFocus,!0)}function l(e){function t(){var e=je.elements.media.duration;i.is.number(e)&&ae(e/10*(a-48))}var a=s(e),l="keydown"===e.type,r=l&&a===c;if(i.is.number(a))if(l){var u=[48,49,50,51,52,53,54,56,57,32,75,38,40,77,39,37,70,67,73,76,79],d=[38,40];if(i.inArray(d,a)){var p=i.getFocusElement();if(i.is.htmlElement(p)&&"radio"===i.getFocusElement().type)return}switch(i.inArray(u,a)&&(e.preventDefault(),e.stopPropagation()),a){case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:r||t();break;case 32:case 75:r||n();break;case 38:ye();break;case 40:ge();break;case 77:r||me();break;case 39:se();break;case 37:ne();break;case 70:ue();break;case 67:r||M();break;case 73:Z("start");break;case 76:Z();break;case 79:Z("end")}!o.fullscreen&&je.fullscreen.active&&27===a&&ue(),c=a}else c=null}var u=je.browser.isIE?"change":"input";if(Re.keyboardShortcuts.focused){var c=null;Re.keyboardShortcuts.global&&i.on(e,"keydown keyup",function(e){var t=s(e),n=i.getFocusElement(),a=[48,49,50,51,52,53,54,56,57,75,77,70,67,73,76,79];!i.inArray(a,t)||i.is.htmlElement(n)&&i.matches(n,Re.selectors.editable)||l(e)},!1),i.on(je.elements.container,"keydown keyup",l,!1)}i.on(e,"keyup",function(e){var t=s(e),n=i.getFocusElement();9===t&&a(n)}),i.on(t.body,"click",function(){i.toggleClass(p("."+Re.classes.tabFocus),Re.classes.tabFocus,!1)});for(var m in je.elements.buttons){var f=je.elements.buttons[m];i.on(f,"blur",function(){i.toggleClass(f,"tab-focus",!1)})}var y=function(e,t,n){i.is.function(t)&&t.call(this,e),i.is.function(n)&&n.call(this,e)};i.proxy(je.elements.buttons.play,"click",Re.listeners.play,n),i.proxy(je.elements.buttons.playLarge,"click",Re.listeners.play,n),i.proxy(je.elements.buttons.pause,"click",Re.listeners.pause,n),i.proxy(je.elements.buttons.restart,"click",Re.listeners.restart,ae),i.proxy(je.elements.buttons.rewind,"click",Re.listeners.rewind,ne),i.proxy(je.elements.buttons.forward,"click",Re.listeners.forward,se),i.proxy(je.elements.buttons.mute,"click",Re.listeners.mute,me),i.proxy(je.elements.buttons.captions,"click",Re.listeners.captions,M),i.proxy(je.elements.buttons.fullscreen,"click",Re.listeners.fullscreen,ue),i.proxy(je.elements.buttons.pip,"click",Re.listeners.pip,function(e){o.pip&&je.elements.media.webkitSetPresentationMode("picture-in-picture"===je.elements.media.webkitPresentationMode?"inline":"picture-in-picture")}),i.proxy(je.elements.buttons.airplay,"click",Re.listeners.airplay,function(e){o.airplay&&je.elements.media.webkitShowPlaybackTargetPicker()}),i.on(je.elements.buttons.settings,"click",ce),i.on(t.documentElement,"click",ce),i.on(je.elements.settings.form,"click",pe),i.on(je.elements.settings.form,"click",function(e){i.matches(e.target,Re.selectors.inputs.language)?y.call(this,e,Re.listeners.language,L):i.matches(e.target,Re.selectors.inputs.quality)?y.call(this,e,Re.listeners.quality,function(){He("Set quality")}):i.matches(e.target,Re.selectors.inputs.speed)?y.call(this,e,Re.listeners.speed,ee):i.matches(e.target,Re.selectors.buttons.loop)&&y.call(this,e,Re.listeners.loop,function(){var t=e.target.getAttribute("data-loop__value")||e.target.getAttribute("data-loop__type");i.inArray(["start","end","all","none"],t)&&Z(t)})}),i.proxy(je.elements.inputs.seek,u,Re.listeners.seek,ae),i.proxy(je.elements.inputs.volume,u,Re.listeners.volume,fe),i.on(je.elements.progress,"mouseenter mouseleave mousemove",Te),Re.hideControls&&(i.on(je.elements.container,"mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen",Se),i.on(je.elements.controls,"mouseenter mouseleave",function(e){je.elements.controls.hover="mouseenter"===e.type}),i.on(je.elements.controls,"mousedown mouseup touchstart touchend touchcancel",function(e){je.elements.controls.pressed=i.inArray(["mousedown","touchstart"],e.type)}),i.on(je.elements.controls,"focus blur",Se,!0,!0)),i.proxy(je.elements.inputs.volume,"wheel",Re.listeners.volume,function(e){var t=e.webkitDirectionInvertedFromDevice,n=.2,s=0;(e.deltaY<0||e.deltaX>0)&&(t?(ge(n),s=-1):(ye(n),s=1)),(e.deltaY>0||e.deltaX<0)&&(t?(ye(n),s=1):(ge(n),s=-1)),(1===s&&je.elements.media.volume<1||s===-1&&je.elements.media.volume>0)&&e.preventDefault()},!1),o.fullscreen&&i.on(t,r.eventType,ue)}function _e(){if(i.on(je.elements.media,"timeupdate seeking",Ae),i.on(je.elements.media,"durationchange loadedmetadata",Ee),i.on(je.elements.media,"ended",function(){"video"===je.type&&Re.showPosterOnEnd&&("video"===je.type&&q(),ae(),je.elements.media.load())}),i.on(je.elements.media,"progress playing",he),i.on(je.elements.media,"volumechange",be),i.on(je.elements.media,"play pause ended",ie),i.on(je.elements.media,"waiting canplay seeked",ve),Re.clickToPlay&&"audio"!==je.type){var e=p("."+Re.classes.videoWrapper);if(!e)return;e.style.cursor="pointer",i.on(e,"click",function(){Re.hideControls&&o.touch&&!je.elements.media.paused||(je.elements.media.paused?$():je.elements.media.ended?(ae(),$()):G())})}Re.disableContextMenu&&i.on(je.elements.media,"contextmenu",function(e){e.preventDefault()},!1),i.on(je.elements.media,Re.events.concat(["keyup","keydown"]).join(" "),function(e){c(je.elements.container,e.type,!0)})}function Ne(){if(i.inArray(l.html5,je.type)){for(var e=je.elements.media.querySelectorAll("source"),t=0;t<e.length;t++)i.removeElement(e[t]);je.elements.media.setAttribute("src","https://cdn.selz.com/plyr/blank.mp4"),je.elements.media.load(),Be("Cancelled network requests")}}function Le(n,s){function a(){i.is.boolean(s)||(s=!0),i.is.function(n)&&n.call(je.original),s&&(je.elements.container.parentNode.replaceChild(je.original,je.elements.container),t.body.style.overflow="",c(je.original,"destroyed",!0))}switch(je.type){case"youtube":e.clearInterval(Ve.buffering),e.clearInterval(Ve.playing),je.embed.destroy(),a();break;case"vimeo":je.embed.unload().then(a),e.setTimeout(a,200);break;case"video":case"audio":R(!0),a()}}function qe(){return je.supported.full?(i.is.htmlElement(je.elements.controls)||(j(),Pe()),void(i.is.htmlElement(je.elements.controls)&&(_e(),R(),I(),P(),fe(),be(),ee(),Z(),Ae(),ie()))):(He("Basic support only",je.type),m("controls"),m("buttons.play"),void R(!0))}function Oe(){c(je.elements.container,"ready",!0),Re.autoplay&&$()}function Me(e){if(!i.is.htmlElement(e))return We("Setup failed. No suitable element passed."),!1;if(!Re.enabled)return!1;if(!i.checkSupport().basic)return!1;if(e.plyr)return!1;var t=e.tagName.toLowerCase();switch(t){case"div":if(je.type=e.getAttribute("data-type"),je.embedId=e.getAttribute("data-video-id"),i.is.empty(je.type)||i.is.empty(je.embedId))return!1;e.removeAttribute("data-type"),e.removeAttribute("data-video-id");break;case"iframe":break;case"video":case"audio":je.type=t,Re.crossorigin=null!==e.getAttribute("crossorigin"),Re.autoplay=Re.autoplay||null!==e.getAttribute("autoplay"),Re.inline=null!==e.getAttribute("playsinline"),Re.loop.active=Re.loop||null!==e.getAttribute("loop");break;default:return!1}if(je.browser=i.getBrowser(),H(),je.supported=i.checkSupport(je.type,Re.inline),!je.supported.basic)return!1;if(je.elements.container=i.wrap(e,i.createElement("div")),je.original=e.cloneNode(!0),je.elements.container.setAttribute("tabindex",0),D(),Be(je.browser.name+" "+je.browser.version),Y(),Re.debug){var n=Re.events.concat(["setup","statechange","enterfullscreen","exitfullscreen","captionsenabled","captionsdisabled"]);i.on(je.elements.container,n.join(" "),function(e){Be(["event:",e.type].join(" ").trim())})}return(i.inArray(l.html5,je.type)||i.inArray(l.embed,je.type)&&!je.supported.full)&&(qe(),Oe(),B()),!0}var je=this,Ve={},De={};i.is.string(n)&&(n=t.querySelectorAll(n)),(e.jQuery&&n instanceof jQuery||i.is.nodeList(n)||i.is.array(n))&&(n=n[0]);var Re=i.extend({},a,u,function(){try{return JSON.parse(n.getAttribute("data-plyr"))}catch(e){}}());je.elements={container:null,buttons:{},display:{},progress:{},inputs:{},settings:{menu:null,panes:{},tabs:{}},media:n,captions:null},je.captions={enabled:!1,captions:[],tracks:[],currentTrack:null},je.fullscreen={active:!1};var Be=function(){},He=function(){},We=function(){};return Re.debug&&"console"in e&&(Be=e.console.log,He=e.console.warn,We=e.console.error),Be("Config",Re),Be("Support",o),De={getOriginal:function(){return je.original},getContainer:function(){return je.elements.container},getEmbed:function(){return je.embed},getMedia:function(){return je.elements.media},getType:function(){return je.type},getDuration:le,getCurrentTime:function(){return je.elements.media.currentTime},getVolume:function(){return je.elements.media.volume},isMuted:function(){return je.elements.media.muted},isReady:function(){return i.hasClass(je.elements.container,Re.classes.ready)},isLoading:function(){return i.hasClass(je.elements.container,Re.classes.loading)},isPaused:function(){return je.elements.media.paused},isLooping:function(){return Re.loop.active},on:function(e,t){return i.on(je.elements.container,e,t),this},play:$,pause:G,loop:Z,stop:function(){G(),ae()},restart:ae,rewind:ne,forward:se,seek:ae,source:xe,poster:Ie,setVolume:fe,setSpeed:ee,togglePlay:K,toggleMute:me,toggleCaptions:M,toggleFullscreen:ue,toggleControls:Se,setLanguage:L,isFullscreen:je.fullscreen.active,support:function(e){return o.mime(je,e)},destroy:Le},Me(je.elements.media)?De:null}var s={x:0,y:0},a={enabled:!0,title:"",debug:!1,autoplay:!1,seekTime:10,volume:10,duration:null,displayDuration:!0,loadSprite:!0,iconPrefix:"plyr",iconUrl:"https://cdn.plyr.io/2.0.10/plyr.svg",clickToPlay:!0,hideControls:!0,showPosterOnEnd:!1,disableContextMenu:!0,quality:{default:"auto",selected:"auto"},loop:{active:!1,start:0,end:null,indicator:{start:0,end:0}},speed:{selected:1,options:[.25,.5,.75,1,1.25,1.5,2]},keyboardShortcuts:{focused:!0,global:!1},tooltips:{controls:!1,seek:!0},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"}},classes:{setup:"plyr--setup",ready:"plyr--ready",videoWrapper:"plyr__video-wrapper",embedWrapper:"plyr__video-embed",control:"plyr__control",type:"plyr--{0}",stopped:"plyr--stopped",playing:"plyr--playing",muted:"plyr--muted",loading:"plyr--loading",hover:"plyr--hover",tooltip:"plyr__tooltip",hidden:"plyr__sr-only",hideControls:"plyr--hide-controls",isIos:"plyr--is-ios",isTouch:"plyr--is-touch",menu:{value:"plyr__menu__value",badge:"plyr__badge"},captions:{enabled:"plyr--captions-enabled",active:"plyr--captions-active"},fullscreen:{enabled:"plyr--fullscreen-enabled",active:"plyr--fullscreen-active"},pip:{enabled:"plyr--pip-enabled",active:"plyr--pip-active"},airplay:{enabled:"plyr--airplay-enabled",active:"plyr--airplay-active"},tabFocus:"tab-focus"},captions:{active:!1,language:e.navigator.language.split("-")[0]},fullscreen:{enabled:!0,fallback:!0,allowAudio:!1},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"},urls:{vimeo:{api:"https://player.vimeo.com/api/player.js"},youtube:{api:"https://www.youtube.com/iframe_api"},soundcloud:{api:"https://w.soundcloud.com/player/api.js"}},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"],logPrefix:""},l={embed:["youtube","vimeo","soundcloud"],html5:["video","audio"]},i={is:{object:function(e){return null!==e&&"object"==typeof e&&e.constructor===Object},array:function(e){return null!==e&&Array.isArray(e)},number:function(e){return null!==e&&("number"==typeof e&&!isNaN(e-0)||"object"==typeof e&&e.constructor===Number)},string:function(e){return null!==e&&("string"==typeof e||"object"==typeof e&&e.constructor===String)},boolean:function(e){return null!==e&&"boolean"==typeof e},nodeList:function(e){return null!==e&&e instanceof NodeList},htmlElement:function(e){return null!==e&&e instanceof HTMLElement},function:function(e){return null!==e&&"function"==typeof e},event:function(e){return null!==e&&e instanceof Event},cue:function(t){return null!==t&&(t instanceof e.TextTrackCue||t instanceof e.VTTCue)},track:function(t){return null!==t&&t instanceof e.TextTrack},undefined:function(e){return null!==e&&"undefined"==typeof e},empty:function(e){return null===e||this.undefined(e)||(this.string(e)||this.array(e)||this.nodeList(e))&&0===e.length||this.object(e)&&0===Object.keys(e).length}},getBrowser:function(){var e,t,n,s=navigator.userAgent,a=navigator.appName,l=""+parseFloat(navigator.appVersion),i=parseInt(navigator.appVersion,10),r=!1,o=!1,u=!1,c=!1;return navigator.appVersion.indexOf("Windows NT")!==-1&&navigator.appVersion.indexOf("rv:11")!==-1?(r=!0,a="IE",l="11"):(t=s.indexOf("MSIE"))!==-1?(r=!0,a="IE",l=s.substring(t+5)):(t=s.indexOf("Chrome"))!==-1?(u=!0,a="Chrome",l=s.substring(t+7)):(t=s.indexOf("Safari"))!==-1?(c=!0,a="Safari",l=s.substring(t+7),(t=s.indexOf("Version"))!==-1&&(l=s.substring(t+8))):(t=s.indexOf("Firefox"))!==-1?(o=!0,a="Firefox",l=s.substring(t+8)):(e=s.lastIndexOf(" ")+1)<(t=s.lastIndexOf("/"))&&(a=s.substring(e,t),l=s.substring(t+1),a.toLowerCase()===a.toUpperCase()&&(a=navigator.appName)),(n=l.indexOf(";"))!==-1&&(l=l.substring(0,n)),(n=l.indexOf(" "))!==-1&&(l=l.substring(0,n)),i=parseInt(""+l,10),isNaN(i)&&(l=""+parseFloat(navigator.appVersion),i=parseInt(navigator.appVersion,10)),{name:a,version:i,isIE:r,isOldIE:r&&i<=9,isFirefox:o,isChrome:u,isSafari:c,isIPhone:/(iPhone|iPod)/gi.test(navigator.platform),isIos:/(iPad|iPhone|iPod)/gi.test(navigator.platform)}},checkSupport:function(e,t){var n=!1,s=!1,a=i.getBrowser(),l=a.isIPhone&&t&&o.inline;switch(e){case"video":n=o.video,s=n&&!a.isOldIE&&(!a.isIPhone||l);break;case"audio":n=o.audio,s=n&&!a.isOldIE;break;case"youtube":n=o.video,s=n&&!a.isOldIE&&(!a.isIPhone||l);break;case"vimeo":case"soundcloud":n=!0,s=!a.isOldIE&&!a.isIos;break;default:n=o.audio&&o.video,s=n&&!a.isOldIE}return{basic:n,full:s}},injectScript:function(e){if(!t.querySelectorAll('script[src="'+e+'"]').length){var n=t.createElement("script");n.src=e;var s=t.getElementsByTagName("script")[0];s.parentNode.insertBefore(n,s)}},inFrame:function(){try{return e.self!==e.top}catch(e){return!0}},inArray:function(e,t){return i.is.array(e)&&e.indexOf(t)!==-1},replaceAll:function(e,t,n){return e.replace(new RegExp(t.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g,"\\$1"),"g"),n)},wrap:function(e,t){e.length||(e=[e]);for(var n=e.length-1;n>=0;n--){var s=n>0?t.cloneNode(!0):t,a=e[n],l=a.parentNode,i=a.nextSibling;return s.appendChild(a),i?l.insertBefore(s,i):l.appendChild(s),s}},removeElement:function(e){i.is.htmlElement(e)&&i.is.htmlElement(e.parentNode)&&e.parentNode.removeChild(e)},prependChild:function(e,t){e.insertBefore(t,e.firstChild)},insertAfter:function(e,t){t.parentNode.insertBefore(e,t.nextSibling)},createElement:function(e,n,s){var a=t.createElement(e);return i.is.object(n)&&i.setAttributes(a,n),i.is.string(s)&&(a.textContent=s),a},insertElement:function(e,t,n,s){var a=i.createElement(e,n,s);i.prependChild(t,a)},emptyElement:function(e){for(var t=e.childNodes.length;t--;)e.removeChild(e.lastChild)},setAttributes:function(e,t){for(var n in t)e.setAttribute(n,t[n])},getAttributesFromSelector:function(e,t){if(!i.is.string(e)||i.is.empty(e))return{};var n={};return e.split(",").forEach(function(e){e=e.trim();var s=e.charAt(0);switch(s){case".":var a=e.replace(".","");i.is.object(t)&&i.is.string(t.class)&&(t.class+=" "+a),n.class=a;break;case"#":n.id=e.replace("#","");break;case"[":e=e.replace(/[\[\]]/g,"");var l=e.split("="),r=l[0],o=l.length>1?l[1].replace(/[\"\']/g,""):"";n[r]=o}}),n},toggleClass:function(e,t,n){if(e)if(e.classList)e.classList[n?"add":"remove"](t);else{var s=(" "+e.className+" ").replace(/\s+/g," ").replace(" "+t+" ","");e.className=s+(n?" "+t:"")}},hasClass:function(e,t){return!!e&&(e.classList?e.classList.contains(t):new RegExp("(\\s|^)"+t+"(\\s|$)").test(e.className))},matches:function(e,n){var s=Element.prototype,a=s.matches||s.webkitMatchesSelector||s.mozMatchesSelector||s.msMatchesSelector||function(e){return[].indexOf.call(t.querySelectorAll(e),this)!==-1};return a.call(e,n)},getFocusElement:function(){var e=t.activeElement;return e=e&&e!==t.body?t.querySelector(":focus"):null},proxy:function(e,t,n,s,a,l){i.on(e,t,function(t){n&&n.apply(e,[t]),s.apply(e,[t])},a,l)},toggleListener:function(e,t,n,s,a,l){if(t=t.split(" "),i.is.boolean(l)||(l=!1),i.is.boolean(a)||(a=!0),e instanceof NodeList){var r=1===arguments.length?[arguments[0]]:Array.apply(null,arguments);return r.shift(),void[].forEach.call(e,function(e){e instanceof Node&&i.toggleListener.apply(null,[e].concat(r))})}var u=l;o.passiveListeners&&(u={passive:a,capture:l}),t.forEach(function(t){e[s?"addEventListener":"removeEventListener"](t,n,u)})},on:function(e,t,n,s,a){i.is.undefined(e)||i.toggleListener(e,t,n,!0,s,a)},off:function(e,t,n,s,a){i.is.undefined(e)||i.toggleListener(e,t,n,!1,s,a)},event:function(n,s,a,l){if(n&&s){i.is.boolean(a)||(a=!1);var r;i.is.function(e.CustomEvent)?r=e.CustomEvent:(r=function(e,n){n=n||{bubbles:!1,cancelable:!1,detail:void 0};var s=t.createEvent("CustomEvent");return s.initCustomEvent(e,n.bubbles,n.cancelable,n.detail),s},r.prototype=e.Event.prototype);var o=new r(s,{bubbles:a,detail:l});n.dispatchEvent(o)}},toggleState:function(e,t){if(e)return t=i.is.boolean(t)?t:!e.getAttribute("aria-pressed"),e.setAttribute("aria-pressed",t),t},getPercentage:function(e,t){return 0===e||0===t||isNaN(e)||isNaN(t)?0:(e/t*100).toFixed(2)},extend:function(){var e=arguments;if(e.length){if(1===e.length)return e[0];var t=Array.prototype.shift.call(e);i.is.object(t)||(t={});for(var n=e.length,s=0;s<n;s++){var a=e[s];i.is.object(a)||(a={});for(var l in a)a[l]&&a[l].constructor&&a[l].constructor===Object?(t[l]=t[l]||{},i.extend(t[l],a[l])):t[l]=a[l]}return t}},parseYouTubeId:function(e){var t=/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;return e.match(t)?RegExp.$2:e},stripHTML:function(e){var n=t.createDocumentFragment(),s=t.createElement("div");return n.appendChild(s),s.innerHTML=e,n.firstChild.innerText},loadSprite:function(n,s){function a(e,n){e.innerHTML=n,t.body.insertBefore(e,t.body.childNodes[0])}if("string"==typeof n){var l="cache-",i="string"==typeof s,r=!1;if(!i||!t.querySelectorAll("#"+s).length){var u=t.createElement("div");if(u.setAttribute("hidden",""),i&&u.setAttribute("id",s),o.storage){var c=e.localStorage.getItem(l+s);if(r=null!==c){var d=JSON.parse(c);a(u,d.content)}}var p=new XMLHttpRequest;if(!("withCredentials"in p))return;p.open("GET",n,!0),p.onload=function(){o.storage&&e.localStorage.setItem(l+s,JSON.stringify({content:p.responseText})),a(u,p.responseText)},p.send()}}},transitionEnd:function(){var e=t.createElement("span"),n={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var s in n)if(void 0!==e.style[s])return n[s];return!1}()},r=function(){var e=function(){var e=!1;return i.is.function(t.cancelFullScreen)?e="":["webkit","o","moz","ms","khtml"].some(function(n){return i.is.function(t[n+"CancelFullScreen"])?(e=n,!0):i.is.function(t.msExitFullscreen)&&t.msFullscreenEnabled?(e="ms",!0):void 0}),e}();return{prefix:e,eventType:"ms"===e?"MSFullscreenChange":e+"fullscreenchange",isFullScreen:function(n){if(!o.fullscreen)return!1;switch(i.is.undefined(n)&&(n=t.body),this.prefix){case"":return t.fullscreenElement===n;case"moz":return t.mozFullScreenElement===n;default:return t[e+"FullscreenElement"]===n}},requestFullScreen:function(n){return!!o.fullscreen&&(i.is.htmlElement(n)||(n=t.body),""===e?n.requestFullScreen():n[e+("ms"===e?"RequestFullscreen":"RequestFullScreen")]())},cancelFullScreen:function(){return!!o.fullscreen&&(""===e?t.cancelFullScreen():t[e+("ms"===e?"ExitFullscreen":"CancelFullScreen")]())},element:function(){return o.fullscreen?""===e?t.fullscreenElement:t[e+"FullscreenElement"]:null}}}(),o={audio:"canPlayType"in t.createElement("audio"),video:"canPlayType"in t.createElement("video"),fullscreen:r.prefix!==!1,storage:function(){if(!("localStorage"in e))return!1;var t="___test";try{return e.localStorage.setItem(t,t),e.localStorage.removeItem(t),!0}catch(e){return!1}return!1}(),pip:function(){var e=i.getBrowser();return!e.isIPhone&&i.is.function(i.createElement("video").webkitSetPresentationMode)}(),airplay:i.is.function(e.WebKitPlaybackTargetAvailabilityEvent),inline:"playsInline"in t.createElement("video"),mime:function(e,t){var n=e.media;try{if(!i.is.function(n.canPlayType))return!1;if("video"===e.type)switch(t){case"video/webm":return n.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/,"");case"video/mp4":return n.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/,"");case"video/ogg":return n.canPlayType('video/ogg; codecs="theora"').replace(/no/,"")}else if("audio"===e.type)switch(t){case"audio/mpeg":return n.canPlayType("audio/mpeg;").replace(/no/,"");case"audio/ogg":return n.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/,"");case"audio/wav":return n.canPlayType('audio/wav; codecs="1"').replace(/no/,"")}}catch(e){return!1}return!1},textTracks:"textTracks"in t.createElement("video"),passiveListeners:function(){var t=!1;try{var n=Object.defineProperty({},"passive",{get:function(){t=!0}});e.addEventListener("test",null,n)}catch(e){}return t}(),touch:"ontouchstart"in t.documentElement,transitions:!(i.transitionEnd===!1||"matchMedia"in e&&e.matchMedia("(prefers-reduced-motion)").matches)};return n}); \ No newline at end of file
+(function(e,t,n){"use strict";"object"==typeof exports?module.exports=n(require):"function"==typeof define&&define.amd?define(n):t[e]=n()}).call(this,"Plyr",this,function(e){"use strict";function t(e,t){function n(e,t,n,i){a.event(e,t,n,a.extend({},i,{plyr:pe}))}function l(e){return pe.elements.container.querySelectorAll(e)}function c(e){return l(e)[0]}function u(e){a.is.string(e)?(a.removeElement(pe.elements[e]),pe.elements[e]=null):a.removeElement(e)}function d(){function e(e){9===e.which&&pe.fullscreen.active&&(e.target!==i||e.shiftKey?e.target===n&&e.shiftKey&&(e.preventDefault(),i.focus()):(e.preventDefault(),n.focus()))}var t=l("input:not([disabled]), button:not([disabled])"),n=t[0],i=t[t.length-1];a.on(pe.elements.container,"keydown",e,!1)}function p(e,t){a.is.string(t)?a.insertElement(e,pe.media,{src:t}):a.is.array(t)&&t.forEach(function(t){a.insertElement(e,pe.media,t)})}function m(){return{url:pe.config.iconUrl,absolute:0===pe.config.iconUrl.indexOf("http")||pe.browser.isIE}}function f(e,t){var n="http://www.w3.org/2000/svg",i=m(),o=(i.absolute?"":i.url)+"#"+pe.config.iconPrefix,s=document.createElementNS(n,"svg");a.setAttributes(s,a.extend(t,{role:"presentation"}));var r=document.createElementNS(n,"use");return r.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",o+"-"+e),s.appendChild(r),s}function g(e){var t=pe.config.i18n[e];switch(e){case"pip":t="PIP";break;case"airplay":t="AirPlay"}return a.createElement("span",{class:pe.config.classes.hidden},t)}function y(e){var t=a.createElement("span",{class:pe.config.classes.menu.value});return t.appendChild(a.createElement("span",{class:pe.config.classes.menu.badge},e)),t}function b(e,t){var n,i,o,s=a.createElement("button");switch(a.is.object(t)||(t={}),"class"in t?t.class.indexOf(pe.config.classes.control)===-1&&(t.class+=" "+pe.config.classes.control):t.class=pe.config.classes.control,e){case"mute":o="toggleMute",n="volume",i="muted";break;case"captions":o="toggleCaptions",n="captions-off",i="captions-on";break;case"fullscreen":o="toggleFullscreen",n="enter-fullscreen",i="exit-fullscreen";break;case"play-large":t.class="plyr__play-large",e="play",o="play",n="play";break;default:o=e,n=e}return a.extend(t,a.getAttributesFromSelector(pe.config.selectors.buttons[e],t)),a.is.string(i)&&s.appendChild(f(i,{class:"icon--"+i})),s.appendChild(f(n)),s.appendChild(g(o)),a.setAttributes(s,t),pe.elements.buttons[e]=s,s}function v(e,t){var n=a.createElement("label",{for:t.id,class:pe.config.classes.hidden},pe.config.i18n[e]),i=a.createElement("input",a.extend(a.getAttributesFromSelector(pe.config.selectors.inputs[e]),{type:"range",min:0,max:100,step:.1,value:0,autocomplete:"off"},t));return pe.elements.inputs[e]=i,{label:n,input:i}}function h(e,t){var n=a.createElement("progress",a.extend(a.getAttributesFromSelector(pe.config.selectors.display[e]),{min:0,max:100,value:0},t));if("volume"!==e){n.appendChild(a.createElement("span",null,"0"));var i="";switch(e){case"played":i=pe.config.i18n.played;break;case"buffer":i=pe.config.i18n.buffered}n.textContent="% "+i.toLowerCase()}return pe.elements.display[e]=n,n}function w(e){var t=a.createElement("span",{class:"plyr__time"});return t.appendChild(a.createElement("span",{class:pe.config.classes.hidden},pe.config.i18n[e])),t.appendChild(a.createElement("span",a.getAttributesFromSelector(pe.config.selectors.display[e]),"00:00")),pe.elements.display[e]=t,t}function k(e){var t=a.createElement("div",a.getAttributesFromSelector(pe.config.selectors.controls.wrapper));if(a.inArray(pe.config.controls,"restart")&&t.appendChild(b("restart")),a.inArray(pe.config.controls,"rewind")&&t.appendChild(b("rewind")),a.inArray(pe.config.controls,"play")&&(t.appendChild(b("play")),t.appendChild(b("pause"))),a.inArray(pe.config.controls,"fast-forward")&&t.appendChild(b("fast-forward")),a.inArray(pe.config.controls,"progress")){var n=a.createElement("span",a.getAttributesFromSelector(pe.config.selectors.progress)),i=v("seek",{id:"plyr-seek-"+e.id});if(n.appendChild(i.label),n.appendChild(i.input),n.appendChild(h("played")),n.appendChild(h("buffer")),pe.config.tooltips.seek){var o=a.createElement("span",{role:"tooltip",class:pe.config.classes.tooltip},"00:00");n.appendChild(o),pe.elements.display.seekTooltip=o}pe.elements.progress=n,t.appendChild(pe.elements.progress)}if(a.inArray(pe.config.controls,"current-time")&&t.appendChild(w("currentTime")),a.inArray(pe.config.controls,"duration")&&t.appendChild(w("duration")),a.inArray(pe.config.controls,"mute")&&t.appendChild(b("mute")),a.inArray(pe.config.controls,"volume")){var s=a.createElement("span",{class:"plyr__volume"}),l={max:10,value:pe.config.volume},c=v("volume",a.extend(l,{id:"plyr-volume-"+e.id}));s.appendChild(c.label),s.appendChild(c.input);var u=h("volume",l);s.appendChild(u),t.appendChild(s)}if(a.inArray(pe.config.controls,"captions")&&t.appendChild(b("captions")),a.inArray(pe.config.controls,"settings")){var d=a.createElement("div",{class:"plyr__menu"});d.appendChild(b("settings",{id:"plyr-settings-toggle-"+e.id,"aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id,"aria-expanded":!1}));var p=a.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=a.createElement("div"),f=a.createElement("div",{id:"plyr-settings-"+e.id+"-home","aria-hidden":!1,"aria-labelled-by":"plyr-settings-toggle-"+e.id,role:"tabpanel"}),g=a.createElement("ul",{role:"tablist"});pe.config.settings.forEach(function(t){var n=a.createElement("li",{role:"tab",hidden:""}),i=a.createElement("button",a.extend(a.getAttributesFromSelector(pe.config.selectors.buttons.settings),{type:"button",class:pe.config.classes.control+" "+pe.config.classes.control+"--forward",id:"plyr-settings-"+e.id+"-"+t+"-tab","aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id+"-"+t,"aria-expanded":!1}),pe.config.i18n[t]),o=a.createElement("span",{class:pe.config.classes.menu.value});o.innerHTML=e[t],i.appendChild(o),n.appendChild(i),g.appendChild(n),pe.elements.settings.tabs[t]=n}),f.appendChild(g),m.appendChild(f),pe.config.settings.forEach(function(t){var n=a.createElement("div",{id:"plyr-settings-"+e.id+"-"+t,"aria-hidden":!0,"aria-labelled-by":"plyr-settings-"+e.id+"-"+t+"-tab",role:"tabpanel",tabindex:-1,hidden:""}),i=a.createElement("button",{type:"button",class:pe.config.classes.control+" "+pe.config.classes.control+"--back","aria-haspopup":!0,"aria-controls":"plyr-settings-"+e.id+"-home","aria-expanded":!1},pe.config.i18n[t]);n.appendChild(i);var o=a.createElement("ul");n.appendChild(o),m.appendChild(n),pe.elements.settings.panes[t]=n}),p.appendChild(m),d.appendChild(p),t.appendChild(d),pe.elements.settings.form=p,pe.elements.settings.menu=d}return a.inArray(pe.config.controls,"pip")&&r.pip&&t.appendChild(b("pip")),a.inArray(pe.config.controls,"airplay")&&r.airplay&&t.appendChild(b("airplay")),a.inArray(pe.config.controls,"fullscreen")&&t.appendChild(b("fullscreen")),a.inArray(pe.config.controls,"play-large")&&(pe.elements.buttons.playLarge=b("play-large"),pe.elements.container.appendChild(pe.elements.buttons.playLarge)),pe.elements.controls=t,E(),S(),t}function C(e,t){function n(e){var t="";switch(e){case"hd2160":t="4K";break;case"hd1440":t="WQHD";break;case"hd1080":t="HD";break;case"hd720":t="HD"}return t.length?y(t):null}function i(e){switch(e){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";default:return"Auto"}}var o=pe.elements.settings.panes.quality.querySelector("ul");pe.elements.settings.tabs.quality.removeAttribute("hidden"),pe.elements.settings.panes.quality.removeAttribute("hidden"),a.emptyElement(o),a.is.array(e)&&!a.is.empty(e)&&e.filter(function(e){return!a.inArray(["tiny","small"],e)}).forEach(function(e){var t=a.createElement("li"),s=a.createElement("label",{class:pe.config.classes.control}),r=a.createElement("input",a.extend(a.getAttributesFromSelector(pe.config.selectors.inputs.quality),{type:"radio",name:"plyr-quality",value:e}));e===pe.config.quality.selected&&(r.checked=!0),s.appendChild(r),s.appendChild(document.createTextNode(i(e)));var l=n(e);a.is.htmlElement(l)&&s.appendChild(l),t.appendChild(s),o.appendChild(t)})}function E(){var e=["start","end","all","reset"],t=pe.elements.settings.panes.loop.querySelector("ul");pe.elements.settings.tabs.loop.removeAttribute("hidden"),pe.elements.settings.panes.loop.removeAttribute("hidden"),a.emptyElement(t),e.forEach(function(e){var n=a.createElement("li"),i=a.createElement("button",a.extend(a.getAttributesFromSelector(pe.config.selectors.buttons.loop),{type:"button",class:pe.config.classes.control,"data-plyr-loop-action":e}),pe.config.i18n[e]);if(a.inArray(["start","end"],e)){var o=y("00:00");i.appendChild(o)}n.appendChild(i),t.appendChild(n)})}function A(){var e=pe.elements.settings.panes.captions.querySelector("ul");if(pe.elements.settings.tabs.captions.removeAttribute("hidden"),pe.elements.settings.panes.captions.removeAttribute("hidden"),a.emptyElement(e),!a.is.empty(pe.captions.tracks)){var t=[].map.call(pe.captions.tracks,function(e){return{language:e.language,badge:!0,label:a.is.empty(e.label)?e.language.toUpperCase():e.label}});t.unshift({language:"off",label:pe.config.i18n.none}),t.forEach(function(t){var n=a.createElement("li"),i=a.createElement("label",{class:pe.config.classes.control}),o=a.createElement("input",a.extend(a.getAttributesFromSelector(pe.config.selectors.inputs.language),{type:"radio",name:"plyr-language",value:t.language}));t.language.toLowerCase()===pe.config.captions.language.toLowerCase()&&(o.checked=!0),i.appendChild(o),i.appendChild(document.createTextNode(t.label||t.language)),t.badge&&i.appendChild(y(t.language.toUpperCase())),n.appendChild(i),e.appendChild(n)})}}function S(e){var t=pe.elements.settings.panes.speed.querySelector("ul");pe.elements.settings.tabs.speed.removeAttribute("hidden"),pe.elements.settings.panes.speed.removeAttribute("hidden"),a.emptyElement(t),a.is.array(e)||(e=pe.config.speed.options),e.forEach(function(e){var n=a.createElement("li"),i=a.createElement("label",{class:pe.config.classes.control}),o=a.createElement("input",a.extend(a.getAttributesFromSelector(pe.config.selectors.inputs.speed),{type:"radio",name:"plyr-speed",value:e}));e===pe.config.speed.selected&&(o.checked=!0),i.appendChild(o),i.insertAdjacentHTML("beforeend",U(e)),n.appendChild(i),t.appendChild(n)})}function T(){if(pe.supported.full&&("audio"!==pe.type||pe.config.fullscreen.allowAudio)&&pe.config.fullscreen.enabled){var e=r.fullscreen;e||pe.config.fullscreen.fallback&&!a.inFrame()?(fe((e?"Native":"Fallback")+" fullscreen enabled"),a.toggleClass(pe.elements.container,pe.config.classes.fullscreen.enabled,!0)):fe("Fullscreen not supported and fallback disabled"),pe.elements.buttons&&pe.elements.buttons.fullscreen&&a.toggleState(pe.elements.buttons.fullscreen,!1),d()}}function x(e){if(a.inArray(["video","vimeo"],pe.type)&&("video"!==pe.type||r.textTracks)&&(a.is.htmlElement(pe.elements.captions)||(pe.elements.captions=a.createElement("div",a.getAttributesFromSelector(pe.config.selectors.captions)),a.insertAfter(pe.elements.captions,pe.elements.wrapper)),pe.captions.tracks=a.is.array(e)?e:pe.media.textTracks,a.toggleClass(pe.elements.container,pe.config.classes.captions.enabled,!a.is.empty(pe.captions.tracks)),!a.is.empty(pe.captions.tracks))){if(_(),"video"===pe.type){var t=pe.config.captions.language.toLowerCase();[].forEach.call(pe.captions.tracks,function(e){a.off(e,"cuechange",F),e.mode="hidden",e.language===t&&(pe.captions.currentTrack=e)}),a.is.track(pe.captions.currentTrack)||(ge("No language found to match "+t+" in tracks"),pe.captions.currentTrack=pe.captions.tracks[0]);var n=pe.captions.currentTrack;a.is.track(n)&&a.inArray(["captions","subtitles"],n.kind)&&(a.on(n,"cuechange",F),n.activeCues&&n.activeCues.length>0&&F(n))}A()}}function P(){return!r.textTracks||a.is.empty(pe.captions.tracks)?"No Subs":pe.captions.enabled?pe.captions.currentTrack.label:"Disabled"}function F(e){a.is.event(e)&&(e=e.target);var t=e.activeCues[0];a.is.cue(t)?I(t.getCueAsHTML()):I()}function I(e){if(a.is.htmlElement(pe.elements.captions)){var t=a.createElement("span");a.emptyElement(pe.elements.captions),a.is.undefined(e)&&(e=""),a.is.string(e)?t.textContent=e.trim():t.appendChild(e),pe.elements.captions.appendChild(t)}else ge("No captions element to render to")}function _(){if(pe.elements.buttons.captions){var e=pe.storage.captions;a.is.boolean(e)?pe.config.captions.active=e:e=pe.config.captions.active,e&&(a.toggleClass(pe.elements.container,pe.config.classes.captions.active,!0),a.toggleState(pe.elements.buttons.captions,!0))}}function N(){if(pe.config.loadSprite){var e=m();e.absolute?(fe("AJAX loading absolute SVG sprite"+(pe.browser.isIE?" (due to IE)":"")),a.loadSprite(e.url,"sprite-plyr")):fe("Sprite will be used as external resource directly")}pe.id=Math.floor(1e4*Math.random());var t=null;t=a.is.string(pe.config.controls)?pe.config.controls:a.is.function(pe.config.controls)?pe.config.controls({id:pe.id,seektime:pe.config.seekTime}):k({id:pe.id,seektime:pe.config.seekTime,speed:U(),quality:"HD",captions:P(),loop:"None"});var n;if(a.is.string(pe.config.selectors.controls.container)&&(n=document.querySelector(pe.config.selectors.controls.container)),a.is.htmlElement(n)||(n=pe.elements.container),a.is.htmlElement(t)?n.appendChild(t):n.insertAdjacentHTML("beforeend",t),a.is.htmlElement(pe.elements.controls)&&L(),pe.config.tooltips.controls)for(var i=l([pe.config.selectors.controls.wrapper," ",pe.config.selectors.labels," .",pe.config.classes.hidden].join("")),o=i.length-1;o>=0;o--){var s=i[o];a.toggleClass(s,pe.config.classes.hidden,!1),a.toggleClass(s,pe.config.classes.tooltip,!0)}}function L(){try{return pe.elements.controls=c(pe.config.selectors.controls.wrapper),pe.elements.buttons={play:l(pe.config.selectors.buttons.play),pause:c(pe.config.selectors.buttons.pause),restart:c(pe.config.selectors.buttons.restart),rewind:c(pe.config.selectors.buttons.rewind),forward:c(pe.config.selectors.buttons.forward),mute:c(pe.config.selectors.buttons.mute),pip:c(pe.config.selectors.buttons.pip),airplay:c(pe.config.selectors.buttons.airplay),settings:c(pe.config.selectors.buttons.settings),captions:c(pe.config.selectors.buttons.captions),fullscreen:c(pe.config.selectors.buttons.fullscreen)},pe.elements.progress=c(pe.config.selectors.progress),pe.elements.inputs={seek:c(pe.config.selectors.inputs.seek),volume:c(pe.config.selectors.inputs.volume)},pe.elements.display={buffer:c(pe.config.selectors.display.buffer),played:c(pe.config.selectors.display.played),volume:c(pe.config.selectors.display.volume),duration:c(pe.config.selectors.display.duration),currentTime:c(pe.config.selectors.display.currentTime)},a.is.htmlElement(pe.elements.progress)&&(pe.elements.display.seekTooltip=pe.elements.progress.querySelector("."+pe.config.classes.tooltip)),!0}catch(e){return ge("It looks like there is a problem with your custom controls HTML",e),M(!0),!1}}function q(){a.toggleClass(pe.elements.container,pe.config.selectors.container.replace(".",""),pe.supported.full)}function M(e){e&&a.inArray(o.html5,pe.type)?pe.media.setAttribute("controls",""):pe.media.removeAttribute("controls")}function V(e){var t=pe.config.i18n.play;if(a.is.string(pe.config.title)&&!a.is.empty(pe.config.title)&&(t+=", "+pe.config.title,pe.elements.container.setAttribute("aria-label",pe.config.title)),pe.supported.full&&(a.is.htmlElement(pe.elements.buttons.play)&&pe.elements.buttons.play.setAttribute("aria-label",t),a.is.htmlElement(pe.elements.buttons.playLarge)&&pe.elements.buttons.playLarge.setAttribute("aria-label",t)),a.is.htmlElement(e)){var n=a.is.string(pe.config.title)&&!a.is.empty(pe.config.title)?pe.config.title:"video";e.setAttribute("title",pe.config.i18n.frameTitle.replace("{title}",n))}}function O(){var e=null;pe.storage={},r.storage&&pe.config.storage.enabled&&(window.localStorage.removeItem("plyr-volume"),e=window.localStorage.getItem(pe.config.storage.key),e&&(/^\d+(\.\d+)?$/.test(e)?D({volume:parseFloat(e)}):pe.storage=JSON.parse(e)))}function D(e){r.storage&&pe.config.storage.enabled&&(a.extend(pe.storage,e),window.localStorage.setItem(pe.config.storage.key,JSON.stringify(pe.storage)))}function j(){return pe.media?(pe.supported.full&&(a.toggleClass(pe.elements.container,pe.config.classes.type.replace("{0}",pe.type),!0),a.inArray(o.embed,pe.type)&&a.toggleClass(pe.elements.container,pe.config.classes.type.replace("{0}","video"),!0),a.toggleClass(pe.elements.container,pe.config.classes.pip.enabled,r.pip&&"video"===pe.type),a.toggleClass(pe.elements.container,pe.config.classes.airplay.enabled,r.airplay&&a.inArray(o.html5,pe.type)),a.toggleClass(pe.elements.container,pe.config.classes.stopped,pe.config.autoplay),a.toggleClass(pe.elements.container,pe.config.classes.isIos,pe.browser.isIos),a.toggleClass(pe.elements.container,pe.config.classes.isTouch,r.touch)),a.inArray(["video","youtube","vimeo"],pe.type)&&(pe.elements.wrapper=a.createElement("div",{class:pe.config.classes.video}),a.wrap(pe.media,pe.elements.wrapper)),void(a.inArray(o.embed,pe.type)&&R())):void ge("No media element found!")}function R(){var e,t=pe.type+"-"+Math.floor(1e4*Math.random());switch(pe.type){case"youtube":e=a.parseYouTubeId(pe.embedId);break;default:e=pe.embedId}for(var n=l('[id^="'+pe.type+'-"]'),i=n.length-1;i>=0;i--)a.removeElement(n[i]);if(a.toggleClass(pe.elements.wrapper,pe.config.classes.embed,!0),"youtube"===pe.type)pe.media.setAttribute("id",t),a.is.object(window.YT)?B(e):(a.injectScript(pe.config.urls.youtube.api),window.onYouTubeReadyCallbacks=window.onYouTubeReadyCallbacks||[],window.onYouTubeReadyCallbacks.push(function(){B(e)}),window.onYouTubeIframeAPIReady=function(){window.onYouTubeReadyCallbacks.forEach(function(e){e()})});else if("vimeo"===pe.type)if(pe.media.setAttribute("id",t),a.is.object(window.Vimeo))Y(e);else{a.injectScript(pe.config.urls.vimeo.api);var o=window.setInterval(function(){a.is.object(window.Vimeo)&&(window.clearInterval(o),Y(e))},50)}else if("soundcloud"===pe.type){var s=a.createElement("iframe");s.loaded=!1,a.on(s,"load",function(){s.loaded=!0}),a.setAttributes(s,{src:"https://w.soundcloud.com/player/?url=https://api.soundcloud.com/tracks/"+e,id:t}),pe.media.appendChild(s),window.SC||a.injectScript(pe.config.urls.soundcloud.api);var r=window.setInterval(function(){window.SC&&s.loaded&&(window.clearInterval(r),W.call(s))},50)}}function H(){pe.supported.full&&(ce(),ue()),V(c("iframe"))}function B(e){pe.embed=new window.YT.Player(pe.media.id,{videoId:e,playerVars:{autoplay:pe.config.autoplay?1:0,controls:pe.supported.full?0:1,rel:0,showinfo:0,iv_load_policy:3,cc_load_policy:pe.config.captions.active?1:0,cc_lang_pref:"en",wmode:"transparent",modestbranding:1,disablekb:1,playsinline:1,origin:window.location.href},events:{onError:function(e){n(pe.elements.container,"error",!0,{code:e.data,embed:e.target})},onPlaybackQualityChange:function(e){var t=e.target,n=t.getPlaybackQuality();console.warn(n)},onReady:function(e){var t=e.target;pe.media.play=function(){t.playVideo(),pe.media.paused=!1},pe.media.pause=function(){t.pauseVideo(),pe.media.paused=!0},pe.media.stop=function(){t.stopVideo(),pe.media.paused=!0},pe.media.duration=t.getDuration(),pe.media.paused=!0,pe.media.currentTime=0,pe.media.muted=t.isMuted();var i=t.getPlaybackRate(),o=t.getAvailablePlaybackRates();console.warn(i,o),pe.config.title=t.getVideoData().title,pe.supported.full&&pe.media.setAttribute("tabindex",-1),H(),n(pe.media,"timeupdate"),n(pe.media,"durationchange"),window.clearInterval(me.buffering),me.buffering=window.setInterval(function(){pe.media.buffered=t.getVideoLoadedFraction(),(null===pe.media.lastBuffered||pe.media.lastBuffered<pe.media.buffered)&&n(pe.media,"progress"),pe.media.lastBuffered=pe.media.buffered,1===pe.media.buffered&&(window.clearInterval(me.buffering),n(pe.media,"canplaythrough"))},200)},onStateChange:function(e){var t=e.target;switch(window.clearInterval(me.playing),e.data){case 0:if(pe.config.loop.active){t.stopVideo(),t.playVideo();break}pe.media.paused=!0,n(pe.media,"ended");break;case 1:pe.media.paused=!1,pe.media.seeking&&n(pe.media,"seeked"),pe.media.seeking=!1,n(pe.media,"play"),n(pe.media,"playing"),me.playing=window.setInterval(function(){pe.media.currentTime=t.getCurrentTime(),n(pe.media,"timeupdate")},100),pe.media.duration!==t.getDuration()&&(pe.media.duration=t.getDuration(),n(pe.media,"durationchange"));var i=t.getAvailableQualityLevels(),o=t.getPlaybackQuality();C(i,o);break;case 2:pe.media.paused=!0,n(pe.media,"pause")}n(pe.elements.container,"statechange",!1,{code:e.data})}}})}function Y(e){pe.embed=new window.Vimeo.Player(pe.media,{id:e,loop:pe.config.loop.active,autoplay:pe.config.autoplay,byline:!1,portrait:!1,title:!1}),pe.media.play=function(){pe.embed.play(),pe.media.paused=!1},pe.media.pause=function(){pe.embed.pause(),pe.media.paused=!0},pe.media.stop=function(){pe.embed.stop(),pe.media.paused=!0},pe.media.paused=!0,pe.media.currentTime=0,H(),pe.embed.getCurrentTime().then(function(e){pe.media.currentTime=e,n(pe.media,"timeupdate")}),pe.embed.getDuration().then(function(e){pe.media.duration=e,n(pe.media,"durationchange")}),pe.embed.getTextTracks().then(function(e){x(e),pe.config.captions.active&&pe.embed.enableTextTrack(pe.config.captions.language.toLowerCase())}),pe.embed.on("cuechange",function(e){var t=null;e.cues.length&&(t=a.stripHTML(e.cues[0].text)),I(t)}),pe.embed.on("loaded",function(){a.is.htmlElement(pe.embed.element)&&pe.supported.full&&pe.embed.element.setAttribute("tabindex",-1)}),pe.embed.on("play",function(){pe.media.paused=!1,n(pe.media,"play"),n(pe.media,"playing")}),pe.embed.on("pause",function(){pe.media.paused=!0,n(pe.media,"pause")}),pe.embed.on("timeupdate",function(e){pe.media.seeking=!1,pe.media.currentTime=e.seconds,n(pe.media,"timeupdate")}),pe.embed.on("progress",function(e){pe.media.buffered=e.percent,n(pe.media,"progress"),1===parseInt(e.percent)&&n(pe.media,"canplaythrough")}),pe.embed.on("seeked",function(){pe.media.seeking=!1,n(pe.media,"seeked"),n(pe.media,"play")}),pe.embed.on("ended",function(){pe.media.paused=!0,n(pe.media,"ended")})}function W(){pe.embed=window.SC.Widget(this),pe.embed.bind(window.SC.Widget.Events.READY,function(){pe.media.play=function(){pe.embed.play(),pe.media.paused=!1},pe.media.pause=function(){pe.embed.pause(),pe.media.paused=!0},pe.media.stop=function(){pe.embed.seekTo(0),pe.embed.pause(),pe.media.paused=!0},pe.media.paused=!0,pe.media.currentTime=0,pe.embed.getDuration(function(e){pe.media.duration=e/1e3,H()}),pe.embed.getPosition(function(e){pe.media.currentTime=e,n(pe.media,"timeupdate")}),pe.embed.bind(window.SC.Widget.Events.PLAY,function(){pe.media.paused=!1,n(pe.media,"play"),n(pe.media,"playing")}),pe.embed.bind(window.SC.Widget.Events.PAUSE,function(){pe.media.paused=!0,n(pe.media,"pause")}),pe.embed.bind(window.SC.Widget.Events.PLAY_PROGRESS,function(e){pe.media.seeking=!1,pe.media.currentTime=e.currentPosition/1e3,n(pe.media,"timeupdate")}),pe.embed.bind(window.SC.Widget.Events.LOAD_PROGRESS,function(e){pe.media.buffered=e.loadProgress,n(pe.media,"progress"),1===parseInt(e.loadProgress)&&n(pe.media,"canplaythrough")}),pe.embed.bind(window.SC.Widget.Events.FINISH,function(){pe.media.paused=!0,n(pe.media,"ended")})})}function U(e){return a.is.number(e)||(e=pe.config.speed.selected),1===e?"Normal":e+"&times;"}function Q(){a.toggleClass(pe.elements.container,pe.config.classes.playing,!pe.media.paused),a.toggleClass(pe.elements.container,pe.config.classes.stopped,pe.media.paused),pe.toggleControls(pe.media.paused)}function z(e){var t=pe.elements.settings.form,n=pe.elements.buttons.settings,i=a.is.boolean(e)?e:"true"===t.getAttribute("aria-hidden");if(a.is.event(e)){var o=t.contains(e.target),s=e.target===pe.elements.buttons.settings;if(o||!o&&!s&&i)return;s&&e.stopPropagation()}t.setAttribute("aria-hidden",!i),n.setAttribute("aria-expanded",i),i?t.removeAttribute("tabindex"):t.setAttribute("tabindex",-1)}function J(e){var t,n,i=e.cloneNode(!0);return i.style.position="absolute",i.style.opacity=0,i.setAttribute("aria-hidden",!1),[].forEach.call(i.querySelectorAll("input[name]"),function(e){var t=e.getAttribute("name");e.setAttribute("name",t+"-clone")}),e.parentNode.appendChild(i),t=i.scrollWidth,n=i.scrollHeight,a.removeElement(i),{width:t,height:n}}function X(e){var t=pe.elements.settings.menu,n=e.target,i="false"===n.getAttribute("aria-expanded"),o=document.getElementById(n.getAttribute("aria-controls"));if(a.is.htmlElement(o)){var s="tabpanel"===o.getAttribute("role");if(s){var l=t.querySelector('[role="tabpanel"][aria-hidden="false"]'),c=l.parentNode;if([].forEach.call(t.querySelectorAll('[aria-controls="'+l.getAttribute("id")+'"]'),function(e){e.setAttribute("aria-expanded",!1)}),r.transitions&&!r.reducedMotion){c.style.width=l.scrollWidth+"px",c.style.height=l.scrollHeight+"px";var u=J(o),d=function(e){e.target===c&&a.inArray(["width","height"],e.propertyName)&&(c.style.width="",c.style.height="",a.off(c,a.transitionEnd,d))};a.on(c,a.transitionEnd,d),c.style.width=u.width+"px",c.style.height=u.height+"px"}l.setAttribute("aria-hidden",!0),l.setAttribute("tabindex",-1),o.setAttribute("aria-hidden",!i),n.setAttribute("aria-expanded",i),o.removeAttribute("tabindex")}}}function $(){var e=pe.media.muted?0:10*pe.media.volume;pe.supported.full&&(pe.elements.inputs.volume&&(pe.elements.inputs.volume.value=e),pe.elements.display.volume&&(pe.elements.display.volume.value=e)),D({volume:e}),a.toggleClass(pe.elements.container,pe.config.classes.muted,0===e),pe.supported.full&&pe.elements.buttons.mute&&a.toggleState(pe.elements.buttons.mute,0===e)}function G(e){pe.loading="waiting"===e.type,clearTimeout(me.loading),me.loading=setTimeout(function(){a.toggleClass(pe.elements.container,pe.config.classes.loading,pe.loading),pe.toggleControls(pe.loading)},pe.loading?250:0)}function K(e){if(pe.supported.full){var t=pe.elements.display.played,n=0,i=pe.getDuration();if(e)switch(e.type){case"timeupdate":case"seeking":if(pe.elements.controls.pressed)return;n=a.getPercentage(pe.media.currentTime,i),"timeupdate"===e.type&&pe.elements.inputs.seek&&(pe.elements.inputs.seek.value=n);break;case"playing":case"progress":t=pe.elements.display.buffer,n=function(){var e=pe.media.buffered;return e&&e.length?a.getPercentage(e.end(0),i):a.is.number(e)?100*e:0}()}a.is.number(pe.config.loop.start)&&a.is.number(pe.config.loop.end)&&pe.media.currentTime>=pe.config.loop.end&&pe.seek(pe.config.loop.start),Z(t,n)}}function Z(e,t){if(pe.supported.full){if(a.is.undefined(t)&&(t=0),a.is.undefined(e)){if(!a.is.htmlElement(pe.elements.display.buffer))return;e=pe.elements.display.buffer}if(a.is.htmlElement(e)){e.value=t;var n=e.getElementsByTagName("span")[0];a.is.htmlElement(n)&&(n.childNodes[0].nodeValue=t)}}}function ee(e,t){if(t){isNaN(e)&&(e=0);var n=parseInt(e%60),i=parseInt(e/60%60),o=parseInt(e/60/60%60),a=pe.getDuration(),s=parseInt(a/60/60%60)>0;n=("0"+n).slice(-2),i=("0"+i).slice(-2);var r=(s?o+":":"")+i+":"+n;return t.textContent=r,r}}function te(){if(pe.supported.full){var e=pe.getDuration()||0;!pe.elements.display.duration&&pe.config.displayDuration&&pe.media.paused&&ee(e,pe.elements.display.currentTime),pe.elements.display.duration&&ee(e,pe.elements.display.duration),oe()}}function ne(e){ee(pe.media.currentTime,pe.elements.display.currentTime),e&&"timeupdate"===e.type&&pe.media.seeking||K(e)}function ie(e){a.is.number(e)||(e=0);var t=pe.getDuration(),n=a.getPercentage(e,t);pe.elements.progress&&pe.elements.display.played&&(pe.elements.display.played.value=n),pe.elements.buttons&&pe.elements.inputs.seek&&(pe.elements.inputs.seek.value=n)}function oe(e){var t=pe.getDuration();if(pe.config.tooltips.seek&&a.is.htmlElement(pe.elements.inputs.seek)&&a.is.htmlElement(pe.elements.display.seekTooltip)&&0!==t){var n=pe.elements.inputs.seek.getBoundingClientRect(),i=0,o=pe.config.classes.tooltip+"--visible";if(a.is.event(e))i=100/n.width*(e.pageX-n.left);else{if(!a.hasClass(pe.elements.display.seekTooltip,o))return;i=pe.elements.display.seekTooltip.style.left.replace("%","")}i<0?i=0:i>100&&(i=100),ee(t/100*i,pe.elements.display.seekTooltip),pe.elements.display.seekTooltip.style.left=i+"%",a.is.event(e)&&a.inArray(["mouseenter","mouseleave"],e.type)&&a.toggleClass(pe.elements.display.seekTooltip,o,"mouseenter"===e.type)}}function ae(e){function t(){if(pe.embed=null,u("media"),u("captions"),u("wrapper"),pe.elements.container&&pe.elements.container.removeAttribute("class"),"type"in e&&(pe.type=e.type,"video"===pe.type)){var t=e.sources[0];"type"in t&&a.inArray(o.embed,t.type)&&(pe.type=t.type)}switch(pe.supported=a.checkSupport(pe.type,pe.config.inline),pe.type){case"video":pe.media=a.createElement("video");break;case"audio":pe.media=a.createElement("audio");break;case"youtube":case"vimeo":case"soundcloud":pe.media=a.createElement("div"),pe.embedId=e.sources[0].src}a.prependChild(pe.elements.container,pe.media),a.is.boolean(e.autoplay)&&(pe.config.autoplay=e.autoplay),a.inArray(o.html5,pe.type)&&(pe.config.crossorigin&&pe.media.setAttribute("crossorigin",""),pe.config.autoplay&&pe.media.setAttribute("autoplay",""),"poster"in e&&pe.media.setAttribute("poster",e.poster),pe.config.loop.active&&pe.media.setAttribute("loop",""),pe.config.inline&&pe.media.setAttribute("playsinline","")),a.toggleClass(pe.elements.container,pe.config.classes.fullscreen.active,pe.fullscreen.active),a.toggleClass(pe.elements.container,pe.config.classes.captions.active,pe.captions.enabled),q(),a.inArray(o.html5,pe.type)&&p("source",e.sources),j(),a.inArray(o.html5,pe.type)&&("tracks"in e&&p("track",e.tracks),pe.media.load()),(a.inArray(o.html5,pe.type)||a.inArray(o.embed,pe.type)&&!pe.supported.full)&&(ce(),ue()),pe.config.title=e.title,V()}return a.is.object(e)&&"sources"in e&&e.sources.length?(pe.ready=!1,pe.stop(),ie(),Z(),le(),void pe.destroy(t,!1)):void ge("Invalid source format")}function se(){function e(){var e=pe.togglePlay(),t=pe.elements.buttons[e?"play":"pause"],n=pe.elements.buttons[e?"pause":"play"];if(n){var i=a.hasClass(t,pe.config.classes.tabFocus);setTimeout(function(){a.is.htmlElement(n)&&n.focus(),i&&(a.toggleClass(t,pe.config.classes.tabFocus,!1),a.toggleClass(n,pe.config.classes.tabFocus,!0))},100)}}function t(e){return e.keyCode?e.keyCode:e.which}function n(e){a.toggleClass(l("."+pe.config.classes.tabFocus),pe.config.classes.tabFocus,!1),pe.elements.container.contains(e)&&a.toggleClass(e,pe.config.classes.tabFocus,!0)}function i(n){function i(){var e=pe.media.duration;a.is.number(e)&&pe.seek(e/10*(o-48))}var o=t(n),s="keydown"===n.type,l=s&&o===u;if(a.is.number(o))if(s){var c=[48,49,50,51,52,53,54,56,57,32,75,38,40,77,39,37,70,67,73,76,79],d=[38,40];if(a.inArray(d,o)){var p=a.getFocusElement();if(a.is.htmlElement(p)&&"radio"===a.getFocusElement().type)return}switch(a.inArray(c,o)&&(n.preventDefault(),n.stopPropagation()),o){case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:l||i();break;case 32:case 75:l||e();break;case 38:pe.increaseVolume();break;case 40:pe.decreaseVolume();break;case 77:l||pe.toggleMute();break;case 39:pe.forward();break;case 37:pe.rewind();break;case 70:pe.toggleFullscreen();break;case 67:l||pe.toggleCaptions();break;case 73:pe.loop("start");break;case 76:pe.loop();break;case 79:pe.loop("end")}!r.fullscreen&&pe.fullscreen.active&&27===o&&pe.toggleFullscreen(),u=o}else u=null}var o=pe.browser.isIE?"change":"input";if(pe.config.keyboardShortcuts.focused){var u=null;pe.config.keyboardShortcuts.global&&a.on(window,"keydown keyup",function(e){var n=t(e),o=a.getFocusElement(),s=[48,49,50,51,52,53,54,56,57,75,77,70,67,73,76,79];!a.inArray(s,n)||a.is.htmlElement(o)&&a.matches(o,pe.config.selectors.editable)||i(e)},!1),a.on(pe.elements.container,"keydown keyup",i,!1)}a.on(window,"keyup",function(e){var i=t(e),o=a.getFocusElement();9===i&&n(o);
+}),a.on(document.body,"click",function(){a.toggleClass(c("."+pe.config.classes.tabFocus),pe.config.classes.tabFocus,!1)});for(var d in pe.elements.buttons){var p=pe.elements.buttons[d];a.on(p,"blur",function(){a.toggleClass(p,"tab-focus",!1)})}var m=function(e,t,n){a.is.function(t)&&t.call(this,e),a.is.function(n)&&n.call(this,e)};a.proxy(pe.elements.buttons.play,"click",pe.config.listeners.play,e),a.proxy(pe.elements.buttons.playLarge,"click",pe.config.listeners.play,e),a.proxy(pe.elements.buttons.pause,"click",pe.config.listeners.pause,e),a.proxy(pe.elements.buttons.restart,"click",pe.config.listeners.restart,function(){pe.restart()}),a.proxy(pe.elements.buttons.rewind,"click",pe.config.listeners.rewind,function(){pe.rewind()}),a.proxy(pe.elements.buttons.forward,"click",pe.config.listeners.forward,function(){pe.forward()}),a.proxy(pe.elements.buttons.mute,"click",pe.config.listeners.mute,function(){pe.toggleMute()}),a.proxy(pe.elements.buttons.captions,"click",pe.config.listeners.captions,function(){pe.toggleCaptions()}),a.proxy(pe.elements.buttons.fullscreen,"click",pe.config.listeners.fullscreen,function(e){pe.toggleFullscreen(e)}),a.proxy(pe.elements.buttons.pip,"click",pe.config.listeners.pip,function(){pe.togglePictureInPicture()}),a.proxy(pe.elements.buttons.airplay,"click",pe.config.listeners.airplay,function(){pe.airPlay()}),a.on(pe.elements.buttons.settings,"click",z),a.on(document.documentElement,"click",z),a.on(pe.elements.settings.form,"click",X),a.on(pe.elements.settings.form,"click",function(e){a.matches(e.target,pe.config.selectors.inputs.language)?m.call(this,e,pe.config.listeners.language,function(){pe.language(e.target.value.toLowerCase())}):a.matches(e.target,pe.config.selectors.inputs.quality)?m.call(this,e,pe.config.listeners.quality,function(){ge("Set quality")}):a.matches(e.target,pe.config.selectors.inputs.speed)?m.call(this,e,pe.config.listeners.speed,function(){pe.setSpeed(parseFloat(e.target.value))}):a.matches(e.target,pe.config.selectors.buttons.loop)&&m.call(this,e,pe.config.listeners.loop,function(){var t=e.target.getAttribute("data-loop__value")||e.target.getAttribute("data-loop__type");a.inArray(["start","end","all","none"],t)&&pe.loop(t)})}),a.proxy(pe.elements.inputs.seek,o,pe.config.listeners.seek,function(e){var t=pe.getDuration();pe.seek(e.target.value/e.target.max*t)}),a.proxy(pe.elements.inputs.volume,o,pe.config.listeners.volume,function(){pe.setVolume(event.target.value)}),a.on(pe.elements.progress,"mouseenter mouseleave mousemove",oe),pe.config.hideControls&&(a.on(pe.elements.container,"mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen",function(e){pe.toggleControls(e)}),a.on(pe.elements.controls,"mouseenter mouseleave",function(e){pe.elements.controls.hover="mouseenter"===e.type}),a.on(pe.elements.controls,"mousedown mouseup touchstart touchend touchcancel",function(e){pe.elements.controls.pressed=a.inArray(["mousedown","touchstart"],e.type)}),a.on(pe.elements.controls,"focus blur",function(e){pe.toggleControls(e)},!0,!0)),a.proxy(pe.elements.inputs.volume,"wheel",pe.config.listeners.volume,function(e){var t=e.webkitDirectionInvertedFromDevice,n=.2,i=0;(e.deltaY<0||e.deltaX>0)&&(t?(pe.decreaseVolume(n),i=-1):(pe.increaseVolume(n),i=1)),(e.deltaY>0||e.deltaX<0)&&(t?(pe.increaseVolume(n),i=1):(pe.decreaseVolume(n),i=-1)),(1===i&&pe.media.volume<1||i===-1&&pe.media.volume>0)&&e.preventDefault()},!1),r.fullscreen&&a.on(document,s.eventType,function(e){pe.toggleFullscreen(e)})}function re(){if(a.on(pe.media,"timeupdate seeking",ne),a.on(pe.media,"durationchange loadedmetadata",te),a.on(pe.media,"ended",function(){"video"===pe.type&&pe.config.showPosterOnEnd&&("video"===pe.type&&I(),pe.restart(),pe.media.load())}),a.on(pe.media,"progress playing",K),a.on(pe.media,"volumechange",$),a.on(pe.media,"play pause ended",Q),a.on(pe.media,"waiting canplay seeked",G),pe.config.clickToPlay&&"audio"!==pe.type){var e=c("."+pe.config.classes.video);if(!e)return;e.style.cursor="pointer",a.on(e,"click",function(){pe.config.hideControls&&r.touch&&!pe.media.paused||(pe.media.paused?pe.play():pe.media.ended?(pe.restart(),pe.play()):pe.pause())})}pe.config.disableContextMenu&&a.on(pe.media,"contextmenu",function(e){e.preventDefault()},!1),a.on(pe.media,pe.config.events.concat(["keyup","keydown"]).join(" "),function(e){n(pe.elements.container,e.type,!0)})}function le(){if(a.inArray(o.html5,pe.type)){for(var e=pe.media.querySelectorAll("source"),t=0;t<e.length;t++)a.removeElement(e[t]);pe.media.setAttribute("src","https://cdn.selz.com/plyr/blank.mp4"),pe.media.load(),fe("Cancelled network requests")}}function ce(){return pe.supported.full?(a.is.htmlElement(pe.elements.controls)||(N(),se()),void(a.is.htmlElement(pe.elements.controls)&&(re(),M(),T(),x(),pe.setVolume(),$(),pe.setSpeed(),pe.loop(),ne(),Q()))):(ge("Basic support only",pe.type),u("controls"),u("buttons.play"),void M(!0))}function ue(){n(pe.elements.container,"ready",!0),pe.config.autoplay&&pe.play()}function de(e){if(null===e||a.is.undefined(e)||!a.is.htmlElement(e))return void ye("Setup failed: no suitable element passed");if(!pe.config.enabled)return void ye("Setup failed: disabled by config");if(!a.checkSupport().basic)return void ye("Setup failed: no support");if(e.plyr)return fe("Target already setup"),e.plyr;var t=e.tagName.toLowerCase();switch(t){case"div":if(pe.type=e.getAttribute("data-type"),pe.embedId=e.getAttribute("data-video-id"),a.is.empty(pe.type))return void ye("Setup failed: embed type missing");if(a.is.empty(pe.embedId))return void ye("Setup failed: video id missing");e.removeAttribute("data-type"),e.removeAttribute("data-video-id");break;case"iframe":break;case"video":case"audio":pe.type=t,pe.config.crossorigin=null!==e.getAttribute("crossorigin"),pe.config.autoplay=pe.config.autoplay||null!==e.getAttribute("autoplay"),pe.config.inline=null!==e.getAttribute("playsinline"),pe.config.loop.active=pe.config.loop||null!==e.getAttribute("loop");break;default:return ye("Setup failed: unsupported type"),!1}if(pe.browser=a.getBrowser(),O(),pe.supported=a.checkSupport(pe.type,pe.config.inline),!pe.supported.basic)return ye("Setup failed: no support"),!1;if(pe.elements.container=a.wrap(e,a.createElement("div")),pe.original=e.cloneNode(!0),pe.elements.container.setAttribute("tabindex",0),q(),fe(pe.browser.name+" "+pe.browser.version),j(),pe.config.debug){var n=pe.config.events.concat(["setup","statechange","enterfullscreen","exitfullscreen","captionsenabled","captionsdisabled"]);a.on(pe.elements.container,n.join(" "),function(e){fe(["event:",e.type].join(" ").trim())})}(a.inArray(o.html5,pe.type)||a.inArray(o.embed,pe.type)&&!pe.supported.full)&&(ce(),ue(),V())}var pe=this,me={};pe.media=e,a.is.string(pe.media)&&(pe.media=document.querySelectorAll(pe.media)),(window.jQuery&&pe.media instanceof jQuery||a.is.nodeList(pe.media)||a.is.array(pe.media))&&(pe.media=pe.media[0]),pe.config=a.extend({},i,t,function(){try{return JSON.parse(pe.media.getAttribute("data-plyr"))}catch(e){}}()),pe.elements={container:null,buttons:{},display:{},progress:{},inputs:{},settings:{menu:null,panes:{},tabs:{}},captions:null},pe.captions={enabled:!1,captions:[],tracks:[],currentTrack:null},pe.fullscreen={active:!1};var fe=function(){},ge=function(){},ye=function(){};pe.config.debug&&"console"in window&&(fe=console.log,ge=console.warn,ye=console.error,fe("Debugging enabled")),fe("Config",pe.config),fe("Support",r),pe.core={getElement:c,getElements:l,trigger:n,setCaption:I,setupCaptions:x,toggleNativeControls:M,updateTimeDisplay:ee,updateSeekDisplay:ie,updateSource:ae,updateStorage:D,timers:me,support:r,log:fe,warn:ge,error:ye},de(pe.media)}var n={x:0,y:0},i={enabled:!0,title:"",debug:!1,autoplay:!1,seekTime:10,volume:10,duration:null,displayDuration:!0,loadSprite:!0,iconPrefix:"plyr",iconUrl:"https://cdn.plyr.io/2.0.10/plyr.svg",clickToPlay:!0,hideControls:!0,showPosterOnEnd:!1,disableContextMenu:!0,quality:{default:"auto",selected:"auto"},loop:{active:!1,start:0,end:null,indicator:{start:0,end:0}},speed:{selected:1,options:[.25,.5,.75,1,1.25,1.5,2]},keyboardShortcuts:{focused:!0,global:!1},tooltips:{controls:!1,seek:!0},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"}},classes:{video:"plyr__video-wrapper",embed:"plyr__video-embed",control:"plyr__control",type:"plyr--{0}",stopped:"plyr--stopped",playing:"plyr--playing",muted:"plyr--muted",loading:"plyr--loading",hover:"plyr--hover",tooltip:"plyr__tooltip",hidden:"plyr__sr-only",hideControls:"plyr--hide-controls",isIos:"plyr--is-ios",isTouch:"plyr--is-touch",menu:{value:"plyr__menu__value",badge:"plyr__badge"},captions:{enabled:"plyr--captions-enabled",active:"plyr--captions-active"},fullscreen:{enabled:"plyr--fullscreen-enabled",active:"plyr--fullscreen-active"},pip:{enabled:"plyr--pip-enabled",active:"plyr--pip-active"},airplay:{enabled:"plyr--airplay-enabled",active:"plyr--airplay-active"},tabFocus:"tab-focus"},captions:{active:!1,language:window.navigator.language.split("-")[0]},fullscreen:{enabled:!0,fallback:!0,allowAudio:!1},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"},urls:{vimeo:{api:"https://player.vimeo.com/api/player.js"},youtube:{api:"https://www.youtube.com/iframe_api"},soundcloud:{api:"https://w.soundcloud.com/player/api.js"}},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"],logPrefix:""},o={embed:["youtube","vimeo","soundcloud"],html5:["video","audio"]},a={is:{object:function(e){return null!==e&&"object"==typeof e&&e.constructor===Object},array:function(e){return null!==e&&Array.isArray(e)},number:function(e){return null!==e&&("number"==typeof e&&!isNaN(e-0)||"object"==typeof e&&e.constructor===Number)},string:function(e){return null!==e&&("string"==typeof e||"object"==typeof e&&e.constructor===String)},boolean:function(e){return null!==e&&"boolean"==typeof e},nodeList:function(e){return null!==e&&e instanceof NodeList},htmlElement:function(e){return null!==e&&e instanceof HTMLElement},function:function(e){return null!==e&&"function"==typeof e},event:function(e){return null!==e&&e instanceof Event},cue:function(e){return null!==e&&(e instanceof window.TextTrackCue||e instanceof window.VTTCue)},track:function(e){return null!==e&&e instanceof window.TextTrack},undefined:function(e){return null!==e&&"undefined"==typeof e},empty:function(e){return null===e||this.undefined(e)||(this.string(e)||this.array(e)||this.nodeList(e))&&0===e.length||this.object(e)&&0===Object.keys(e).length}},getBrowser:function(){var e,t,n,i=navigator.userAgent,o=navigator.appName,a=""+parseFloat(navigator.appVersion),s=parseInt(navigator.appVersion,10),r=!1,l=!1,c=!1,u=!1;return navigator.appVersion.indexOf("Windows NT")!==-1&&navigator.appVersion.indexOf("rv:11")!==-1?(r=!0,o="IE",a="11"):(t=i.indexOf("MSIE"))!==-1?(r=!0,o="IE",a=i.substring(t+5)):(t=i.indexOf("Chrome"))!==-1?(c=!0,o="Chrome",a=i.substring(t+7)):(t=i.indexOf("Safari"))!==-1?(u=!0,o="Safari",a=i.substring(t+7),(t=i.indexOf("Version"))!==-1&&(a=i.substring(t+8))):(t=i.indexOf("Firefox"))!==-1?(l=!0,o="Firefox",a=i.substring(t+8)):(e=i.lastIndexOf(" ")+1)<(t=i.lastIndexOf("/"))&&(o=i.substring(e,t),a=i.substring(t+1),o.toLowerCase()===o.toUpperCase()&&(o=navigator.appName)),(n=a.indexOf(";"))!==-1&&(a=a.substring(0,n)),(n=a.indexOf(" "))!==-1&&(a=a.substring(0,n)),s=parseInt(""+a,10),isNaN(s)&&(a=""+parseFloat(navigator.appVersion),s=parseInt(navigator.appVersion,10)),{name:o,version:s,isIE:r,isOldIE:r&&s<=9,isFirefox:l,isChrome:c,isSafari:u,isIPhone:/(iPhone|iPod)/gi.test(navigator.platform),isIos:/(iPad|iPhone|iPod)/gi.test(navigator.platform)}},checkSupport:function(e,t){var n=!1,i=!1,o=a.getBrowser(),s=o.isIPhone&&t&&r.inline;switch(e){case"video":n=r.video,i=n&&!o.isOldIE&&(!o.isIPhone||s);break;case"audio":n=r.audio,i=n&&!o.isOldIE;break;case"youtube":n=r.video,i=n&&!o.isOldIE&&(!o.isIPhone||s);break;case"vimeo":case"soundcloud":n=!0,i=!o.isOldIE&&!o.isIos;break;default:n=r.audio&&r.video,i=n&&!o.isOldIE}return{basic:n,full:i}},injectScript:function(e){if(!document.querySelectorAll('script[src="'+e+'"]').length){var t=document.createElement("script");t.src=e;var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n)}},inFrame:function(){try{return window.self!==window.top}catch(e){return!0}},inArray:function(e,t){return a.is.array(e)&&e.indexOf(t)!==-1},replaceAll:function(e,t,n){return e.replace(new RegExp(t.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g,"\\$1"),"g"),n)},wrap:function(e,t){e.length||(e=[e]);for(var n=e.length-1;n>=0;n--){var i=n>0?t.cloneNode(!0):t,o=e[n],a=o.parentNode,s=o.nextSibling;return i.appendChild(o),s?a.insertBefore(i,s):a.appendChild(i),i}},removeElement:function(e){a.is.htmlElement(e)&&a.is.htmlElement(e.parentNode)&&e.parentNode.removeChild(e)},prependChild:function(e,t){e.insertBefore(t,e.firstChild)},insertAfter:function(e,t){t.parentNode.insertBefore(e,t.nextSibling)},createElement:function(e,t,n){var i=document.createElement(e);return a.is.object(t)&&a.setAttributes(i,t),a.is.string(n)&&(i.textContent=n),i},insertElement:function(e,t,n,i){var o=a.createElement(e,n,i);a.prependChild(t,o)},emptyElement:function(e){for(var t=e.childNodes.length;t--;)e.removeChild(e.lastChild)},setAttributes:function(e,t){for(var n in t)e.setAttribute(n,t[n])},getAttributesFromSelector:function(e,t){if(!a.is.string(e)||a.is.empty(e))return{};var n={};return e.split(",").forEach(function(e){e=e.trim();var i=e.charAt(0);switch(i){case".":var o=e.replace(".","");a.is.object(t)&&a.is.string(t.class)&&(t.class+=" "+o),n.class=o;break;case"#":n.id=e.replace("#","");break;case"[":e=e.replace(/[\[\]]/g,"");var s=e.split("="),r=s[0],l=s.length>1?s[1].replace(/[\"\']/g,""):"";n[r]=l}}),n},toggleClass:function(e,t,n){if(e)if(e.classList)e.classList[n?"add":"remove"](t);else{var i=(" "+e.className+" ").replace(/\s+/g," ").replace(" "+t+" ","");e.className=i+(n?" "+t:"")}},hasClass:function(e,t){return!!e&&(e.classList?e.classList.contains(t):new RegExp("(\\s|^)"+t+"(\\s|$)").test(e.className))},matches:function(e,t){var n=Element.prototype,i=n.matches||n.webkitMatchesSelector||n.mozMatchesSelector||n.msMatchesSelector||function(e){return[].indexOf.call(document.querySelectorAll(e),this)!==-1};return i.call(e,t)},getFocusElement:function(){var e=document.activeElement;return e=e&&e!==document.body?document.querySelector(":focus"):null},proxy:function(e,t,n,i,o,s){a.on(e,t,function(t){n&&n.apply(e,[t]),i.apply(e,[t])},o,s)},toggleListener:function(e,t,n,i,o,s){if(t=t.split(" "),a.is.boolean(s)||(s=!1),a.is.boolean(o)||(o=!0),e instanceof NodeList){var l=1===arguments.length?[arguments[0]]:Array.apply(null,arguments);return l.shift(),void[].forEach.call(e,function(e){e instanceof Node&&a.toggleListener.apply(null,[e].concat(l))})}var c=s;r.passiveListeners&&(c={passive:o,capture:s}),t.forEach(function(t){e[i?"addEventListener":"removeEventListener"](t,n,c)})},on:function(e,t,n,i,o){a.is.undefined(e)||a.toggleListener(e,t,n,!0,i,o)},off:function(e,t,n,i,o){a.is.undefined(e)||a.toggleListener(e,t,n,!1,i,o)},event:function(e,t,n,i){if(e&&t){a.is.boolean(n)||(n=!1);var o;a.is.function(window.CustomEvent)?o=window.CustomEvent:(o=function(e,t){t=t||{bubbles:!1,cancelable:!1,detail:void 0};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),n},o.prototype=window.Event.prototype);var s=new o(t,{bubbles:n,detail:i});e.dispatchEvent(s)}},toggleState:function(e,t){if(e)return t=a.is.boolean(t)?t:!e.getAttribute("aria-pressed"),e.setAttribute("aria-pressed",t),t},getPercentage:function(e,t){return 0===e||0===t||isNaN(e)||isNaN(t)?0:(e/t*100).toFixed(2)},extend:function(){var e=arguments;if(e.length){if(1===e.length)return e[0];var t=Array.prototype.shift.call(e);a.is.object(t)||(t={});for(var n=e.length,i=0;i<n;i++){var o=e[i];a.is.object(o)||(o={});for(var s in o)o[s]&&o[s].constructor&&o[s].constructor===Object?(t[s]=t[s]||{},a.extend(t[s],o[s])):t[s]=o[s]}return t}},parseYouTubeId:function(e){var t=/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;return e.match(t)?RegExp.$2:e},stripHTML:function(e){var t=document.createDocumentFragment(),n=document.createElement("div");return t.appendChild(n),n.innerHTML=e,t.firstChild.innerText},loadSprite:function(e,t){function n(e,t){e.innerHTML=t,document.body.insertBefore(e,document.body.childNodes[0])}if("string"==typeof e){var i="cache-",o="string"==typeof t,a=!1;if(!o||!document.querySelectorAll("#"+t).length){var s=document.createElement("div");if(s.setAttribute("hidden",""),o&&s.setAttribute("id",t),r.storage){var l=window.localStorage.getItem(i+t);if(a=null!==l){var c=JSON.parse(l);n(s,c.content)}}var u=new XMLHttpRequest;if(!("withCredentials"in u))return;u.open("GET",e,!0),u.onload=function(){r.storage&&window.localStorage.setItem(i+t,JSON.stringify({content:u.responseText})),n(s,u.responseText)},u.send()}}},transitionEnd:function(){var e=document.createElement("span"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var n in t)if(void 0!==e.style[n])return t[n];return!1}()},s=function(){var e=function(){var e=!1;return a.is.function(document.cancelFullScreen)?e="":["webkit","o","moz","ms","khtml"].some(function(t){return a.is.function(document[t+"CancelFullScreen"])?(e=t,!0):a.is.function(document.msExitFullscreen)&&document.msFullscreenEnabled?(e="ms",!0):void 0}),e}();return{prefix:e,eventType:"ms"===e?"MSFullscreenChange":e+"fullscreenchange",isFullScreen:function(t){if(!r.fullscreen)return!1;switch(a.is.undefined(t)&&(t=document.body),this.prefix){case"":return document.fullscreenElement===t;case"moz":return document.mozFullScreenElement===t;default:return document[e+"FullscreenElement"]===t}},requestFullScreen:function(t){return!!r.fullscreen&&(a.is.htmlElement(t)||(t=document.body),""===e?t.requestFullScreen():t[e+("ms"===e?"RequestFullscreen":"RequestFullScreen")]())},cancelFullScreen:function(){return!!r.fullscreen&&(""===e?document.cancelFullScreen():document[e+("ms"===e?"ExitFullscreen":"CancelFullScreen")]())},element:function(){return r.fullscreen?""===e?document.fullscreenElement:document[e+"FullscreenElement"]:null}}}(),r={audio:"canPlayType"in document.createElement("audio"),video:"canPlayType"in document.createElement("video"),fullscreen:s.prefix!==!1,storage:function(){if(!("localStorage"in window))return!1;var e="___test";try{return window.localStorage.setItem(e,e),window.localStorage.removeItem(e),!0}catch(e){return!1}return!1}(),pip:function(){var e=a.getBrowser();return!e.isIPhone&&a.is.function(a.createElement("video").webkitSetPresentationMode)}(),airplay:a.is.function(window.WebKitPlaybackTargetAvailabilityEvent),inline:"playsInline"in document.createElement("video"),mime:function(e,t){var n=e.media;try{if(!a.is.function(n.canPlayType))return!1;if("video"===e.type)switch(t){case"video/webm":return n.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/,"");case"video/mp4":return n.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/,"");case"video/ogg":return n.canPlayType('video/ogg; codecs="theora"').replace(/no/,"")}else if("audio"===e.type)switch(t){case"audio/mpeg":return n.canPlayType("audio/mpeg;").replace(/no/,"");case"audio/ogg":return n.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/,"");case"audio/wav":return n.canPlayType('audio/wav; codecs="1"').replace(/no/,"")}}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(){e=!0}});window.addEventListener("test",null,t)}catch(e){}return e}(),touch:"ontouchstart"in document.documentElement,transitions:a.transitionEnd!==!1,reducedMotion:"matchMedia"in window&&window.matchMedia("(prefers-reduced-motion)").matches};return t.prototype.play=function(){var e=this;return"play"in e.media&&e.media.play(),e},t.prototype.pause=function(){var e=this;return"pause"in e.media&&e.media.pause(),e},t.prototype.togglePlay=function(e){var t=this;return a.is.boolean(e)||(e=t.media.paused),e?t.play():t.pause(),e},t.prototype.stop=function(){var e=this;return e.restart(),e.pause(),e},t.prototype.restart=function(){var e=this;return e.seek(),e},t.prototype.rewind=function(e){var t=this;return a.is.number(e)||(e=t.config.seekTime),t.seek(t.media.currentTime-e),t},t.prototype.forward=function(e){var t=this;return a.is.number(e)||(e=t.config.seekTime),t.seek(t.media.currentTime+e),t},t.prototype.seek=function(e){var t=this,n=0,i=t.media.paused,s=t.getDuration();a.is.number(e)&&(n=e),n<0?n=0:n>s&&(n=s),t.core.updateSeekDisplay(n);try{t.media.currentTime=n.toFixed(4)}catch(e){}if(a.inArray(o.embed,t.type)){switch(t.type){case"youtube":t.embed.seekTo(n);break;case"vimeo":t.embed.setCurrentTime(n.toFixed(0));break;case"soundcloud":t.embed.seekTo(1e3*n)}i&&t.pause(),t.core.trigger(t.media,"timeupdate"),t.media.seeking=!0,t.core.trigger(t.media,"seeking")}return t.core.log("Seeking to "+t.media.currentTime+" seconds"),t},t.prototype.setVolume=function(e){var t=this,n=10,i=0;if(a.is.undefined(e)&&(e=t.storage.volume),(null===e||isNaN(e))&&(e=t.config.volume),e>n&&(e=n),e<i&&(e=i),t.media.volume=parseFloat(e/n),t.elements.display.volume&&(t.elements.display.volume.value=e),a.inArray(o.embed,t.type)){switch(t.type){case"youtube":t.embed.setVolume(100*t.media.volume);break;case"vimeo":case"soundcloud":t.embed.setVolume(t.media.volume)}t.core.trigger(t.media,"volumechange")}return 0===e?t.media.muted=!0:t.media.muted&&e>0&&t.toggleMute(),t},t.prototype.increaseVolume=function(e){var t=this,n=t.media.muted?0:10*t.media.volume;return a.is.number(e)||(e=1),t.setVolume(n+e),t},t.prototype.decreaseVolume=function(e){var t=this,n=t.media.muted?0:10*t.media.volume;return a.is.number(e)||(e=1),t.setVolume(n-e),t},t.prototype.toggleMute=function(e){var t=this;if(a.is.boolean(e)||(e=!t.media.muted),a.toggleState(t.elements.buttons.mute,e),t.media.muted=e,0===t.media.volume&&t.volume(t.config.volume),a.inArray(o.embed,t.type)){switch(t.type){case"youtube":t.embed[t.media.muted?"mute":"unMute"]();break;case"vimeo":case"soundcloud":t.embed.setVolume(t.media.muted?0:parseFloat(t.config.volume/10))}t.core.trigger(t.media,"volumechange")}return t},t.prototype.setSpeed=function(e){var t=this;return a.is.number(e)||(e=parseFloat(t.storage.speed||t.config.speed.selected)),e<.1&&(e=.1),e>2&&(e=2),a.is.array(t.config.speed.options)?(t.config.speed.selected=e,t.media.playbackRate=e,t.core.updateStorage({speed:e}),t):void t.core.warn("Invalid speeds format")},t.prototype.loop=function(e){var t=this;a.inArray(["start","end","all","none","toggle"],e)||(e="toggle");var n=Number(t.media.currentTime);switch(e){case"start":t.config.loop.end&&t.config.loop.end<=n&&(t.config.loop.end=null),t.config.loop.start=n,t.config.loop.indicator.start=t.elements.display.played.value;break;case"end":if(t.config.loop.start>=n)return;t.config.loop.end=n,t.config.loop.indicator.end=t.elements.display.played.value;break;case"all":t.config.loop.start=0,t.config.loop.end=t.media.duration-2,t.config.loop.indicator.start=0,t.config.loop.indicator.end=100;break;case"toggle":t.config.loop.active?(t.config.loop.start=0,t.config.loop.end=null):(t.config.loop.start=0,t.config.loop.end=t.media.duration-2);break;default:t.config.loop.start=0,t.config.loop.end=null}t.config.loop.active=a.is.number(t.config.loop.start)&&a.is.number(t.config.loop.end);var i=(t.core.updateTimeDisplay(t.config.loop.start,t.core.getElement('[data-plyr-loop="start"]')),null);return a.is.number(t.config.loop.end)&&(i=t.core.updateTimeDisplay(t.config.loop.end,t.core.getElement('[data-loop__value="loopout"]'))),t.config.loop.active,t},t.prototype.source=function(e){var t=this;if(a.is.object(e))return t.core.updateSource(e),t;var n;switch(t.type){case"youtube":n=t.embed.getVideoUrl();break;case"vimeo":t.embed.getVideoUrl.then(function(e){n=e});break;case"soundcloud":t.embed.getCurrentSound(function(e){n=e.permalink_url});break;default:n=t.media.currentSrc}return n},t.prototype.poster=function(e){var t=this;return a.is.string(e)?("video"===t.type?t.media.setAttribute("poster",e):t.core.warn("Poster can only be set on HTML5 video"),t):t.media.getAttribute("poster")},t.prototype.toggleCaptions=function(e){var t=this;if(t.supported.full&&t.elements.buttons.captions)return a.is.boolean(e)||(e=t.elements.container.className.indexOf(t.config.classes.captions.active)===-1),t.captions.enabled=e,a.toggleState(t.elements.buttons.captions,t.captions.enabled),a.toggleClass(t.elements.container,t.config.classes.captions.active,t.captions.enabled),t.core.trigger(t.elements.container,t.captions.enabled?"captionsenabled":"captionsdisabled",!0),t.core.updateStorage({captions:t.captions.enabled}),t},t.prototype.language=function(e){var t=this;return a.is.string(e)?(t.config.captions.language=e.toLowerCase(),t.core.setCaption(),t.core.setupCaptions(),t):t.config.captions.language},t.prototype.toggleFullscreen=function(e){function t(){n={x:window.pageXOffset||0,y:window.pageYOffset||0}}function i(){window.scrollTo(n.x,n.y)}var o=this,l=r.fullscreen;if(l){if(!a.is.event(e)||e.type!==s.eventType)return s.isFullScreen(o.elements.container)?s.cancelFullScreen():(t(),s.requestFullScreen(o.elements.container)),void(o.fullscreen.active=s.isFullScreen(o.elements.container));o.fullscreen.active=s.isFullScreen(o.elements.container)}else o.fullscreen.active=!o.fullscreen.active,document.body.style.overflow=o.fullscreen.active?"hidden":"";return a.toggleClass(o.elements.container,o.config.classes.fullscreen.active,o.fullscreen.active),o.elements.buttons&&o.elements.buttons.fullscreen&&a.toggleState(o.elements.buttons.fullscreen,o.fullscreen.active),o.core.trigger(o.elements.container,o.fullscreen.active?"enterfullscreen":"exitfullscreen",!0),!o.fullscreen.active&&l&&i(),o},t.prototype.togglePictureInPicture=function(e){var t=this,n={pip:"picture-in-picture",inline:"inline"};if(t.core.support.pip)return a.is.boolean(e)||(e=t.media.webkitPresentationMode===n.inline),t.media.webkitSetPresentationMode(e?n.pip:n.inline),t},t.prototype.airPlay=function(){var e=this;if(e.core.support.airplay)return e.media.webkitShowPlaybackTargetPicker(),e},t.prototype.toggleControls=function(e){var t=this;if(t.config.hideControls&&"audio"!==t.type){var n=0,i=e,o=!1,s=a.hasClass(t.elements.container,t.config.classes.loading);if(a.is.boolean(e)||(a.is.event(e)?(o="enterfullscreen"===e.type,i=a.inArray(["mousemove","touchstart","mouseenter","focus"],e.type),a.inArray(["mousemove","touchmove"],e.type)&&(n=2e3),"focus"===e.type&&(n=3e3)):i=a.hasClass(t.elements.container,t.config.classes.hideControls)),window.clearTimeout(t.core.timers.hover),i||t.media.paused||s){if(a.toggleClass(t.elements.container,t.config.classes.hideControls,!1),t.media.paused||s)return;r.touch&&(n=3e3)}return i&&t.media.paused||(t.core.timers.hover=window.setTimeout(function(){(!t.elements.controls.pressed&&!t.elements.controls.hover||o)&&a.toggleClass(t.elements.container,t.config.classes.hideControls,!0)},n)),t}},t.prototype.on=function(e,t){var n=this;return a.on(n.elements.container,e,t),n},t.prototype.supports=function(e){return r.mime(this,e)},t.prototype.destroy=function(e,t){function n(){a.is.boolean(t)||(t=!0),a.is.function(e)&&e.call(i.original),t&&(i.elements.container.parentNode.replaceChild(i.original,i.elements.container),document.body.style.overflow="",i.core.trigger(i.original,"destroyed",!0))}var i=this;switch(i.type){case"youtube":window.clearInterval(i.timers.buffering),window.clearInterval(i.timers.playing),i.embed.destroy(),n();break;case"vimeo":i.embed.unload().then(n),window.setTimeout(n,200);break;case"video":case"audio":i.core.toggleNativeControls(!0),n()}return i},t.prototype.getDuration=function(){var e=this,t=parseInt(e.config.duration),n=0;return null===e.media.duration||isNaN(e.media.duration)||(n=e.media.duration),isNaN(t)?n:t},t}); \ No newline at end of file
diff --git a/notes.md b/notes.md
index c71bfc0f..3adf38c9 100644
--- a/notes.md
+++ b/notes.md
@@ -40,7 +40,35 @@
- Added `playsinline` support for iOS 10
- Embed setup now accepts an <iframe> as the target element for true progressive enhancement
-#### Breaking changes
+## Changes
+
+### Config changes
+- videoWrapper -> video
+- embedWrapper -> embed
+- setup and ready classes removed
+
+### API changes
+- Can now chain most functions (need to document which can)
+- support -> supports
+- isFullscreen -> fullscreen.active
+- new 'language'
+- getType -> type
+- getEmbed -> embed
+- getContainer removed
+- getMedia -> media
+- getCurrentTime -> media.currentTime
+- getVolume -> media.volume
+- isMuted -> media.muted
+- isLoading -> media.loading
+- isPaused -> media.paused
+- updatePoster -> poster
+- setVolume -> volume
+- increaseVolume (new)
+- decreaseVolume (new)
+- togglePictureInPicture (new)
+- airPlay (new)
+
+#### Other breaking changes
- New config options for loop
- Selectors changes (new `input` and `display` object) - DOCUMENT
- Custom HTML option now `controls` which accepts a string (HTML), a function (your own template engine) or array (use built in controls)
diff --git a/src/js/plyr.js b/src/js/plyr.js
index 2a44a13b..459bc6fd 100644
--- a/src/js/plyr.js
+++ b/src/js/plyr.js
@@ -5,25 +5,20 @@
// License: The MIT License (MIT)
// ==========================================================================
-(function(root, factory) {
+(function(name, context, definition) {
+ /* global define,module,require,YUI */
'use strict';
- /* global define,module */
- if (typeof module === 'object' && typeof module.exports === 'object') {
- // Node, CommonJS-like
- module.exports = factory(root, document);
+ if (typeof exports === 'object') {
+ module.exports = definition(require);
} else if (typeof define === 'function' && define.amd) {
- // AMD
- define([], function() {
- return factory(root, document);
- });
+ define(definition);
} else {
- // Browser globals (root is window)
- root.Plyr = factory(root, document);
+ context[name] = definition();
}
-}(typeof window !== 'undefined' ? window : this, function(window, document) {
+}).call(this, 'Plyr', this, function(require) {
'use strict';
- /* global jQuery */
+ /* global jQuery, console */
// Globals
var scroll = {
@@ -132,10 +127,8 @@
// Class hooks added to the player in different states
classes: {
- setup: 'plyr--setup',
- ready: 'plyr--ready',
- videoWrapper: 'plyr__video-wrapper',
- embedWrapper: 'plyr__video-embed',
+ video: 'plyr__video-wrapper',
+ embed: 'plyr__video-embed',
control: 'plyr__control',
type: 'plyr--{0}',
stopped: 'plyr--stopped',
@@ -306,7 +299,7 @@
html5: ['video', 'audio']
};
- // Utilities outside of Plyr scope
+ // Utilities
var utils = {
// Check variable types
is: {
@@ -1197,25 +1190,30 @@
};
// Player instance
- function Player(element, options) {
+ function Player(media, options) {
var player = this;
var timers = {};
var api = {};
+ // Get the media element
+ player.media = media;
+
// String selector passed
- if (utils.is.string(element)) {
- element = document.querySelectorAll(element);
+ if (utils.is.string(player.media)) {
+ player.media = document.querySelectorAll(player.media);
}
// jQuery, NodeList or Array passed, use first element
- if ((window.jQuery && element instanceof jQuery) || utils.is.nodeList(element) || utils.is.array(element)) {
- element = element[0];
+ if ((window.jQuery && player.media instanceof jQuery) ||
+ utils.is.nodeList(player.media) ||
+ utils.is.array(player.media)) {
+ player.media = player.media[0];
}
- // Config
- var config = utils.extend({}, defaults, options, (function() {
+ // Set config
+ player.config = utils.extend({}, defaults, options, (function() {
try {
- return JSON.parse(element.getAttribute('data-plyr'));
+ return JSON.parse(player.media.getAttribute('data-plyr'));
} catch (e) {}
})());
@@ -1231,7 +1229,6 @@
panes: {},
tabs: {}
},
- media: element,
captions: null
};
@@ -1252,20 +1249,21 @@
var log = function() {};
var warn = function() {};
var error = function() {};
- if (config.debug && 'console' in window) {
- log = window.console.log;
- warn = window.console.warn;
- error = window.console.error;
+ if (player.config.debug && 'console' in window) {
+ log = console.log;
+ warn = console.warn;
+ error = console.error;
+ log('Debugging enabled');
}
// Log config options and support
- log('Config', config);
+ log('Config', player.config);
log('Support', support);
// Trigger events, with plyr instance passed
function trigger(element, type, bubbles, properties) {
utils.event(element, type, bubbles, utils.extend({}, properties, {
- plyr: api
+ plyr: player
}));
}
@@ -1318,12 +1316,12 @@
// Add elements to HTML5 media (source, tracks, etc)
function insertElements(type, attributes) {
if (utils.is.string(attributes)) {
- utils.insertElement(type, player.elements.media, {
+ utils.insertElement(type, player.media, {
src: attributes
});
} else if (utils.is.array(attributes)) {
attributes.forEach(function(attribute) {
- utils.insertElement(type, player.elements.media, attribute);
+ utils.insertElement(type, player.media, attribute);
});
}
}
@@ -1331,8 +1329,8 @@
// Get icon URL
function getIconUrl() {
return {
- url: config.iconUrl,
- absolute: (config.iconUrl.indexOf("http") === 0) || player.browser.isIE
+ url: player.config.iconUrl,
+ absolute: (player.config.iconUrl.indexOf("http") === 0) || player.browser.isIE
};
}
@@ -1340,7 +1338,7 @@
function createIcon(type, attributes) {
var namespace = 'http://www.w3.org/2000/svg';
var iconUrl = getIconUrl();
- var iconPath = (!iconUrl.absolute ? iconUrl.url : '') + '#' + config.iconPrefix;
+ var iconPath = (!iconUrl.absolute ? iconUrl.url : '') + '#' + player.config.iconPrefix;
// Create <svg>
var icon = document.createElementNS(namespace, 'svg');
@@ -1360,7 +1358,7 @@
// Create hidden text label
function createLabel(type) {
- var text = config.i18n[type];
+ var text = player.config.i18n[type];
switch (type) {
case 'pip':
@@ -1373,18 +1371,18 @@
}
return utils.createElement('span', {
- class: config.classes.hidden
+ class: player.config.classes.hidden
}, text);
}
// Create a badge
function createBadge(text) {
var badge = utils.createElement('span', {
- class: config.classes.menu.value
+ class: player.config.classes.menu.value
});
badge.appendChild(utils.createElement('span', {
- class: config.classes.menu.badge
+ class: player.config.classes.menu.badge
}, text));
return badge;
@@ -1402,11 +1400,11 @@
}
if ('class' in attributes) {
- if (attributes.class.indexOf(config.classes.control) === -1) {
- attributes.class += ' ' + config.classes.control;
+ if (attributes.class.indexOf(player.config.classes.control) === -1) {
+ attributes.class += ' ' + player.config.classes.control;
}
} else {
- attributes.class = config.classes.control;
+ attributes.class = player.config.classes.control;
}
// Large play button
@@ -1442,7 +1440,7 @@
}
// Merge attributes
- utils.extend(attributes, utils.getAttributesFromSelector(config.selectors.buttons[type], attributes));
+ utils.extend(attributes, utils.getAttributesFromSelector(player.config.selectors.buttons[type], attributes));
// Add toggle icon if needed
if (utils.is.string(iconToggled)) {
@@ -1466,11 +1464,11 @@
// Seek label
var label = utils.createElement('label', {
for: attributes.id,
- class: config.classes.hidden
- }, config.i18n[type]);
+ class: player.config.classes.hidden
+ }, player.config.i18n[type]);
// Seek input
- var input = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(config.selectors.inputs[type]), {
+ var input = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(player.config.selectors.inputs[type]), {
type: 'range',
min: 0,
max: 100,
@@ -1489,7 +1487,7 @@
// Create a <progress>
function createProgress(type, attributes) {
- var progress = utils.createElement('progress', utils.extend(utils.getAttributesFromSelector(config.selectors.display[type]), {
+ var progress = utils.createElement('progress', utils.extend(utils.getAttributesFromSelector(player.config.selectors.display[type]), {
min: 0,
max: 100,
value: 0
@@ -1502,11 +1500,11 @@
var suffix = '';
switch (type) {
case 'played':
- suffix = config.i18n.played;
+ suffix = player.config.i18n.played;
break;
case 'buffer':
- suffix = config.i18n.buffered;
+ suffix = player.config.i18n.buffered;
break;
}
@@ -1525,10 +1523,10 @@
});
container.appendChild(utils.createElement('span', {
- class: config.classes.hidden
- }, config.i18n[type]));
+ class: player.config.classes.hidden
+ }, player.config.i18n[type]));
- container.appendChild(utils.createElement('span', utils.getAttributesFromSelector(config.selectors.display[type]), '00:00'));
+ container.appendChild(utils.createElement('span', utils.getAttributesFromSelector(player.config.selectors.display[type]), '00:00'));
player.elements.display[type] = container;
@@ -1538,33 +1536,33 @@
// Build the default HTML
function createControls(data) {
// Create the container
- var controls = utils.createElement('div', utils.getAttributesFromSelector(config.selectors.controls.wrapper));
+ var controls = utils.createElement('div', utils.getAttributesFromSelector(player.config.selectors.controls.wrapper));
// Restart button
- if (utils.inArray(config.controls, 'restart')) {
+ if (utils.inArray(player.config.controls, 'restart')) {
controls.appendChild(createButton('restart'));
}
// Rewind button
- if (utils.inArray(config.controls, 'rewind')) {
+ if (utils.inArray(player.config.controls, 'rewind')) {
controls.appendChild(createButton('rewind'));
}
// Play Pause button
// TODO: This should be a toggle button really?
- if (utils.inArray(config.controls, 'play')) {
+ if (utils.inArray(player.config.controls, 'play')) {
controls.appendChild(createButton('play'));
controls.appendChild(createButton('pause'));
}
// Fast forward button
- if (utils.inArray(config.controls, 'fast-forward')) {
+ if (utils.inArray(player.config.controls, 'fast-forward')) {
controls.appendChild(createButton('fast-forward'));
}
// Progress
- if (utils.inArray(config.controls, 'progress')) {
- var container = utils.createElement('span', utils.getAttributesFromSelector(config.selectors.progress));
+ if (utils.inArray(player.config.controls, 'progress')) {
+ var container = utils.createElement('span', utils.getAttributesFromSelector(player.config.selectors.progress));
// Seek range slider
var seek = createRange('seek', {
@@ -1582,10 +1580,10 @@
container.appendChild(createProgress('buffer'));
// Seek tooltip
- if (config.tooltips.seek) {
+ if (player.config.tooltips.seek) {
var tooltip = utils.createElement('span', {
role: 'tooltip',
- class: config.classes.tooltip
+ class: player.config.classes.tooltip
}, '00:00');
container.appendChild(tooltip);
@@ -1597,22 +1595,22 @@
}
// Media current time display
- if (utils.inArray(config.controls, 'current-time')) {
+ if (utils.inArray(player.config.controls, 'current-time')) {
controls.appendChild(createTime('currentTime'));
}
// Media duration display
- if (utils.inArray(config.controls, 'duration')) {
+ if (utils.inArray(player.config.controls, 'duration')) {
controls.appendChild(createTime('duration'));
}
// Toggle mute button
- if (utils.inArray(config.controls, 'mute')) {
+ if (utils.inArray(player.config.controls, 'mute')) {
controls.appendChild(createButton('mute'));
}
// Volume range control
- if (utils.inArray(config.controls, 'volume')) {
+ if (utils.inArray(player.config.controls, 'volume')) {
var volume = utils.createElement('span', {
class: 'plyr__volume'
});
@@ -1620,7 +1618,7 @@
// Set the attributes
var attributes = {
max: 10,
- value: config.volume
+ value: player.config.volume
};
// Create the volume range slider
@@ -1638,12 +1636,12 @@
}
// Toggle captions button
- if (utils.inArray(config.controls, 'captions')) {
+ if (utils.inArray(player.config.controls, 'captions')) {
controls.appendChild(createButton('captions'));
}
// Settings button / menu
- if (utils.inArray(config.controls, 'settings')) {
+ if (utils.inArray(player.config.controls, 'settings')) {
var menu = utils.createElement('div', {
class: 'plyr__menu'
});
@@ -1679,23 +1677,23 @@
});
// Build the tabs
- config.settings.forEach(function(type) {
+ player.config.settings.forEach(function(type) {
var tab = utils.createElement('li', {
role: 'tab',
hidden: ''
});
- var button = utils.createElement('button', utils.extend(utils.getAttributesFromSelector(config.selectors.buttons.settings), {
+ var button = utils.createElement('button', utils.extend(utils.getAttributesFromSelector(player.config.selectors.buttons.settings), {
type: 'button',
- class: config.classes.control + ' ' + config.classes.control + '--forward',
+ class: player.config.classes.control + ' ' + player.config.classes.control + '--forward',
id: 'plyr-settings-' + data.id + '-' + type + '-tab',
'aria-haspopup': true,
'aria-controls': 'plyr-settings-' + data.id + '-' + type,
'aria-expanded': false
- }), config.i18n[type]);
+ }), player.config.i18n[type]);
var value = utils.createElement('span', {
- class: config.classes.menu.value
+ class: player.config.classes.menu.value
});
// Speed contains HTML entities
@@ -1712,7 +1710,7 @@
inner.appendChild(home);
// Build the panes
- config.settings.forEach(function(type) {
+ player.config.settings.forEach(function(type) {
var pane = utils.createElement('div', {
id: 'plyr-settings-' + data.id + '-' + type,
'aria-hidden': true,
@@ -1724,11 +1722,11 @@
var back = utils.createElement('button', {
type: 'button',
- class: config.classes.control + ' ' + config.classes.control + '--back',
+ class: player.config.classes.control + ' ' + player.config.classes.control + '--back',
'aria-haspopup': true,
'aria-controls': 'plyr-settings-' + data.id + '-home',
'aria-expanded': false
- }, config.i18n[type]);
+ }, player.config.i18n[type]);
pane.appendChild(back);
@@ -1749,20 +1747,26 @@
}
// Picture in picture button
- if (utils.inArray(config.controls, 'pip') && support.pip) {
+ if (utils.inArray(player.config.controls, 'pip') && support.pip) {
controls.appendChild(createButton('pip'));
}
// Airplay button
- if (utils.inArray(config.controls, 'airplay') && support.airplay) {
+ if (utils.inArray(player.config.controls, 'airplay') && support.airplay) {
controls.appendChild(createButton('airplay'));
}
// Toggle fullscreen button
- if (utils.inArray(config.controls, 'fullscreen')) {
+ if (utils.inArray(player.config.controls, 'fullscreen')) {
controls.appendChild(createButton('fullscreen'));
}
+ // Larger overlaid play button
+ if (utils.inArray(player.config.controls, 'play-large')) {
+ player.elements.buttons.playLarge = createButton('play-large');
+ player.elements.container.appendChild(player.elements.buttons.playLarge);
+ }
+
player.elements.controls = controls;
setLoopMenu();
@@ -1840,16 +1844,16 @@
var item = utils.createElement('li');
var label = utils.createElement('label', {
- class: config.classes.control
+ class: player.config.classes.control
});
- var radio = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(config.selectors.inputs.quality), {
+ var radio = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(player.config.selectors.inputs.quality), {
type: 'radio',
name: 'plyr-quality',
value: quality,
}));
- if (quality === config.quality.selected) {
+ if (quality === player.config.quality.selected) {
radio.checked = true;
}
@@ -1882,11 +1886,11 @@
options.forEach(function(option) {
var item = utils.createElement('li');
- var button = utils.createElement('button', utils.extend(utils.getAttributesFromSelector(config.selectors.buttons.loop), {
+ var button = utils.createElement('button', utils.extend(utils.getAttributesFromSelector(player.config.selectors.buttons.loop), {
type: 'button',
- class: config.classes.control,
+ class: player.config.classes.control,
'data-plyr-loop-action': option
- }), config.i18n[option]);
+ }), player.config.i18n[option]);
if (utils.inArray(['start', 'end'], option)) {
var badge = createBadge('00:00');
@@ -1926,7 +1930,7 @@
// Add the "None" option to turn off captions
tracks.unshift({
language: 'off',
- label: config.i18n.none
+ label: player.config.i18n.none
});
// Generate options
@@ -1934,16 +1938,16 @@
var item = utils.createElement('li');
var label = utils.createElement('label', {
- class: config.classes.control
+ class: player.config.classes.control
});
- var radio = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(config.selectors.inputs.language), {
+ var radio = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(player.config.selectors.inputs.language), {
type: 'radio',
name: 'plyr-language',
value: track.language,
}));
- if (track.language.toLowerCase() === config.captions.language.toLowerCase()) {
+ if (track.language.toLowerCase() === player.config.captions.language.toLowerCase()) {
radio.checked = true;
}
@@ -1972,23 +1976,23 @@
// If there's no captions, bail
if (!utils.is.array(options)) {
- options = config.speed.options;
+ options = player.config.speed.options;
}
options.forEach(function(speed) {
var item = utils.createElement('li');
var label = utils.createElement('label', {
- class: config.classes.control
+ class: player.config.classes.control
});
- var radio = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(config.selectors.inputs.speed), {
+ var radio = utils.createElement('input', utils.extend(utils.getAttributesFromSelector(player.config.selectors.inputs.speed), {
type: 'radio',
name: 'plyr-speed',
value: speed,
}));
- if (speed === config.speed.selected) {
+ if (speed === player.config.speed.selected) {
radio.checked = true;
}
@@ -2005,15 +2009,15 @@
return;
}
- if ((player.type !== 'audio' || config.fullscreen.allowAudio) && config.fullscreen.enabled) {
+ if ((player.type !== 'audio' || player.config.fullscreen.allowAudio) && player.config.fullscreen.enabled) {
// Check for native support
var nativeSupport = support.fullscreen;
- if (nativeSupport || (config.fullscreen.fallback && !utils.inFrame())) {
+ if (nativeSupport || (player.config.fullscreen.fallback && !utils.inFrame())) {
log((nativeSupport ? 'Native' : 'Fallback') + ' fullscreen enabled');
// Add styling hook
- utils.toggleClass(player.elements.container, config.classes.fullscreen.enabled, true);
+ utils.toggleClass(player.elements.container, player.config.classes.fullscreen.enabled, true);
} else {
log('Fullscreen not supported and fallback disabled');
}
@@ -2037,15 +2041,15 @@
// Inject the container
if (!utils.is.htmlElement(player.elements.captions)) {
- player.elements.captions = utils.createElement('div', utils.getAttributesFromSelector(config.selectors.captions));
+ player.elements.captions = utils.createElement('div', utils.getAttributesFromSelector(player.config.selectors.captions));
utils.insertAfter(player.elements.captions, player.elements.wrapper);
}
// Get tracks
- player.captions.tracks = utils.is.array(tracks) ? tracks : player.elements.media.textTracks;
+ player.captions.tracks = utils.is.array(tracks) ? tracks : player.media.textTracks;
// Set the class hook
- utils.toggleClass(player.elements.container, config.classes.captions.enabled, !utils.is.empty(player.captions.tracks));
+ utils.toggleClass(player.elements.container, player.config.classes.captions.enabled, !utils.is.empty(player.captions.tracks));
// If no caption file exists, hide container for caption text
if (utils.is.empty(player.captions.tracks)) {
@@ -2056,7 +2060,7 @@
showCaptions();
if (player.type === 'video') {
- var language = config.captions.language.toLowerCase();
+ var language = player.config.captions.language.toLowerCase();
// Turn off native caption rendering to avoid double captions
[].forEach.call(player.captions.tracks, function(track) {
@@ -2124,22 +2128,6 @@
}
}
- // Select active caption
- function setLanguage(language) {
- // Save config
- if (utils.is.string(language)) {
- config.captions.language = language.toLowerCase();
- } else if (utils.is.event(language)) {
- config.captions.language = language.target.value.toLowerCase();
- }
-
- // Clear caption
- setCaption();
-
- // Re-run setup
- setupCaptions();
- }
-
// Set the current caption
function setCaption(caption) {
if (utils.is.htmlElement(player.elements.captions)) {
@@ -2182,51 +2170,21 @@
// Otherwise fall back to the default config
if (!utils.is.boolean(active)) {
- active = config.captions.active;
+ active = player.config.captions.active;
} else {
- config.captions.active = active;
+ player.config.captions.active = active;
}
if (active) {
- utils.toggleClass(player.elements.container, config.classes.captions.active, true);
+ utils.toggleClass(player.elements.container, player.config.classes.captions.active, true);
utils.toggleState(player.elements.buttons.captions, true);
}
}
- // Toggle captions
- function toggleCaptions(show) {
- // If there's no full support, or there's no caption toggle
- if (!player.supported.full || !player.elements.buttons.captions) {
- return;
- }
-
- // If the method is called without parameter, toggle based on current value
- if (!utils.is.boolean(show)) {
- show = (player.elements.container.className.indexOf(config.classes.captions.active) === -1);
- }
-
- // Set global
- player.captions.enabled = show;
-
- // Toggle state
- utils.toggleState(player.elements.buttons.captions, player.captions.enabled);
-
- // Add class hook
- utils.toggleClass(player.elements.container, config.classes.captions.active, player.captions.enabled);
-
- // Trigger an event
- trigger(player.elements.container, player.captions.enabled ? 'captionsenabled' : 'captionsdisabled', true);
-
- // Save captions state to localStorage
- updateStorage({
- captions: player.captions.enabled
- });
- }
-
// Insert controls
function injectControls() {
// Sprite
- if (config.loadSprite) {
+ if (player.config.loadSprite) {
var iconUrl = getIconUrl();
// Only load external sprite using AJAX
@@ -2238,12 +2196,6 @@
}
}
- // Larger overlaid play button
- if (utils.inArray(config.controls, 'play-large')) {
- player.elements.buttons.playLarge = createButton('play-large');
- player.elements.container.appendChild(player.elements.buttons.playLarge);
- }
-
// Create a unique ID
player.id = Math.floor(Math.random() * 10000);
@@ -2251,22 +2203,22 @@
var controls = null;
// HTML passed as the option
- if (utils.is.string(config.controls)) {
- controls = config.controls;
+ if (utils.is.string(player.config.controls)) {
+ controls = player.config.controls;
}
// A custom function to build controls
// The function can return a HTMLElement or String
- else if (utils.is.function(config.controls)) {
- controls = config.controls({
+ else if (utils.is.function(player.config.controls)) {
+ controls = player.config.controls({
id: player.id,
- seektime: config.seekTime
+ seektime: player.config.seekTime
});
}
// Create controls
else {
controls = createControls({
id: player.id,
- seektime: config.seekTime,
+ seektime: player.config.seekTime,
speed: getSpeedLabel(),
// TODO: Get current quality
quality: 'HD',
@@ -2280,8 +2232,8 @@
var target;
// Inject to custom location
- if (utils.is.string(config.selectors.controls.container)) {
- target = document.querySelector(config.selectors.controls.container);
+ if (utils.is.string(player.config.selectors.controls.container)) {
+ target = document.querySelector(player.config.selectors.controls.container);
}
// Inject into the container by default
@@ -2302,14 +2254,14 @@
}
// Setup tooltips
- if (config.tooltips.controls) {
- var labels = getElements([config.selectors.controls.wrapper, ' ', config.selectors.labels, ' .', config.classes.hidden].join(''));
+ if (player.config.tooltips.controls) {
+ var labels = getElements([player.config.selectors.controls.wrapper, ' ', player.config.selectors.labels, ' .', player.config.classes.hidden].join(''));
for (var i = labels.length - 1; i >= 0; i--) {
var label = labels[i];
- utils.toggleClass(label, config.classes.hidden, false);
- utils.toggleClass(label, config.classes.tooltip, true);
+ utils.toggleClass(label, player.config.classes.hidden, false);
+ utils.toggleClass(label, player.config.classes.tooltip, true);
}
}
}
@@ -2318,44 +2270,44 @@
// TODO: Allow settings menus with custom controls (coming soon!)
function findElements() {
try {
- player.elements.controls = getElement(config.selectors.controls.wrapper);
+ player.elements.controls = getElement(player.config.selectors.controls.wrapper);
// Buttons
player.elements.buttons = {
- play: getElements(config.selectors.buttons.play),
- pause: getElement(config.selectors.buttons.pause),
- restart: getElement(config.selectors.buttons.restart),
- rewind: getElement(config.selectors.buttons.rewind),
- forward: getElement(config.selectors.buttons.forward),
- mute: getElement(config.selectors.buttons.mute),
- pip: getElement(config.selectors.buttons.pip),
- airplay: getElement(config.selectors.buttons.airplay),
- settings: getElement(config.selectors.buttons.settings),
- captions: getElement(config.selectors.buttons.captions),
- fullscreen: getElement(config.selectors.buttons.fullscreen)
+ play: getElements(player.config.selectors.buttons.play),
+ pause: getElement(player.config.selectors.buttons.pause),
+ restart: getElement(player.config.selectors.buttons.restart),
+ rewind: getElement(player.config.selectors.buttons.rewind),
+ forward: getElement(player.config.selectors.buttons.forward),
+ mute: getElement(player.config.selectors.buttons.mute),
+ pip: getElement(player.config.selectors.buttons.pip),
+ airplay: getElement(player.config.selectors.buttons.airplay),
+ settings: getElement(player.config.selectors.buttons.settings),
+ captions: getElement(player.config.selectors.buttons.captions),
+ fullscreen: getElement(player.config.selectors.buttons.fullscreen)
};
// Progress
- player.elements.progress = getElement(config.selectors.progress);
+ player.elements.progress = getElement(player.config.selectors.progress);
// Inputs
player.elements.inputs = {
- seek: getElement(config.selectors.inputs.seek),
- volume: getElement(config.selectors.inputs.volume),
+ seek: getElement(player.config.selectors.inputs.seek),
+ volume: getElement(player.config.selectors.inputs.volume),
};
// Display
player.elements.display = {
- buffer: getElement(config.selectors.display.buffer),
- played: getElement(config.selectors.display.played),
- volume: getElement(config.selectors.display.volume),
- duration: getElement(config.selectors.display.duration),
- currentTime: getElement(config.selectors.display.currentTime),
+ buffer: getElement(player.config.selectors.display.buffer),
+ played: getElement(player.config.selectors.display.played),
+ volume: getElement(player.config.selectors.display.volume),
+ duration: getElement(player.config.selectors.display.duration),
+ currentTime: getElement(player.config.selectors.display.currentTime),
};
// Seek tooltip
if (utils.is.htmlElement(player.elements.progress)) {
- player.elements.display.seekTooltip = player.elements.progress.querySelector('.' + config.classes.tooltip);
+ player.elements.display.seekTooltip = player.elements.progress.querySelector('.' + player.config.classes.tooltip);
}
return true;
@@ -2372,29 +2324,29 @@
// Toggle style hook
function toggleStyleHook() {
- utils.toggleClass(player.elements.container, config.selectors.container.replace('.', ''), player.supported.full);
+ utils.toggleClass(player.elements.container, player.config.selectors.container.replace('.', ''), player.supported.full);
}
// Toggle native controls
function toggleNativeControls(toggle) {
if (toggle && utils.inArray(types.html5, player.type)) {
- player.elements.media.setAttribute('controls', '');
+ player.media.setAttribute('controls', '');
} else {
- player.elements.media.removeAttribute('controls');
+ player.media.removeAttribute('controls');
}
}
// Setup aria attribute for play and iframe title
function setTitle(iframe) {
// Find the current text
- var label = config.i18n.play;
+ var label = player.config.i18n.play;
// If there's a media title set, use that for the label
- if (utils.is.string(config.title) && !utils.is.empty(config.title)) {
- label += ', ' + config.title;
+ if (utils.is.string(player.config.title) && !utils.is.empty(player.config.title)) {
+ label += ', ' + player.config.title;
// Set container label
- player.elements.container.setAttribute('aria-label', config.title);
+ player.elements.container.setAttribute('aria-label', player.config.title);
}
// If there's a play button, set label
@@ -2410,8 +2362,8 @@
// Set iframe title
// https://github.com/sampotts/plyr/issues/124
if (utils.is.htmlElement(iframe)) {
- var title = utils.is.string(config.title) && !utils.is.empty(config.title) ? config.title : 'video';
- iframe.setAttribute('title', config.i18n.frameTitle.replace('{title}', title));
+ var title = utils.is.string(player.config.title) && !utils.is.empty(player.config.title) ? player.config.title : 'video';
+ iframe.setAttribute('title', player.config.i18n.frameTitle.replace('{title}', title));
}
}
@@ -2421,7 +2373,7 @@
player.storage = {};
// Bail if we don't have localStorage support or it's disabled
- if (!support.storage || !config.storage.enabled) {
+ if (!support.storage || !player.config.storage.enabled) {
return;
}
@@ -2430,7 +2382,7 @@
window.localStorage.removeItem('plyr-volume');
// load value from the current key
- value = window.localStorage.getItem(config.storage.key);
+ value = window.localStorage.getItem(player.config.storage.key);
if (!value) {
// Key wasn't set (or had been cleared), move along
@@ -2451,7 +2403,7 @@
// Save a value back to local storage
function updateStorage(value) {
// Bail if we don't have localStorage support or it's disabled
- if (!support.storage || !config.storage.enabled) {
+ if (!support.storage || !player.config.storage.enabled) {
return;
}
@@ -2459,52 +2411,52 @@
utils.extend(player.storage, value);
// Update storage
- window.localStorage.setItem(config.storage.key, JSON.stringify(player.storage));
+ window.localStorage.setItem(player.config.storage.key, JSON.stringify(player.storage));
}
// Setup media
function setupMedia() {
// If there's no media, bail
- if (!player.elements.media) {
+ if (!player.media) {
warn('No media element found!');
return;
}
if (player.supported.full) {
// Add type class
- utils.toggleClass(player.elements.container, config.classes.type.replace('{0}', player.type), true);
+ utils.toggleClass(player.elements.container, player.config.classes.type.replace('{0}', player.type), true);
// Add video class for embeds
// This will require changes if audio embeds are added
if (utils.inArray(types.embed, player.type)) {
- utils.toggleClass(player.elements.container, config.classes.type.replace('{0}', 'video'), true);
+ utils.toggleClass(player.elements.container, player.config.classes.type.replace('{0}', 'video'), true);
}
// Check for picture-in-picture support
- utils.toggleClass(player.elements.container, config.classes.pip.enabled, support.pip && player.type === 'video');
+ utils.toggleClass(player.elements.container, player.config.classes.pip.enabled, support.pip && player.type === 'video');
// Check for airplay support
- utils.toggleClass(player.elements.container, config.classes.airplay.enabled, support.airplay && utils.inArray(types.html5, player.type));
+ utils.toggleClass(player.elements.container, player.config.classes.airplay.enabled, support.airplay && utils.inArray(types.html5, player.type));
// If there's no autoplay attribute, assume the video is stopped and add state class
- utils.toggleClass(player.elements.container, config.classes.stopped, config.autoplay);
+ utils.toggleClass(player.elements.container, player.config.classes.stopped, player.config.autoplay);
// Add iOS class
- utils.toggleClass(player.elements.container, config.classes.isIos, player.browser.isIos);
+ utils.toggleClass(player.elements.container, player.config.classes.isIos, player.browser.isIos);
// Add touch class
- utils.toggleClass(player.elements.container, config.classes.isTouch, support.touch);
+ utils.toggleClass(player.elements.container, player.config.classes.isTouch, support.touch);
}
// Inject the player wrapper
if (utils.inArray(['video', 'youtube', 'vimeo'], player.type)) {
// Create the wrapper div
player.elements.wrapper = utils.createElement('div', {
- class: config.classes.videoWrapper
+ class: player.config.classes.video
});
// Wrap the video in a container
- utils.wrap(player.elements.media, player.elements.wrapper);
+ utils.wrap(player.media, player.elements.wrapper);
}
// Embeds
@@ -2536,18 +2488,18 @@
}
// Add embed class for responsive
- utils.toggleClass(player.elements.wrapper, config.classes.embedWrapper, true);
+ utils.toggleClass(player.elements.wrapper, player.config.classes.embed, true);
if (player.type === 'youtube') {
// Set ID
- player.elements.media.setAttribute('id', id);
+ player.media.setAttribute('id', id);
// Setup API
if (utils.is.object(window.YT)) {
youTubeReady(mediaId);
} else {
// Load the API
- utils.injectScript(config.urls.youtube.api);
+ utils.injectScript(player.config.urls.youtube.api);
// Setup callback for the API
window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];
@@ -2566,11 +2518,11 @@
}
} else if (player.type === 'vimeo') {
// Set ID
- player.elements.media.setAttribute('id', id);
+ player.media.setAttribute('id', id);
// Load the API if not already
if (!utils.is.object(window.Vimeo)) {
- utils.injectScript(config.urls.vimeo.api);
+ utils.injectScript(player.config.urls.vimeo.api);
// Wait for fragaloop load
var vimeoTimer = window.setInterval(function() {
@@ -2598,11 +2550,11 @@
'id': id
});
- player.elements.media.appendChild(soundCloud);
+ player.media.appendChild(soundCloud);
// Load the API if not already
if (!window.SC) {
- utils.injectScript(config.urls.soundcloud.api);
+ utils.injectScript(player.config.urls.soundcloud.api);
}
// Wait for SC load
@@ -2631,15 +2583,15 @@
function youTubeReady(videoId) {
// Setup instance
// https://developers.google.com/youtube/iframe_api_reference
- player.embed = new window.YT.Player(player.elements.media.id, {
+ player.embed = new window.YT.Player(player.media.id, {
videoId: videoId,
playerVars: {
- autoplay: (config.autoplay ? 1 : 0),
+ autoplay: (player.config.autoplay ? 1 : 0),
controls: (player.supported.full ? 0 : 1),
rel: 0,
showinfo: 0,
iv_load_policy: 3,
- cc_load_policy: (config.captions.active ? 1 : 0),
+ cc_load_policy: (player.config.captions.active ? 1 : 0),
cc_lang_pref: 'en',
wmode: 'transparent',
modestbranding: 1,
@@ -2669,22 +2621,22 @@
var instance = event.target;
// Create a faux HTML5 API using the YouTube API
- player.elements.media.play = function() {
+ player.media.play = function() {
instance.playVideo();
- player.elements.media.paused = false;
+ player.media.paused = false;
};
- player.elements.media.pause = function() {
+ player.media.pause = function() {
instance.pauseVideo();
- player.elements.media.paused = true;
+ player.media.paused = true;
};
- player.elements.media.stop = function() {
+ player.media.stop = function() {
instance.stopVideo();
- player.elements.media.paused = true;
+ player.media.paused = true;
};
- player.elements.media.duration = instance.getDuration();
- player.elements.media.paused = true;
- player.elements.media.currentTime = 0;
- player.elements.media.muted = instance.isMuted();
+ player.media.duration = instance.getDuration();
+ player.media.paused = true;
+ player.media.currentTime = 0;
+ player.media.muted = instance.isMuted();
// Get available speeds
var speed = instance.getPlaybackRate();
@@ -2693,21 +2645,21 @@
console.warn(speed, speedOptions);
// Set title
- config.title = instance.getVideoData().title;
+ player.config.title = instance.getVideoData().title;
// Set the tabindex
if (player.supported.full) {
- player.elements.media.setAttribute('tabindex', -1);
+ player.media.setAttribute('tabindex', -1);
}
// Update UI
embedReady();
// Trigger timeupdate
- trigger(player.elements.media, 'timeupdate');
+ trigger(player.media, 'timeupdate');
// Trigger timeupdate
- trigger(player.elements.media, 'durationchange');
+ trigger(player.media, 'durationchange');
// Reset timer
window.clearInterval(timers.buffering);
@@ -2715,22 +2667,22 @@
// Setup buffering
timers.buffering = window.setInterval(function() {
// Get loaded % from YouTube
- player.elements.media.buffered = instance.getVideoLoadedFraction();
+ player.media.buffered = instance.getVideoLoadedFraction();
// Trigger progress only when we actually buffer something
- if (player.elements.media.lastBuffered === null || player.elements.media.lastBuffered < player.elements.media.buffered) {
- trigger(player.elements.media, 'progress');
+ if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {
+ trigger(player.media, 'progress');
}
// Set last buffer point
- player.elements.media.lastBuffered = player.elements.media.buffered;
+ player.media.lastBuffered = player.media.buffered;
// Bail if we're at 100%
- if (player.elements.media.buffered === 1) {
+ if (player.media.buffered === 1) {
window.clearInterval(timers.buffering);
// Trigger event
- trigger(player.elements.media, 'canplaythrough');
+ trigger(player.media, 'canplaythrough');
}
}, 200);
},
@@ -2751,43 +2703,43 @@
switch (event.data) {
case 0:
// YouTube doesn't support loop for a single video, so mimick it.
- if (config.loop.active) {
+ if (player.config.loop.active) {
// YouTube needs a call to `stopVideo` before playing again
instance.stopVideo();
instance.playVideo();
break;
}
- player.elements.media.paused = true;
- trigger(player.elements.media, 'ended');
+ player.media.paused = true;
+ trigger(player.media, 'ended');
break;
case 1:
- player.elements.media.paused = false;
+ player.media.paused = false;
// If we were seeking, fire seeked event
- if (player.elements.media.seeking) {
- trigger(player.elements.media, 'seeked');
+ if (player.media.seeking) {
+ trigger(player.media, 'seeked');
}
- player.elements.media.seeking = false;
- trigger(player.elements.media, 'play');
- trigger(player.elements.media, 'playing');
+ player.media.seeking = false;
+ trigger(player.media, 'play');
+ trigger(player.media, 'playing');
// Poll to get playback progress
timers.playing = window.setInterval(function() {
// Set the current time
- player.elements.media.currentTime = instance.getCurrentTime();
+ player.media.currentTime = instance.getCurrentTime();
// Trigger timeupdate
- trigger(player.elements.media, 'timeupdate');
+ trigger(player.media, 'timeupdate');
}, 100);
// Check duration again due to YouTube bug
// https://github.com/sampotts/plyr/issues/374
// https://code.google.com/p/gdata-issues/issues/detail?id=8690
- if (player.elements.media.duration !== instance.getDuration()) {
- player.elements.media.duration = instance.getDuration();
- trigger(player.elements.media, 'durationchange');
+ if (player.media.duration !== instance.getDuration()) {
+ player.media.duration = instance.getDuration();
+ trigger(player.media, 'durationchange');
}
// Get quality
@@ -2798,8 +2750,8 @@
break;
case 2:
- player.elements.media.paused = true;
- trigger(player.elements.media, 'pause');
+ player.media.paused = true;
+ trigger(player.media, 'pause');
break;
}
@@ -2815,47 +2767,47 @@
function vimeoReady(mediaId) {
// Setup instance
// https://github.com/vimeo/player.js
- player.embed = new window.Vimeo.Player(player.elements.media, {
+ player.embed = new window.Vimeo.Player(player.media, {
id: mediaId,
- loop: config.loop.active,
- autoplay: config.autoplay,
+ loop: player.config.loop.active,
+ autoplay: player.config.autoplay,
byline: false,
portrait: false,
title: false
});
// Create a faux HTML5 API using the Vimeo API
- player.elements.media.play = function() {
+ player.media.play = function() {
player.embed.play();
- player.elements.media.paused = false;
+ player.media.paused = false;
};
- player.elements.media.pause = function() {
+ player.media.pause = function() {
player.embed.pause();
- player.elements.media.paused = true;
+ player.media.paused = true;
};
- player.elements.media.stop = function() {
+ player.media.stop = function() {
player.embed.stop();
- player.elements.media.paused = true;
+ player.media.paused = true;
};
- player.elements.media.paused = true;
- player.elements.media.currentTime = 0;
+ player.media.paused = true;
+ player.media.currentTime = 0;
// Update UI
embedReady();
player.embed.getCurrentTime().then(function(value) {
- player.elements.media.currentTime = value;
+ player.media.currentTime = value;
// Trigger timeupdate
- trigger(player.elements.media, 'timeupdate');
+ trigger(player.media, 'timeupdate');
});
player.embed.getDuration().then(function(value) {
- player.elements.media.duration = value;
+ player.media.duration = value;
// Trigger timeupdate
- trigger(player.elements.media, 'durationchange');
+ trigger(player.media, 'durationchange');
});
// Get captions
@@ -2864,8 +2816,8 @@
setupCaptions(tracks);
// TODO: Captions
- if (config.captions.active) {
- player.embed.enableTextTrack(config.captions.language.toLowerCase());
+ if (player.config.captions.active) {
+ player.embed.enableTextTrack(player.config.captions.language.toLowerCase());
}
});
@@ -2888,41 +2840,41 @@
});
player.embed.on('play', function() {
- player.elements.media.paused = false;
- trigger(player.elements.media, 'play');
- trigger(player.elements.media, 'playing');
+ player.media.paused = false;
+ trigger(player.media, 'play');
+ trigger(player.media, 'playing');
});
player.embed.on('pause', function() {
- player.elements.media.paused = true;
- trigger(player.elements.media, 'pause');
+ player.media.paused = true;
+ trigger(player.media, 'pause');
});
player.embed.on('timeupdate', function(data) {
- player.elements.media.seeking = false;
- player.elements.media.currentTime = data.seconds;
- trigger(player.elements.media, 'timeupdate');
+ player.media.seeking = false;
+ player.media.currentTime = data.seconds;
+ trigger(player.media, 'timeupdate');
});
player.embed.on('progress', function(data) {
- player.elements.media.buffered = data.percent;
- trigger(player.elements.media, 'progress');
+ player.media.buffered = data.percent;
+ trigger(player.media, 'progress');
if (parseInt(data.percent) === 1) {
// Trigger event
- trigger(player.elements.media, 'canplaythrough');
+ trigger(player.media, 'canplaythrough');
}
});
player.embed.on('seeked', function() {
- player.elements.media.seeking = false;
- trigger(player.elements.media, 'seeked');
- trigger(player.elements.media, 'play');
+ player.media.seeking = false;
+ trigger(player.media, 'seeked');
+ trigger(player.media, 'play');
});
player.embed.on('ended', function() {
- player.elements.media.paused = true;
- trigger(player.elements.media, 'ended');
+ player.media.paused = true;
+ trigger(player.media, 'ended');
});
}
@@ -2934,219 +2886,75 @@
// Setup on ready
player.embed.bind(window.SC.Widget.Events.READY, function() {
// Create a faux HTML5 API using the Soundcloud API
- player.elements.media.play = function() {
+ player.media.play = function() {
player.embed.play();
- player.elements.media.paused = false;
+ player.media.paused = false;
};
- player.elements.media.pause = function() {
+ player.media.pause = function() {
player.embed.pause();
- player.elements.media.paused = true;
+ player.media.paused = true;
};
- player.elements.media.stop = function() {
+ player.media.stop = function() {
player.embed.seekTo(0);
player.embed.pause();
- player.elements.media.paused = true;
+ player.media.paused = true;
};
- player.elements.media.paused = true;
- player.elements.media.currentTime = 0;
+ player.media.paused = true;
+ player.media.currentTime = 0;
player.embed.getDuration(function(value) {
- player.elements.media.duration = value / 1000;
+ player.media.duration = value / 1000;
// Update UI
embedReady();
});
player.embed.getPosition(function(value) {
- player.elements.media.currentTime = value;
+ player.media.currentTime = value;
// Trigger timeupdate
- trigger(player.elements.media, 'timeupdate');
+ trigger(player.media, 'timeupdate');
});
player.embed.bind(window.SC.Widget.Events.PLAY, function() {
- player.elements.media.paused = false;
- trigger(player.elements.media, 'play');
- trigger(player.elements.media, 'playing');
+ player.media.paused = false;
+ trigger(player.media, 'play');
+ trigger(player.media, 'playing');
});
player.embed.bind(window.SC.Widget.Events.PAUSE, function() {
- player.elements.media.paused = true;
- trigger(player.elements.media, 'pause');
+ player.media.paused = true;
+ trigger(player.media, 'pause');
});
player.embed.bind(window.SC.Widget.Events.PLAY_PROGRESS, function(data) {
- player.elements.media.seeking = false;
- player.elements.media.currentTime = data.currentPosition / 1000;
- trigger(player.elements.media, 'timeupdate');
+ player.media.seeking = false;
+ player.media.currentTime = data.currentPosition / 1000;
+ trigger(player.media, 'timeupdate');
});
player.embed.bind(window.SC.Widget.Events.LOAD_PROGRESS, function(data) {
- player.elements.media.buffered = data.loadProgress;
- trigger(player.elements.media, 'progress');
+ player.media.buffered = data.loadProgress;
+ trigger(player.media, 'progress');
if (parseInt(data.loadProgress) === 1) {
// Trigger event
- trigger(player.elements.media, 'canplaythrough');
+ trigger(player.media, 'canplaythrough');
}
});
player.embed.bind(window.SC.Widget.Events.FINISH, function() {
- player.elements.media.paused = true;
- trigger(player.elements.media, 'ended');
+ player.media.paused = true;
+ trigger(player.media, 'ended');
});
});
}
- // Play media
- function play() {
- if ('play' in player.elements.media) {
- player.elements.media.play();
- }
- }
-
- // Pause media
- function pause() {
- if ('pause' in player.elements.media) {
- player.elements.media.pause();
- }
- }
-
- // Toggle playback
- function togglePlay(toggle) {
- // True toggle
- if (!utils.is.boolean(toggle)) {
- toggle = player.elements.media.paused;
- }
-
- if (toggle) {
- play();
- } else {
- pause();
- }
-
- return toggle;
- }
-
- // Toggle loop
- // TODO: Set the indicator on load as user may pass loop as config
- function toggleLoop(type) {
- // Set default to be a true toggle
- if (!utils.inArray(['start', 'end', 'all', 'none', 'toggle'], type)) {
- type = 'toggle';
- }
-
- var currentTime = Number(player.elements.media.currentTime);
-
- switch (type) {
- case 'start':
- if (config.loop.end && config.loop.end <= currentTime) {
- config.loop.end = null;
- }
- config.loop.start = currentTime;
- config.loop.indicator.start = player.elements.display.played.value;
- break;
-
- case 'end':
- if (config.loop.start >= currentTime) {
- return;
- }
- config.loop.end = currentTime;
- config.loop.indicator.end = player.elements.display.played.value;
- break;
-
- case 'all':
- config.loop.start = 0;
- config.loop.end = player.elements.media.duration - 2;
- config.loop.indicator.start = 0;
- config.loop.indicator.end = 100;
- break;
-
- case 'toggle':
- if (config.loop.active) {
- config.loop.start = 0;
- config.loop.end = null;
- } else {
- config.loop.start = 0;
- config.loop.end = player.elements.media.duration - 2;
- }
- break;
-
- default:
- config.loop.start = 0;
- config.loop.end = null;
- break;
- }
-
- // Check if can loop
- config.loop.active = utils.is.number(config.loop.start) && utils.is.number(config.loop.end);
- var start = updateTimeDisplay(config.loop.start, getElement('[data-plyr-loop="start"]'));
- var end = null;
-
- if (utils.is.number(config.loop.end)) {
- // Find the <span> inside button
- end = updateTimeDisplay(config.loop.end, document.querySelector('[data-loop__value="loopout"]'));
- } else {
- // Find the <span> inside button
- //end = document.querySelector('[data-loop__value="loopout"]').innerHTML = '';
- }
-
- if (config.loop.active) {
- // TODO: Improve the design of the loop indicator and put styling in CSS where it's meant to be
- //getElement('[data-menu="loop"]').innerHTML = start + ' - ' + end;
- //getElement(config.selectors.progress.looped).style.position = 'absolute';
- //getElement(config.selectors.progress.looped).style.left = config.loopinPositionPercentage + '%';
- //getElement(config.selectors.progress.looped).style.width = (config.loopoutPositionPercentage - config.loopinPositionPercentage) + '%';
- //getElement(config.selectors.progress.looped).style.background = '#ffbb00';
- //getElement(config.selectors.progress.looped).style.height = '3px';
- //getElement(config.selectors.progress.looped).style.top = '3px';
- //getElement(config.selectors.progress.looped).style['border-radius'] = '100px';
- } else {
- //getElement('[data-menu="loop"]').innerHTML = config.i18n.loopNone;
- //getElement(config.selectors.progress.looped).style.width = '0px';
- }
- }
-
- // Set playback speed
- function setSpeed(speed) {
- // Load speed from storage or default value
- if (utils.is.event(speed)) {
- speed = parseFloat(speed.target.value);
- } else if (!utils.is.number(speed)) {
- speed = parseFloat(player.storage.speed || config.speed.selected);
- }
-
- // Set min/max
- if (speed < 0.1) {
- speed = 0.1;
- }
- if (speed > 2.0) {
- speed = 2.0;
- }
-
- if (!utils.is.array(config.speed.options)) {
- warn('Invalid speeds format');
- return;
- }
-
- // Store current speed
- config.speed.selected = speed;
-
- // Set HTML5 speed
- // TODO: set YouTube
- player.elements.media.playbackRate = speed;
-
- // Save speed to localStorage
- updateStorage({
- speed: speed
- });
- }
-
// Get the current speed value
function getSpeedLabel(speed) {
if (!utils.is.number(speed)) {
- speed = config.speed.selected;
+ speed = player.config.speed.selected;
}
if (speed === 1) {
@@ -3156,182 +2964,13 @@
return speed + '&times;';
}
- // Rewind
- function rewind(seekTime) {
- // Use default if needed
- if (!utils.is.number(seekTime)) {
- seekTime = config.seekTime;
- }
- seek(player.elements.media.currentTime - seekTime);
- }
-
- // Fast forward
- function forward(seekTime) {
- // Use default if needed
- if (!utils.is.number(seekTime)) {
- seekTime = config.seekTime;
- }
- seek(player.elements.media.currentTime + seekTime);
- }
-
- // Seek to time
- // The input parameter can be an event or a number
- function seek(input) {
- var targetTime = 0;
- var paused = player.elements.media.paused;
- var duration = getDuration();
-
- if (utils.is.number(input)) {
- targetTime = input;
- } else if (utils.is.event(input) && utils.inArray(['input', 'change'], input.type)) {
- // It's the seek slider
- // Seek to the selected time
- targetTime = ((input.target.value / input.target.max) * duration);
- }
-
- // Normalise targetTime
- if (targetTime < 0) {
- targetTime = 0;
- } else if (targetTime > duration) {
- targetTime = duration;
- }
-
- // Update seek range and progress
- updateSeekDisplay(targetTime);
-
- // Set the current time
- // Try/catch incase the media isn't set and we're calling seek() from source() and IE moans
- try {
- player.elements.media.currentTime = targetTime.toFixed(4);
- } catch (e) {}
-
- // Embeds
- if (utils.inArray(types.embed, player.type)) {
- switch (player.type) {
- case 'youtube':
- player.embed.seekTo(targetTime);
- break;
-
- case 'vimeo':
- // Round to nearest second for vimeo
- player.embed.setCurrentTime(targetTime.toFixed(0));
- break;
-
- case 'soundcloud':
- player.embed.seekTo(targetTime * 1000);
- break;
- }
-
- if (paused) {
- pause();
- }
-
- // Trigger timeupdate
- trigger(player.elements.media, 'timeupdate');
-
- // Set seeking flag
- player.elements.media.seeking = true;
-
- // Trigger seeking
- trigger(player.elements.media, 'seeking');
- }
-
- // Logging
- log('Seeking to ' + player.elements.media.currentTime + ' seconds');
- }
-
- // Get the duration (or custom if set)
- function getDuration() {
- // It should be a number, but parse it just incase
- var duration = parseInt(config.duration);
-
- // True duration
- var mediaDuration = 0;
-
- // Only if duration available
- if (player.elements.media.duration !== null && !isNaN(player.elements.media.duration)) {
- mediaDuration = player.elements.media.duration;
- }
-
- // If custom duration is funky, use regular duration
- return (isNaN(duration) ? mediaDuration : duration);
- }
-
// Check playing state
function checkPlaying() {
- utils.toggleClass(player.elements.container, config.classes.playing, !player.elements.media.paused);
+ utils.toggleClass(player.elements.container, player.config.classes.playing, !player.media.paused);
- utils.toggleClass(player.elements.container, config.classes.stopped, player.elements.media.paused);
+ utils.toggleClass(player.elements.container, player.config.classes.stopped, player.media.paused);
- toggleControls(player.elements.media.paused);
- }
-
- // Save scroll position
- function saveScrollPosition() {
- scroll = {
- x: window.pageXOffset || 0,
- y: window.pageYOffset || 0
- };
- }
-
- // Restore scroll position
- function restoreScrollPosition() {
- window.scrollTo(scroll.x, scroll.y);
- }
-
- // Toggle fullscreen
- function toggleFullscreen(event) {
- // Check for native support
- var nativeSupport = support.fullscreen;
-
- if (nativeSupport) {
- // If it's a fullscreen change event, update the UI
- if (event && event.type === fullscreen.eventType) {
- player.fullscreen.active = fullscreen.isFullScreen(player.elements.container);
- } else {
- // Else it's a user request to enter or exit
- if (!fullscreen.isFullScreen(player.elements.container)) {
- // Save scroll position
- saveScrollPosition();
-
- // Request full screen
- fullscreen.requestFullScreen(player.elements.container);
- } else {
- // Bail from fullscreen
- fullscreen.cancelFullScreen();
- }
-
- // Check if we're actually full screen (it could fail)
- player.fullscreen.active = fullscreen.isFullScreen(player.elements.container);
-
- return;
- }
- } else {
- // Otherwise, it's a simple toggle
- player.fullscreen.active = !player.fullscreen.active;
-
- // Bind/unbind escape key
- document.body.style.overflow = player.fullscreen.active ? 'hidden' : '';
- }
-
- // Set class hook
- utils.toggleClass(player.elements.container, config.classes.fullscreen.active, player.fullscreen.active);
-
- // Trap focus
- focusTrap(player.fullscreen.active);
-
- // Set button state
- if (player.elements.buttons && player.elements.buttons.fullscreen) {
- utils.toggleState(player.elements.buttons.fullscreen, player.fullscreen.active);
- }
-
- // Trigger an event
- trigger(player.elements.container, player.fullscreen.active ? 'enterfullscreen' : 'exitfullscreen', true);
-
- // Restore scroll position
- if (!player.fullscreen.active && nativeSupport) {
- restoreScrollPosition();
- }
+ player.toggleControls(player.media.paused);
}
// Show/hide menu
@@ -3471,131 +3110,10 @@
pane.removeAttribute('tabindex');
}
- // Mute
- function toggleMute(muted) {
- // If the method is called without parameter, toggle based on current value
- if (!utils.is.boolean(muted)) {
- muted = !player.elements.media.muted;
- }
-
- // Set button state
- utils.toggleState(player.elements.buttons.mute, muted);
-
- // Set mute on the player
- player.elements.media.muted = muted;
-
- // If volume is 0 after unmuting, set to default
- if (player.elements.media.volume === 0) {
- setVolume(config.volume);
- }
-
- // Embeds
- if (utils.inArray(types.embed, player.type)) {
- // YouTube
- switch (player.type) {
- case 'youtube':
- player.embed[player.elements.media.muted ? 'mute' : 'unMute']();
- break;
-
- case 'vimeo':
- case 'soundcloud':
- player.embed.setVolume(player.elements.media.muted ? 0 : parseFloat(config.volume / 10));
- break;
- }
-
- // Trigger volumechange for embeds
- trigger(player.elements.media, 'volumechange');
- }
- }
-
- // Set volume
- function setVolume(volume) {
- var max = 10;
- var min = 0;
-
- // If volume is event, get from input
- if (utils.is.event(volume)) {
- volume = volume.target.value;
- }
-
- // Load volume from storage if no value specified
- if (utils.is.undefined(volume)) {
- volume = player.storage.volume;
- }
-
- // Use config if all else fails
- if (volume === null || isNaN(volume)) {
- volume = config.volume;
- }
-
- // Maximum is volumeMax
- if (volume > max) {
- volume = max;
- }
- // Minimum is volumeMin
- if (volume < min) {
- volume = min;
- }
-
- // Set the player volume
- player.elements.media.volume = parseFloat(volume / max);
-
- // Set the display
- if (player.elements.display.volume) {
- player.elements.display.volume.value = volume;
- }
-
- // Embeds
- if (utils.inArray(types.embed, player.type)) {
- switch (player.type) {
- case 'youtube':
- player.embed.setVolume(player.elements.media.volume * 100);
- break;
-
- case 'vimeo':
- case 'soundcloud':
- player.embed.setVolume(player.elements.media.volume);
- break;
- }
-
- // Trigger volumechange for embeds
- trigger(player.elements.media, 'volumechange');
- }
-
- // Toggle muted state
- if (volume === 0) {
- player.elements.media.muted = true;
- } else if (player.elements.media.muted && volume > 0) {
- toggleMute();
- }
- }
-
- // Increase volume
- function increaseVolume(step) {
- var volume = player.elements.media.muted ? 0 : (player.elements.media.volume * 10);
-
- if (!utils.is.number(step)) {
- step = 1;
- }
-
- setVolume(volume + step);
- }
-
- // Decrease volume
- function decreaseVolume(step) {
- var volume = player.elements.media.muted ? 0 : (player.elements.media.volume * 10);
-
- if (!utils.is.number(step)) {
- step = 1;
- }
-
- setVolume(volume - step);
- }
-
// Update volume UI and storage
function updateVolume() {
// Get the current volume
- var volume = player.elements.media.muted ? 0 : (player.elements.media.volume * 10);
+ var volume = player.media.muted ? 0 : (player.media.volume * 10);
// Update the <input type="range"> if present
if (player.supported.full) {
@@ -3613,7 +3131,7 @@
});
// Toggle class if muted
- utils.toggleClass(player.elements.container, config.classes.muted, (volume === 0));
+ utils.toggleClass(player.elements.container, player.config.classes.muted, (volume === 0));
// Update checkbox for mute state
if (player.supported.full && player.elements.buttons.mute) {
@@ -3623,7 +3141,7 @@
// Check if media is loading
function checkLoading(event) {
- var loading = (event.type === 'waiting');
+ player.loading = (event.type === 'waiting');
// Clear timer
clearTimeout(timers.loading);
@@ -3631,11 +3149,11 @@
// Timer to prevent flicker when seeking
timers.loading = setTimeout(function() {
// Toggle container class hook
- utils.toggleClass(player.elements.container, config.classes.loading, loading);
+ utils.toggleClass(player.elements.container, player.config.classes.loading, player.loading);
// Show controls if loading, hide if done
- toggleControls(loading);
- }, (loading ? 250 : 0));
+ player.toggleControls(player.loading);
+ }, (player.loading ? 250 : 0));
}
// Update <progress> elements
@@ -3644,9 +3162,9 @@
return;
}
- var progress = player.elements.display.played,
- value = 0,
- duration = getDuration();
+ var progress = player.elements.display.played;
+ var value = 0;
+ var duration = player.getDuration();
if (event) {
switch (event.type) {
@@ -3657,7 +3175,7 @@
return;
}
- value = utils.getPercentage(player.elements.media.currentTime, duration);
+ value = utils.getPercentage(player.media.currentTime, duration);
// Set seek range value only if it's a 'natural' time event
if (event.type === 'timeupdate' && player.elements.inputs.seek) {
@@ -3671,7 +3189,7 @@
case 'progress':
progress = player.elements.display.buffer;
value = (function() {
- var buffered = player.elements.media.buffered;
+ var buffered = player.media.buffered;
if (buffered && buffered.length) {
// HTML5
@@ -3688,8 +3206,8 @@
}
}
- if (utils.is.number(config.loop.start) && utils.is.number(config.loop.end) && player.elements.media.currentTime >= config.loop.end) {
- seek(config.loop.start);
+ if (utils.is.number(player.config.loop.start) && utils.is.number(player.config.loop.end) && player.media.currentTime >= player.config.loop.end) {
+ player.seek(player.config.loop.start);
}
setProgress(progress, value);
@@ -3741,9 +3259,10 @@
var secs = parseInt(time % 60);
var mins = parseInt((time / 60) % 60);
var hours = parseInt(((time / 60) / 60) % 60);
+ var duration = player.getDuration();
// Do we need to display hours?
- var displayHours = (parseInt(((getDuration() / 60) / 60) % 60) > 0);
+ var displayHours = (parseInt(((duration / 60) / 60) % 60) > 0);
// Ensure it's two digits. For example, 03 rather than 3.
secs = ('0' + secs).slice(-2);
@@ -3766,10 +3285,10 @@
}
// Determine duration
- var duration = getDuration() || 0;
+ var duration = player.getDuration() || 0;
// If there's only one time display, display duration there
- if (!player.elements.display.duration && config.displayDuration && player.elements.media.paused) {
+ if (!player.elements.display.duration && player.config.displayDuration && player.media.paused) {
updateTimeDisplay(duration, player.elements.display.currentTime);
}
@@ -3785,10 +3304,10 @@
// Handle time change event
function timeUpdate(event) {
// Duration
- updateTimeDisplay(player.elements.media.currentTime, player.elements.display.currentTime);
+ updateTimeDisplay(player.media.currentTime, player.elements.display.currentTime);
// Ignore updates while seeking
- if (event && event.type === 'timeupdate' && player.elements.media.seeking) {
+ if (event && event.type === 'timeupdate' && player.media.seeking) {
return;
}
@@ -3803,8 +3322,8 @@
time = 0;
}
- var duration = getDuration(),
- value = utils.getPercentage(time, duration);
+ var duration = player.getDuration();
+ var value = utils.getPercentage(time, duration);
// Update progress
if (player.elements.progress && player.elements.display.played) {
@@ -3819,17 +3338,17 @@
// Update hover tooltip for seeking
function updateSeekTooltip(event) {
- var duration = getDuration();
+ var duration = player.getDuration();
// Bail if setting not true
- if (!config.tooltips.seek || !utils.is.htmlElement(player.elements.inputs.seek) || !utils.is.htmlElement(player.elements.display.seekTooltip) || duration === 0) {
+ if (!player.config.tooltips.seek || !utils.is.htmlElement(player.elements.inputs.seek) || !utils.is.htmlElement(player.elements.display.seekTooltip) || duration === 0) {
return;
}
// Calculate percentage
var clientRect = player.elements.inputs.seek.getBoundingClientRect();
var percent = 0;
- var visible = config.classes.tooltip + '--visible';
+ var visible = player.config.classes.tooltip + '--visible';
// Determine percentage, if already visible
if (utils.is.event(event)) {
@@ -3862,108 +3381,6 @@
}
}
- // Show the player controls in fullscreen mode
- function toggleControls(toggle) {
- // Don't hide if config says not to, it's audio, or not ready or loading
- if (!config.hideControls || player.type === 'audio') {
- return;
- }
-
- var delay = 0;
- var isEnterFullscreen = false;
- var show = toggle;
- var loading = utils.hasClass(player.elements.container, config.classes.loading);
-
- // Default to false if no boolean
- if (!utils.is.boolean(toggle)) {
- if (toggle && toggle.type) {
- // Is the enter fullscreen event
- isEnterFullscreen = (toggle.type === 'enterfullscreen');
-
- // Whether to show controls
- show = utils.inArray(['mousemove', 'touchstart', 'mouseenter', 'focus'], toggle.type);
-
- // Delay hiding on move events
- if (utils.inArray(['mousemove', 'touchmove'], toggle.type)) {
- delay = 2000;
- }
-
- // Delay a little more for keyboard users
- if (toggle.type === 'focus') {
- delay = 3000;
- }
- } else {
- show = utils.hasClass(player.elements.container, config.classes.hideControls);
- }
- }
-
- // Clear timer every movement
- window.clearTimeout(timers.hover);
-
- // If the mouse is not over the controls, set a timeout to hide them
- if (show || player.elements.media.paused || loading) {
- utils.toggleClass(player.elements.container, config.classes.hideControls, false);
-
- // Always show controls when paused or if touch
- if (player.elements.media.paused || loading) {
- return;
- }
-
- // Delay for hiding on touch
- if (support.touch) {
- delay = 3000;
- }
- }
-
- // If toggle is false or if we're playing (regardless of toggle),
- // then set the timer to hide the controls
- if (!show || !player.elements.media.paused) {
- timers.hover = window.setTimeout(function() {
- // If the mouse is over the controls (and not entering fullscreen), bail
- if ((player.elements.controls.pressed || player.elements.controls.hover) && !isEnterFullscreen) {
- return;
- }
-
- utils.toggleClass(player.elements.container, config.classes.hideControls, true);
- }, delay);
- }
- }
-
- // Add common function to retrieve media source
- function source(source) {
- // If not null or undefined, parse it
- if (!utils.is.undefined(source)) {
- updateSource(source);
- return;
- }
-
- // Return the current source
- var url;
- switch (player.type) {
- case 'youtube':
- url = player.embed.getVideoUrl();
- break;
-
- case 'vimeo':
- player.embed.getVideoUrl.then(function(value) {
- url = value;
- });
- break;
-
- case 'soundcloud':
- player.embed.getCurrentSound(function(object) {
- url = object.permalink_url;
- });
- break;
-
- default:
- url = player.elements.media.currentSrc;
- break;
- }
-
- return url || '';
- }
-
// Update source
// Sources are not checked for support so be careful
function updateSource(source) {
@@ -3973,10 +3390,10 @@
}
// Remove ready class hook
- utils.toggleClass(player.elements.container, config.classes.ready, false);
+ player.ready = false;
- // Pause playback
- pause();
+ // Stop playback
+ player.stop();
// Update seek range and progress
updateSeekDisplay();
@@ -4021,56 +3438,56 @@
}
// Check for support
- player.supported = utils.checkSupport(player.type, config.inline);
+ player.supported = utils.checkSupport(player.type, player.config.inline);
// Create new markup
switch (player.type) {
case 'video':
- player.elements.media = utils.createElement('video');
+ player.media = utils.createElement('video');
break;
case 'audio':
- player.elements.media = utils.createElement('audio');
+ player.media = utils.createElement('audio');
break;
case 'youtube':
case 'vimeo':
case 'soundcloud':
- player.elements.media = utils.createElement('div');
+ player.media = utils.createElement('div');
player.embedId = source.sources[0].src;
break;
}
// Inject the new element
- utils.prependChild(player.elements.container, player.elements.media);
+ utils.prependChild(player.elements.container, player.media);
// Autoplay the new source?
if (utils.is.boolean(source.autoplay)) {
- config.autoplay = source.autoplay;
+ player.config.autoplay = source.autoplay;
}
// Set attributes for audio and video
if (utils.inArray(types.html5, player.type)) {
- if (config.crossorigin) {
- player.elements.media.setAttribute('crossorigin', '');
+ if (player.config.crossorigin) {
+ player.media.setAttribute('crossorigin', '');
}
- if (config.autoplay) {
- player.elements.media.setAttribute('autoplay', '');
+ if (player.config.autoplay) {
+ player.media.setAttribute('autoplay', '');
}
if ('poster' in source) {
- player.elements.media.setAttribute('poster', source.poster);
+ player.media.setAttribute('poster', source.poster);
}
- if (config.loop.active) {
- player.elements.media.setAttribute('loop', '');
+ if (player.config.loop.active) {
+ player.media.setAttribute('loop', '');
}
- if (config.inline) {
- player.elements.media.setAttribute('playsinline', '');
+ if (player.config.inline) {
+ player.media.setAttribute('playsinline', '');
}
}
// Restore class hooks
- utils.toggleClass(player.elements.container, config.classes.fullscreen.active, player.fullscreen.active);
- utils.toggleClass(player.elements.container, config.classes.captions.active, player.captions.enabled);
+ utils.toggleClass(player.elements.container, player.config.classes.fullscreen.active, player.fullscreen.active);
+ utils.toggleClass(player.elements.container, player.config.classes.captions.active, player.captions.enabled);
toggleStyleHook();
// Set new sources for html5
@@ -4089,7 +3506,7 @@
}
// Load HTML5 sources
- player.elements.media.load();
+ player.media.load();
}
// If HTML5 or embed but not fully supported, setupInterface and call ready now
@@ -4102,20 +3519,13 @@
}
// Set aria title and iframe title
- config.title = source.title;
+ player.config.title = source.title;
setTitle();
}
// Destroy instance adn wait for callback
// Vimeo throws a wobbly if you don't wait
- destroy(setup, false);
- }
-
- // Update poster
- function updatePoster(source) {
- if (player.type === 'video') {
- player.elements.media.setAttribute('poster', source);
- }
+ player.destroy(setup, false);
}
// Listen for control events
@@ -4124,8 +3534,8 @@
var inputEvent = (player.browser.isIE ? 'change' : 'input');
// Click play/pause helper
- function _togglePlay() {
- var play = togglePlay();
+ function togglePlay() {
+ var play = player.togglePlay();
// Determine which buttons
var trigger = player.elements.buttons[play ? 'play' : 'pause'];
@@ -4133,7 +3543,7 @@
// Setup focus and tab focus
if (target) {
- var hadTabFocus = utils.hasClass(trigger, config.classes.tabFocus);
+ var hadTabFocus = utils.hasClass(trigger, player.config.classes.tabFocus);
setTimeout(function() {
if (utils.is.htmlElement(target)) {
@@ -4141,8 +3551,8 @@
}
if (hadTabFocus) {
- utils.toggleClass(trigger, config.classes.tabFocus, false);
- utils.toggleClass(target, config.classes.tabFocus, true);
+ utils.toggleClass(trigger, player.config.classes.tabFocus, false);
+ utils.toggleClass(target, player.config.classes.tabFocus, true);
}
}, 100);
}
@@ -4155,19 +3565,19 @@
// Detect tab focus
function checkTabFocus(focused) {
- utils.toggleClass(getElements('.' + config.classes.tabFocus), config.classes.tabFocus, false);
+ utils.toggleClass(getElements('.' + player.config.classes.tabFocus), player.config.classes.tabFocus, false);
if (player.elements.container.contains(focused)) {
- utils.toggleClass(focused, config.classes.tabFocus, true);
+ utils.toggleClass(focused, player.config.classes.tabFocus, true);
}
}
// Keyboard shortcuts
- if (config.keyboardShortcuts.focused) {
+ if (player.config.keyboardShortcuts.focused) {
var last = null;
// Handle global presses
- if (config.keyboardShortcuts.global) {
+ if (player.config.keyboardShortcuts.global) {
utils.on(window, 'keydown keyup', function(event) {
var code = getKeyCode(event);
var focused = utils.getFocusElement();
@@ -4176,7 +3586,7 @@
// Only handle global key press if key is in the allowed keys
// and if the focused element is not editable (e.g. text input)
// and any that accept key input http://webaim.org/techniques/keyboard/
- if (utils.inArray(allowed, code) && (!utils.is.htmlElement(focused) || !utils.matches(focused, config.selectors.editable))) {
+ if (utils.inArray(allowed, code) && (!utils.is.htmlElement(focused) || !utils.matches(focused, player.config.selectors.editable))) {
handleKey(event);
}
}, false);
@@ -4200,7 +3610,7 @@
// Seek by the number keys
function seekByKey() {
// Get current duration
- var duration = player.elements.media.duration;
+ var duration = player.media.duration;
// Bail if we have no duration set
if (!utils.is.number(duration)) {
@@ -4208,7 +3618,7 @@
}
// Divide the max duration into 10th's and times by the number value
- seek((duration / 10) * (code - 48));
+ player.seek((duration / 10) * (code - 48));
}
// Handle the key on keydown
@@ -4253,66 +3663,66 @@
case 75:
// Space and K key
if (!held) {
- _togglePlay();
+ togglePlay();
}
break;
case 38:
// Arrow up
- increaseVolume();
+ player.increaseVolume();
break;
case 40:
// Arrow down
- decreaseVolume();
+ player.decreaseVolume();
break;
case 77:
// M key
if (!held) {
- toggleMute();
+ player.toggleMute();
}
break;
case 39:
// Arrow forward
- forward();
+ player.forward();
break;
case 37:
// Arrow back
- rewind();
+ player.rewind();
break;
case 70:
// F key
- toggleFullscreen();
+ player.toggleFullscreen();
break;
case 67:
// C key
if (!held) {
- toggleCaptions();
+ player.toggleCaptions();
}
break;
case 73:
- toggleLoop('start');
+ player.loop('start');
break;
case 76:
- toggleLoop();
+ player.loop();
break;
case 79:
- toggleLoop('end');
+ player.loop('end');
break;
}
// Escape is handle natively when in full screen
// So we only need to worry about non native
if (!support.fullscreen && player.fullscreen.active && code === 27) {
- toggleFullscreen();
+ player.toggleFullscreen();
}
// Store last code for next cycle
@@ -4332,7 +3742,7 @@
}
});
utils.on(document.body, 'click', function() {
- utils.toggleClass(getElement('.' + config.classes.tabFocus), config.classes.tabFocus, false);
+ utils.toggleClass(getElement('.' + player.config.classes.tabFocus), player.config.classes.tabFocus, false);
});
for (var button in player.elements.buttons) {
var element = player.elements.buttons[button];
@@ -4353,44 +3763,50 @@
}
// Play
- utils.proxy(player.elements.buttons.play, 'click', config.listeners.play, _togglePlay);
- utils.proxy(player.elements.buttons.playLarge, 'click', config.listeners.play, _togglePlay);
+ utils.proxy(player.elements.buttons.play, 'click', player.config.listeners.play, togglePlay);
+ utils.proxy(player.elements.buttons.playLarge, 'click', player.config.listeners.play, togglePlay);
// Pause
- utils.proxy(player.elements.buttons.pause, 'click', config.listeners.pause, _togglePlay);
+ utils.proxy(player.elements.buttons.pause, 'click', player.config.listeners.pause, togglePlay);
// Pause
- utils.proxy(player.elements.buttons.restart, 'click', config.listeners.restart, seek);
+ utils.proxy(player.elements.buttons.restart, 'click', player.config.listeners.restart, function() {
+ player.restart();
+ });
// Rewind
- utils.proxy(player.elements.buttons.rewind, 'click', config.listeners.rewind, rewind);
+ utils.proxy(player.elements.buttons.rewind, 'click', player.config.listeners.rewind, function() {
+ player.rewind();
+ });
// Rewind
- utils.proxy(player.elements.buttons.forward, 'click', config.listeners.forward, forward);
+ utils.proxy(player.elements.buttons.forward, 'click', player.config.listeners.forward, function() {
+ player.forward();
+ });
// Mute
- utils.proxy(player.elements.buttons.mute, 'click', config.listeners.mute, toggleMute);
+ utils.proxy(player.elements.buttons.mute, 'click', player.config.listeners.mute, function() {
+ player.toggleMute();
+ });
// Captions
- utils.proxy(player.elements.buttons.captions, 'click', config.listeners.captions, toggleCaptions);
+ utils.proxy(player.elements.buttons.captions, 'click', player.config.listeners.captions, function() {
+ player.toggleCaptions();
+ });
// Fullscreen
- utils.proxy(player.elements.buttons.fullscreen, 'click', config.listeners.fullscreen, toggleFullscreen);
+ utils.proxy(player.elements.buttons.fullscreen, 'click', player.config.listeners.fullscreen, function(event) {
+ player.toggleFullscreen(event);
+ });
// Picture-in-Picture
- utils.proxy(player.elements.buttons.pip, 'click', config.listeners.pip, function(event) {
- if (!support.pip) {
- return;
- }
- player.elements.media.webkitSetPresentationMode(player.elements.media.webkitPresentationMode === 'picture-in-picture' ? 'inline' : 'picture-in-picture');
+ utils.proxy(player.elements.buttons.pip, 'click', player.config.listeners.pip, function() {
+ player.togglePictureInPicture();
});
// Airplay
- utils.proxy(player.elements.buttons.airplay, 'click', config.listeners.airplay, function(event) {
- if (!support.airplay) {
- return;
- }
- player.elements.media.webkitShowPlaybackTargetPicker();
+ utils.proxy(player.elements.buttons.airplay, 'click', player.config.listeners.airplay, function() {
+ player.airPlay();
});
// Settings menu
@@ -4405,49 +3821,60 @@
// Settings menu items - use event delegation as items are added/removed
utils.on(player.elements.settings.form, 'click', function(event) {
// Settings - Language
- if (utils.matches(event.target, config.selectors.inputs.language)) {
- handlerProxy.call(this, event, config.listeners.language, setLanguage);
+ if (utils.matches(event.target, player.config.selectors.inputs.language)) {
+ handlerProxy.call(this, event, player.config.listeners.language, function() {
+ player.language(event.target.value.toLowerCase());
+ });
}
// Settings - Quality
- else if (utils.matches(event.target, config.selectors.inputs.quality)) {
- handlerProxy.call(this, event, config.listeners.quality, function() {
+ else if (utils.matches(event.target, player.config.selectors.inputs.quality)) {
+ handlerProxy.call(this, event, player.config.listeners.quality, function() {
warn("Set quality");
});
}
// Settings - Speed
- else if (utils.matches(event.target, config.selectors.inputs.speed)) {
- handlerProxy.call(this, event, config.listeners.speed, setSpeed);
+ else if (utils.matches(event.target, player.config.selectors.inputs.speed)) {
+ handlerProxy.call(this, event, player.config.listeners.speed, function() {
+ player.setSpeed(parseFloat(event.target.value));
+ });
}
// Settings - Looping
// TODO: use toggle buttons
- else if (utils.matches(event.target, config.selectors.buttons.loop)) {
- handlerProxy.call(this, event, config.listeners.loop, function() {
+ else if (utils.matches(event.target, player.config.selectors.buttons.loop)) {
+ handlerProxy.call(this, event, player.config.listeners.loop, function() {
// TODO: This should be done in the method itself I think
var value = event.target.getAttribute('data-loop__value') || event.target.getAttribute('data-loop__type');
if (utils.inArray(['start', 'end', 'all', 'none'], value)) {
- toggleLoop(value);
+ player.loop(value);
}
});
}
});
// Seek
- utils.proxy(player.elements.inputs.seek, inputEvent, config.listeners.seek, seek);
+ utils.proxy(player.elements.inputs.seek, inputEvent, player.config.listeners.seek, function(event) {
+ var duration = player.getDuration();
+ player.seek((event.target.value / event.target.max) * duration);
+ });
// Seek
- utils.proxy(player.elements.inputs.volume, inputEvent, config.listeners.volume, setVolume);
+ utils.proxy(player.elements.inputs.volume, inputEvent, player.config.listeners.volume, function() {
+ player.setVolume(event.target.value);
+ });
// Seek tooltip
utils.on(player.elements.progress, 'mouseenter mouseleave mousemove', updateSeekTooltip);
// Toggle controls visibility based on mouse movement
- if (config.hideControls) {
+ if (player.config.hideControls) {
// Toggle controls on mouse events and entering fullscreen
- utils.on(player.elements.container, 'mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen', toggleControls);
+ utils.on(player.elements.container, 'mouseenter mouseleave mousemove touchstart touchend touchcancel touchmove enterfullscreen', function(event) {
+ player.toggleControls(event);
+ });
// Watch for cursor over controls so they don't hide when trying to interact
utils.on(player.elements.controls, 'mouseenter mouseleave', function(event) {
@@ -4461,11 +3888,13 @@
// Focus in/out on controls
// TODO: Check we need capture here
- utils.on(player.elements.controls, 'focus blur', toggleControls, true, true);
+ utils.on(player.elements.controls, 'focus blur', function(event) {
+ player.toggleControls(event);
+ }, true, true);
}
// Mouse wheel for volume
- utils.proxy(player.elements.inputs.volume, 'wheel', config.listeners.volume, function(event) {
+ utils.proxy(player.elements.inputs.volume, 'wheel', player.config.listeners.volume, function(event) {
// Detect "natural" scroll - suppored on OS X Safari only
// Other browsers on OS X will be inverted until support improves
var inverted = event.webkitDirectionInvertedFromDevice;
@@ -4475,10 +3904,10 @@
// Scroll down (or up on natural) to decrease
if (event.deltaY < 0 || event.deltaX > 0) {
if (inverted) {
- decreaseVolume(step);
+ player.decreaseVolume(step);
direction = -1;
} else {
- increaseVolume(step);
+ player.increaseVolume(step);
direction = 1;
}
}
@@ -4486,68 +3915,70 @@
// Scroll up (or down on natural) to increase
if (event.deltaY > 0 || event.deltaX < 0) {
if (inverted) {
- increaseVolume(step);
+ player.increaseVolume(step);
direction = 1;
} else {
- decreaseVolume(step);
+ player.decreaseVolume(step);
direction = -1;
}
}
// Don't break page scrolling at max and min
- if ((direction === 1 && player.elements.media.volume < 1) ||
- (direction === -1 && player.elements.media.volume > 0)) {
+ if ((direction === 1 && player.media.volume < 1) ||
+ (direction === -1 && player.media.volume > 0)) {
event.preventDefault();
}
}, false);
// Handle user exiting fullscreen by escaping etc
if (support.fullscreen) {
- utils.on(document, fullscreen.eventType, toggleFullscreen);
+ utils.on(document, fullscreen.eventType, function(event) {
+ player.toggleFullscreen(event);
+ });
}
}
// Listen for media events
function mediaListeners() {
// Time change on media
- utils.on(player.elements.media, 'timeupdate seeking', timeUpdate);
+ utils.on(player.media, 'timeupdate seeking', timeUpdate);
// Display duration
- utils.on(player.elements.media, 'durationchange loadedmetadata', displayDuration);
+ utils.on(player.media, 'durationchange loadedmetadata', displayDuration);
// Handle the media finishing
- utils.on(player.elements.media, 'ended', function() {
+ utils.on(player.media, 'ended', function() {
// Show poster on end
- if (player.type === 'video' && config.showPosterOnEnd) {
+ if (player.type === 'video' && player.config.showPosterOnEnd) {
// Clear
if (player.type === 'video') {
setCaption();
}
// Restart
- seek();
+ player.restart();
// Re-load media
- player.elements.media.load();
+ player.media.load();
}
});
// Check for buffer progress
- utils.on(player.elements.media, 'progress playing', updateProgress);
+ utils.on(player.media, 'progress playing', updateProgress);
// Handle native mute
- utils.on(player.elements.media, 'volumechange', updateVolume);
+ utils.on(player.media, 'volumechange', updateVolume);
// Handle native play/pause
- utils.on(player.elements.media, 'play pause ended', checkPlaying);
+ utils.on(player.media, 'play pause ended', checkPlaying);
// Loading
- utils.on(player.elements.media, 'waiting canplay seeked', checkLoading);
+ utils.on(player.media, 'waiting canplay seeked', checkLoading);
// Click video
- if (config.clickToPlay && player.type !== 'audio') {
+ if (player.config.clickToPlay && player.type !== 'audio') {
// Re-fetch the wrapper
- var wrapper = getElement('.' + config.classes.videoWrapper);
+ var wrapper = getElement('.' + player.config.classes.video);
// Bail if there's no wrapper (this should never happen)
if (!wrapper) {
@@ -4560,31 +3991,31 @@
// On click play, pause ore restart
utils.on(wrapper, 'click', function() {
// Touch devices will just show controls (if we're hiding controls)
- if (config.hideControls && support.touch && !player.elements.media.paused) {
+ if (player.config.hideControls && support.touch && !player.media.paused) {
return;
}
- if (player.elements.media.paused) {
- play();
- } else if (player.elements.media.ended) {
- seek();
- play();
+ if (player.media.paused) {
+ player.play();
+ } else if (player.media.ended) {
+ player.restart();
+ player.play();
} else {
- pause();
+ player.pause();
}
});
}
// Disable right click
- if (config.disableContextMenu) {
- utils.on(player.elements.media, 'contextmenu', function(event) {
+ if (player.config.disableContextMenu) {
+ utils.on(player.media, 'contextmenu', function(event) {
event.preventDefault();
}, false);
}
// Proxy events to container
// Bubble up key events for Edge
- utils.on(player.elements.media, config.events.concat(['keyup', 'keydown']).join(' '), function(event) {
+ utils.on(player.media, player.config.events.concat(['keyup', 'keydown']).join(' '), function(event) {
trigger(player.elements.container, event.type, true);
});
}
@@ -4597,7 +4028,7 @@
}
// Remove child sources
- var sources = player.elements.media.querySelectorAll('source');
+ var sources = player.media.querySelectorAll('source');
for (var i = 0; i < sources.length; i++) {
utils.removeElement(sources[i]);
}
@@ -4605,84 +4036,17 @@
// Set blank video src attribute
// This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
// Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
- player.elements.media.setAttribute('src', 'https://cdn.selz.com/plyr/blank.mp4');
+ player.media.setAttribute('src', 'https://cdn.selz.com/plyr/blank.mp4');
// Load the new empty source
// This will cancel existing requests
// See https://github.com/sampotts/plyr/issues/174
- player.elements.media.load();
+ player.media.load();
// Debugging
log('Cancelled network requests');
}
- // Destroy an instance
- // Event listeners are removed when elements are removed
- // http://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory
- function destroy(callback, restore) {
- // Type specific stuff
- switch (player.type) {
- case 'youtube':
- // Clear timers
- window.clearInterval(timers.buffering);
- window.clearInterval(timers.playing);
-
- // Destroy YouTube API
- player.embed.destroy();
-
- // Clean up
- cleanUp();
-
- break;
-
- case 'vimeo':
- // Destroy Vimeo API
- // then clean up (wait, to prevent postmessage errors)
- player.embed.unload().then(cleanUp);
-
- // Vimeo does not always return
- window.setTimeout(cleanUp, 200);
-
- break;
-
- case 'video':
- case 'audio':
- // Restore native video controls
- toggleNativeControls(true);
-
- // Clean up
- cleanUp();
-
- break;
- }
-
- function cleanUp() {
- // Default to restore original element
- if (!utils.is.boolean(restore)) {
- restore = true;
- }
-
- // Callback
- if (utils.is.function(callback)) {
- callback.call(player.original);
- }
-
- // Bail if we don't need to restore the original element
- if (!restore) {
- return;
- }
-
- // Replace the container with the original element provided
- player.elements.container.parentNode.replaceChild(player.original, player.elements.container);
-
- // Reset overflow (incase destroyed while fullscreen)
- document.body.style.overflow = '';
-
- // Event
- trigger(player.original, 'destroyed', true);
- }
- }
-
// Setup the UI
function setupInterface() {
// Don't setup interface if no support
@@ -4729,14 +4093,14 @@
setupCaptions();
// Set volume
- setVolume();
+ player.setVolume();
updateVolume();
// Set playback speed
- setSpeed();
+ player.setSpeed();
// Set loop
- toggleLoop();
+ player.loop();
// Reset time display
timeUpdate();
@@ -4747,46 +4111,40 @@
// Everything done
function ready() {
- // Set class hook on media element
- // utils.toggleClass(player.elements.media, defaults.classes.setup, true);
-
- // Set container class for ready
- // utils.toggleClass(player.elements.container, config.classes.ready, true);
-
- // Store a refernce to instance
- // player.elements.media.plyr = api;
-
// Ready event at end of execution stack
trigger(player.elements.container, 'ready', true);
// Autoplay
- if (config.autoplay) {
- play();
+ if (player.config.autoplay) {
+ player.play();
}
}
// Setup a player
function setup(target) {
// We need an element to setup
- if (!utils.is.htmlElement(target)) {
- error('Setup failed. No suitable element passed.');
- return false;
+ if (target === null || utils.is.undefined(target) || !utils.is.htmlElement(target)) {
+ error('Setup failed: no suitable element passed');
+ return;
}
// Bail if not enabled
- if (!config.enabled) {
- return false;
+ if (!player.config.enabled) {
+ error('Setup failed: disabled by config');
+ return;
}
// Bail if disabled or no basic support
// You may want to disable certain UAs etc
if (!utils.checkSupport().basic) {
- return false;
+ error('Setup failed: no support');
+ return;
}
// Bail if the element is initialized
if (target.plyr) {
- return false;
+ log('Target already setup');
+ return target.plyr;
}
// Set media type based on tag or data attribute
@@ -4799,8 +4157,14 @@
player.type = target.getAttribute('data-type');
player.embedId = target.getAttribute('data-video-id');
- if (utils.is.empty(player.type) || utils.is.empty(player.embedId)) {
- return false;
+ if (utils.is.empty(player.type)) {
+ error('Setup failed: embed type missing');
+ return;
+ }
+
+ if (utils.is.empty(player.embedId)) {
+ error('Setup failed: video id missing');
+ return;
}
// Clean up
@@ -4815,13 +4179,14 @@
case 'video':
case 'audio':
player.type = type;
- config.crossorigin = target.getAttribute('crossorigin') !== null;
- config.autoplay = config.autoplay || (target.getAttribute('autoplay') !== null);
- config.inline = target.getAttribute('playsinline') !== null;
- config.loop.active = config.loop || (target.getAttribute('loop') !== null);
+ player.config.crossorigin = target.getAttribute('crossorigin') !== null;
+ player.config.autoplay = player.config.autoplay || (target.getAttribute('autoplay') !== null);
+ player.config.inline = target.getAttribute('playsinline') !== null;
+ player.config.loop.active = player.config.loop || (target.getAttribute('loop') !== null);
break;
default:
+ error('Setup failed: unsupported type');
return false;
}
@@ -4831,11 +4196,12 @@
// Load saved settings from localStorage
setupStorage();
- // Check for support
- player.supported = utils.checkSupport(player.type, config.inline);
+ // Check for support again but with type
+ player.supported = utils.checkSupport(player.type, player.config.inline);
// If no native support, bail
if (!player.supported.basic) {
+ error('Setup failed: no support');
return false;
}
@@ -4858,8 +4224,8 @@
setupMedia();
// Listen for events if debugging
- if (config.debug) {
- var events = config.events.concat(['setup', 'statechange', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled']);
+ if (player.config.debug) {
+ var events = player.config.events.concat(['setup', 'statechange', 'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled']);
utils.on(player.elements.container, events.join(' '), function(event) {
log(['event:', event.type].join(' ').trim());
@@ -4878,90 +4244,853 @@
// Set title on button and frame
setTitle();
}
-
- // Successful setup
- return true;
}
- // Expose prototypes
- api = {
- getOriginal: function() {
- return player.original;
- },
- getContainer: function() {
- return player.elements.container
- },
- getEmbed: function() {
- return player.embed;
- },
- getMedia: function() {
- return player.elements.media;
- },
- getType: function() {
- return player.type;
- },
- getDuration: getDuration,
- getCurrentTime: function() {
- return player.elements.media.currentTime;
- },
- getVolume: function() {
- return player.elements.media.volume;
- },
- isMuted: function() {
- return player.elements.media.muted;
- },
- isReady: function() {
- return utils.hasClass(player.elements.container, config.classes.ready);
- },
- isLoading: function() {
- return utils.hasClass(player.elements.container, config.classes.loading);
- },
- isPaused: function() {
- return player.elements.media.paused;
- },
- isLooping: function() {
- return config.loop.active;
- },
- on: function(event, callback) {
- utils.on(player.elements.container, event, callback);
- return this;
- },
- play: play,
- pause: pause,
- loop: toggleLoop,
- stop: function() {
- pause();
- seek();
- },
- restart: seek,
- rewind: rewind,
- forward: forward,
- seek: seek,
- source: source,
- poster: updatePoster,
- setVolume: setVolume,
- setSpeed: setSpeed,
- togglePlay: togglePlay,
- toggleMute: toggleMute,
- toggleCaptions: toggleCaptions,
- toggleFullscreen: toggleFullscreen,
- toggleControls: toggleControls,
- setLanguage: setLanguage,
- isFullscreen: player.fullscreen.active,
- support: function(mimeType) {
- return support.mime(player, mimeType);
- },
- destroy: destroy
+ // Expose some core functions
+ player.core = {
+ getElement: getElement,
+ getElements: getElements,
+ trigger: trigger,
+ setCaption: setCaption,
+ setupCaptions: setupCaptions,
+ toggleNativeControls: toggleNativeControls,
+ updateTimeDisplay: updateTimeDisplay,
+ updateSeekDisplay: updateSeekDisplay,
+ updateSource: updateSource,
+ updateStorage: updateStorage,
+ timers: timers,
+ support: support,
+
+ // Debugging
+ log: log,
+ warn: warn,
+ error: error
};
// Initialize instance
- if (!setup(player.elements.media)) {
- return null;
+ setup(player.media);
+ }
+
+ // API
+ // ---------------------------------------
+ // Play
+ Player.prototype.play = function() {
+ var player = this;
+
+ if ('play' in player.media) {
+ player.media.play();
}
- // Expose API
- return api;
- }
+ // Allow chaining
+ return player;
+ };
+
+ // Pause
+ Player.prototype.pause = function() {
+ var player = this;
+
+ if ('pause' in player.media) {
+ player.media.pause();
+ }
+
+ // Allow chaining
+ return player;
+ };
+
+ // Toggle playback
+ Player.prototype.togglePlay = function(toggle) {
+ var player = this;
+
+ // True toggle if nothing passed
+ if (!utils.is.boolean(toggle)) {
+ toggle = player.media.paused;
+ }
+
+ if (toggle) {
+ player.play();
+ } else {
+ player.pause();
+ }
+
+ return toggle;
+ };
+
+ // Stop
+ Player.prototype.stop = function() {
+ var player = this;
+
+ player.restart();
+ player.pause();
+
+ // Allow chaining
+ return player;
+ };
+
+ // Restart
+ Player.prototype.restart = function() {
+ var player = this;
+
+ // Seek to 0
+ player.seek();
+
+ // Allow chaining
+ return player;
+ };
+
+ // Rewind
+ Player.prototype.rewind = function(seekTime) {
+ var player = this;
+
+ // Use default if needed
+ if (!utils.is.number(seekTime)) {
+ seekTime = player.config.seekTime;
+ }
+
+ player.seek(player.media.currentTime - seekTime);
+
+ // Allow chaining
+ return player;
+ };
+
+ // Fast forward
+ Player.prototype.forward = function(seekTime) {
+ var player = this;
+
+ // Use default if needed
+ if (!utils.is.number(seekTime)) {
+ seekTime = player.config.seekTime;
+ }
+
+ player.seek(player.media.currentTime + seekTime);
+
+ // Allow chaining
+ return player;
+ };
+
+ // Seek to time
+ // The input parameter can be an event or a number
+ Player.prototype.seek = function(input) {
+ var player = this;
+ var targetTime = 0;
+ var paused = player.media.paused;
+ var duration = player.getDuration();
+
+ if (utils.is.number(input)) {
+ targetTime = input;
+ }
+
+ // Normalise targetTime
+ if (targetTime < 0) {
+ targetTime = 0;
+ } else if (targetTime > duration) {
+ targetTime = duration;
+ }
+
+ // Update seek range and progress
+ player.core.updateSeekDisplay(targetTime);
+
+ // Set the current time
+ // Try/catch incase the media isn't set and we're calling seek() from source() and IE moans
+ try {
+ player.media.currentTime = targetTime.toFixed(4);
+ } catch (e) {}
+
+ // Embeds
+ if (utils.inArray(types.embed, player.type)) {
+ switch (player.type) {
+ case 'youtube':
+ player.embed.seekTo(targetTime);
+ break;
+
+ case 'vimeo':
+ // Round to nearest second for vimeo
+ player.embed.setCurrentTime(targetTime.toFixed(0));
+ break;
+
+ case 'soundcloud':
+ player.embed.seekTo(targetTime * 1000);
+ break;
+ }
+
+ if (paused) {
+ player.pause();
+ }
+
+ // Trigger timeupdate
+ player.core.trigger(player.media, 'timeupdate');
+
+ // Set seeking flag
+ player.media.seeking = true;
+
+ // Trigger seeking
+ player.core.trigger(player.media, 'seeking');
+ }
+
+ // Logging
+ player.core.log('Seeking to ' + player.media.currentTime + ' seconds');
+
+ // Allow chaining
+ return player;
+ };
+
+ // Set volume
+ Player.prototype.setVolume = function(volume) {
+ var player = this;
+ var max = 10;
+ var min = 0;
+
+ // Load volume from storage if no value specified
+ if (utils.is.undefined(volume)) {
+ volume = player.storage.volume;
+ }
+
+ // Use config if all else fails
+ if (volume === null || isNaN(volume)) {
+ volume = player.config.volume;
+ }
+
+ // Maximum is volumeMax
+ if (volume > max) {
+ volume = max;
+ }
+ // Minimum is volumeMin
+ if (volume < min) {
+ volume = min;
+ }
+
+ // Set the player volume
+ player.media.volume = parseFloat(volume / max);
+
+ // Set the display
+ if (player.elements.display.volume) {
+ player.elements.display.volume.value = volume;
+ }
+
+ // Embeds
+ if (utils.inArray(types.embed, player.type)) {
+ switch (player.type) {
+ case 'youtube':
+ player.embed.setVolume(player.media.volume * 100);
+ break;
+
+ case 'vimeo':
+ case 'soundcloud':
+ player.embed.setVolume(player.media.volume);
+ break;
+ }
+
+ // Trigger volumechange for embeds
+ player.core.trigger(player.media, 'volumechange');
+ }
+
+ // Toggle muted state
+ if (volume === 0) {
+ player.media.muted = true;
+ } else if (player.media.muted && volume > 0) {
+ player.toggleMute();
+ }
+
+ // Allow chaining
+ return player;
+ };
+
+ // Increase volume
+ Player.prototype.increaseVolume = function(step) {
+ var player = this;
+ var volume = player.media.muted ? 0 : (player.media.volume * 10);
+
+ if (!utils.is.number(step)) {
+ step = 1;
+ }
+
+ player.setVolume(volume + step);
+
+ // Allow chaining
+ return player;
+ };
+
+ // Decrease volume
+ Player.prototype.decreaseVolume = function(step) {
+ var player = this;
+ var volume = player.media.muted ? 0 : (player.media.volume * 10);
+
+ if (!utils.is.number(step)) {
+ step = 1;
+ }
+
+ player.setVolume(volume - step);
+
+ // Allow chaining
+ return player;
+ };
+
+ // Toggle mute
+ Player.prototype.toggleMute = function(muted) {
+ var player = this;
+
+ // If the method is called without parameter, toggle based on current value
+ if (!utils.is.boolean(muted)) {
+ muted = !player.media.muted;
+ }
+
+ // Set button state
+ utils.toggleState(player.elements.buttons.mute, muted);
+
+ // Set mute on the player
+ player.media.muted = muted;
+
+ // If volume is 0 after unmuting, set to default
+ if (player.media.volume === 0) {
+ player.volume(player.config.volume);
+ }
+
+ // Embeds
+ if (utils.inArray(types.embed, player.type)) {
+ // YouTube
+ switch (player.type) {
+ case 'youtube':
+ player.embed[player.media.muted ? 'mute' : 'unMute']();
+ break;
+
+ case 'vimeo':
+ case 'soundcloud':
+ player.embed.setVolume(player.media.muted ? 0 : parseFloat(player.config.volume / 10));
+ break;
+ }
+
+ // Trigger volumechange for embeds
+ player.core.trigger(player.media, 'volumechange');
+ }
+
+ // Allow chaining
+ return player;
+ };
+
+ // Set playback speed
+ Player.prototype.setSpeed = function(speed) {
+ var player = this;
+
+ // Load speed from storage or default value
+ if (!utils.is.number(speed)) {
+ speed = parseFloat(player.storage.speed || player.config.speed.selected);
+ }
+
+ // Set min/max
+ if (speed < 0.1) {
+ speed = 0.1;
+ }
+ if (speed > 2.0) {
+ speed = 2.0;
+ }
+
+ if (!utils.is.array(player.config.speed.options)) {
+ player.core.warn('Invalid speeds format');
+ return;
+ }
+
+ // Store current speed
+ player.config.speed.selected = speed;
+
+ // Set HTML5 speed
+ // TODO: set YouTube
+ player.media.playbackRate = speed;
+
+ // Save speed to localStorage
+ player.core.updateStorage({
+ speed: speed
+ });
+
+ // Allow chaining
+ return player;
+ };
+
+ // Toggle loop
+ // TODO: Finish logic
+ // TODO: Set the indicator on load as user may pass loop as config
+ Player.prototype.loop = function(type) {
+ var player = this;
+
+ // Set default to be a true toggle
+ if (!utils.inArray(['start', 'end', 'all', 'none', 'toggle'], type)) {
+ type = 'toggle';
+ }
+
+ var currentTime = Number(player.media.currentTime);
+
+ switch (type) {
+ case 'start':
+ if (player.config.loop.end && player.config.loop.end <= currentTime) {
+ player.config.loop.end = null;
+ }
+ player.config.loop.start = currentTime;
+ player.config.loop.indicator.start = player.elements.display.played.value;
+ break;
+
+ case 'end':
+ if (player.config.loop.start >= currentTime) {
+ return;
+ }
+ player.config.loop.end = currentTime;
+ player.config.loop.indicator.end = player.elements.display.played.value;
+ break;
+
+ case 'all':
+ player.config.loop.start = 0;
+ player.config.loop.end = player.media.duration - 2;
+ player.config.loop.indicator.start = 0;
+ player.config.loop.indicator.end = 100;
+ break;
+
+ case 'toggle':
+ if (player.config.loop.active) {
+ player.config.loop.start = 0;
+ player.config.loop.end = null;
+ } else {
+ player.config.loop.start = 0;
+ player.config.loop.end = player.media.duration - 2;
+ }
+ break;
+
+ default:
+ player.config.loop.start = 0;
+ player.config.loop.end = null;
+ break;
+ }
+
+ // Check if can loop
+ player.config.loop.active = utils.is.number(player.config.loop.start) && utils.is.number(player.config.loop.end);
+ var start = player.core.updateTimeDisplay(player.config.loop.start, player.core.getElement('[data-plyr-loop="start"]'));
+ var end = null;
+
+ if (utils.is.number(player.config.loop.end)) {
+ // Find the <span> inside button
+ end = player.core.updateTimeDisplay(player.config.loop.end, player.core.getElement('[data-loop__value="loopout"]'));
+ } else {
+ // Find the <span> inside button
+ //end = document.querySelector('[data-loop__value="loopout"]').innerHTML = '';
+ }
+
+ if (player.config.loop.active) {
+ // TODO: Improve the design of the loop indicator and put styling in CSS where it's meant to be
+ //getElement('[data-menu="loop"]').innerHTML = start + ' - ' + end;
+ //getElement(player.config.selectors.progress.looped).style.position = 'absolute';
+ //getElement(player.config.selectors.progress.looped).style.left = player.config.loopinPositionPercentage + '%';
+ //getElement(player.config.selectors.progress.looped).style.width = (player.config.loopoutPositionPercentage - player.config.loopinPositionPercentage) + '%';
+ //getElement(player.config.selectors.progress.looped).style.background = '#ffbb00';
+ //getElement(player.config.selectors.progress.looped).style.height = '3px';
+ //getElement(player.config.selectors.progress.looped).style.top = '3px';
+ //getElement(player.config.selectors.progress.looped).style['border-radius'] = '100px';
+ } else {
+ //getElement('[data-menu="loop"]').innerHTML = player.config.i18n.loopNone;
+ //getElement(player.config.selectors.progress.looped).style.width = '0px';
+ }
+
+ // Allow chaining
+ return player;
+ };
+
+ // Add common function to retrieve media source
+ Player.prototype.source = function(source) {
+ var player = this;
+
+ // If object or string, parse it
+ if (utils.is.object(source)) {
+ player.core.updateSource(source);
+ return player;
+ }
+
+ // Return the current source
+ var url;
+
+ switch (player.type) {
+ case 'youtube':
+ url = player.embed.getVideoUrl();
+ break;
+
+ case 'vimeo':
+ player.embed.getVideoUrl.then(function(value) {
+ url = value;
+ });
+ break;
+
+ case 'soundcloud':
+ player.embed.getCurrentSound(function(object) {
+ url = object.permalink_url;
+ });
+ break;
+
+ default:
+ url = player.media.currentSrc;
+ break;
+ }
+
+ return url;
+ };
+
+ // Set or get poster
+ Player.prototype.poster = function(source) {
+ var player = this;
+
+ if (!utils.is.string(source)) {
+ return player.media.getAttribute('poster');
+ } else if (player.type === 'video') {
+ player.media.setAttribute('poster', source);
+ } else {
+ player.core.warn('Poster can only be set on HTML5 video');
+ }
+
+ // Allow chaining
+ return player;
+ };
+
+ // Toggle captions
+ Player.prototype.toggleCaptions = function(show) {
+ var player = this;
+
+ // If there's no full support, or there's no caption toggle
+ if (!player.supported.full || !player.elements.buttons.captions) {
+ return;
+ }
+
+ // If the method is called without parameter, toggle based on current value
+ if (!utils.is.boolean(show)) {
+ show = (player.elements.container.className.indexOf(player.config.classes.captions.active) === -1);
+ }
+
+ // Set global
+ player.captions.enabled = show;
+
+ // Toggle state
+ utils.toggleState(player.elements.buttons.captions, player.captions.enabled);
+
+ // Add class hook
+ utils.toggleClass(player.elements.container, player.config.classes.captions.active, player.captions.enabled);
+
+ // Trigger an event
+ player.core.trigger(player.elements.container, player.captions.enabled ? 'captionsenabled' : 'captionsdisabled', true);
+
+ // Save captions state to localStorage
+ player.core.updateStorage({
+ captions: player.captions.enabled
+ });
+
+ // Allow chaining
+ return player;
+ };
+
+ // Select active caption
+ Player.prototype.language = function(language) {
+ var player = this;
+
+ if (utils.is.string(language)) {
+ // Update config
+ player.config.captions.language = language.toLowerCase();
+ } else {
+ // If no language passed, return current language
+ return player.config.captions.language;
+ }
+
+ // Clear caption
+ player.core.setCaption();
+
+ // Re-run setup
+ player.core.setupCaptions();
+
+ // Allow chaining
+ return player;
+ };
+
+ // Toggle fullscreen
+ // Requires user input event
+ Player.prototype.toggleFullscreen = function(event) {
+ var player = this;
+
+ // Save scroll position
+ function saveScrollPosition() {
+ scroll = {
+ x: window.pageXOffset || 0,
+ y: window.pageYOffset || 0
+ };
+ }
+
+ // Restore scroll position
+ function restoreScrollPosition() {
+ window.scrollTo(scroll.x, scroll.y);
+ }
+
+ // Check for native support
+ var nativeSupport = support.fullscreen;
+
+ if (nativeSupport) {
+ // If it's a fullscreen change event, update the UI
+ if (utils.is.event(event) && event.type === fullscreen.eventType) {
+ player.fullscreen.active = fullscreen.isFullScreen(player.elements.container);
+ } else {
+ // Else it's a user request to enter or exit
+ if (!fullscreen.isFullScreen(player.elements.container)) {
+ // Save scroll position
+ saveScrollPosition();
+
+ // Request full screen
+ fullscreen.requestFullScreen(player.elements.container);
+ } else {
+ // Bail from fullscreen
+ fullscreen.cancelFullScreen();
+ }
+
+ // Check if we're actually full screen (it could fail)
+ player.fullscreen.active = fullscreen.isFullScreen(player.elements.container);
+
+ return;
+ }
+ } else {
+ // Otherwise, it's a simple toggle
+ player.fullscreen.active = !player.fullscreen.active;
+
+ // Bind/unbind escape key
+ document.body.style.overflow = player.fullscreen.active ? 'hidden' : '';
+ }
+
+ // Set class hook
+ utils.toggleClass(player.elements.container, player.config.classes.fullscreen.active, player.fullscreen.active);
+
+ // Set button state
+ if (player.elements.buttons && player.elements.buttons.fullscreen) {
+ utils.toggleState(player.elements.buttons.fullscreen, player.fullscreen.active);
+ }
+
+ // Trigger an event
+ player.core.trigger(player.elements.container, player.fullscreen.active ? 'enterfullscreen' : 'exitfullscreen', true);
+
+ // Restore scroll position
+ if (!player.fullscreen.active && nativeSupport) {
+ restoreScrollPosition();
+ }
+
+ // Allow chaining
+ return player;
+ };
+
+ // Toggle picture-in-picture
+ // TODO: update player with state, support, enabled
+ // TODO: detect outside changes
+ Player.prototype.togglePictureInPicture = function(toggle) {
+ var player = this;
+ var states = {
+ pip: 'picture-in-picture',
+ inline: 'inline'
+ };
+
+ // Bail if no support
+ if (!player.core.support.pip) {
+ return;
+ }
+
+ // Toggle based on current state if not passed
+ if (!utils.is.boolean(toggle)) {
+ toggle = player.media.webkitPresentationMode === states.inline;
+ }
+
+ // Toggle based on current state
+ player.media.webkitSetPresentationMode(toggle ? states.pip : states.inline);
+
+ // Allow chaining
+ return player;
+ };
+
+ // Trigger airplay
+ // TODO: update player with state, support, enabled
+ Player.prototype.airPlay = function() {
+ var player = this;
+
+ // Bail if no support
+ if (!player.core.support.airplay) {
+ return;
+ }
+
+ // Show dialog
+ player.media.webkitShowPlaybackTargetPicker();
+
+ // Allow chaining
+ return player;
+ };
+
+ // Show the player controls in fullscreen mode
+ Player.prototype.toggleControls = function(toggle) {
+ var player = this;
+
+ // Don't hide if config says not to, it's audio, or not ready or loading
+ if (!player.config.hideControls || player.type === 'audio') {
+ return;
+ }
+
+ var delay = 0;
+ var show = toggle;
+ var isEnterFullscreen = false;
+ var loading = utils.hasClass(player.elements.container, player.config.classes.loading);
+
+ // Default to false if no boolean
+ if (!utils.is.boolean(toggle)) {
+ if (utils.is.event(toggle)) {
+ // Is the enter fullscreen event
+ isEnterFullscreen = (toggle.type === 'enterfullscreen');
+
+ // Whether to show controls
+ show = utils.inArray(['mousemove', 'touchstart', 'mouseenter', 'focus'], toggle.type);
+
+ // Delay hiding on move events
+ if (utils.inArray(['mousemove', 'touchmove'], toggle.type)) {
+ delay = 2000;
+ }
+
+ // Delay a little more for keyboard users
+ if (toggle.type === 'focus') {
+ delay = 3000;
+ }
+ } else {
+ show = utils.hasClass(player.elements.container, player.config.classes.hideControls);
+ }
+ }
+
+ // Clear timer every movement
+ window.clearTimeout(player.core.timers.hover);
+
+ // If the mouse is not over the controls, set a timeout to hide them
+ if (show || player.media.paused || loading) {
+ utils.toggleClass(player.elements.container, player.config.classes.hideControls, false);
+
+ // Always show controls when paused or if touch
+ if (player.media.paused || loading) {
+ return;
+ }
+
+ // Delay for hiding on touch
+ if (support.touch) {
+ delay = 3000;
+ }
+ }
+
+ // If toggle is false or if we're playing (regardless of toggle),
+ // then set the timer to hide the controls
+ if (!show || !player.media.paused) {
+ player.core.timers.hover = window.setTimeout(function() {
+ // If the mouse is over the controls (and not entering fullscreen), bail
+ if ((player.elements.controls.pressed || player.elements.controls.hover) && !isEnterFullscreen) {
+ return;
+ }
+
+ utils.toggleClass(player.elements.container, player.config.classes.hideControls, true);
+ }, delay);
+ }
+
+ // Allow chaining
+ return player;
+ };
+
+ // Event listener
+ Player.prototype.on = function(event, callback) {
+ var player = this;
+
+ utils.on(player.elements.container, event, callback);
+
+ // Allow chaining
+ return player;
+ };
+
+ // Check for support
+ Player.prototype.supports = function(mimeType) {
+ return support.mime(this, mimeType);
+ };
+
+ // Destroy an instance
+ // Event listeners are removed when elements are removed
+ // http://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory
+ Player.prototype.destroy = function(callback, restore) {
+ var player = this;
+ // Type specific stuff
+ switch (player.type) {
+ case 'youtube':
+ // Clear timers
+ window.clearInterval(player.timers.buffering);
+ window.clearInterval(player.timers.playing);
+
+ // Destroy YouTube API
+ player.embed.destroy();
+
+ // Clean up
+ cleanUp();
+
+ break;
+
+ case 'vimeo':
+ // Destroy Vimeo API
+ // then clean up (wait, to prevent postmessage errors)
+ player.embed.unload().then(cleanUp);
+
+ // Vimeo does not always return
+ window.setTimeout(cleanUp, 200);
+
+ break;
+
+ case 'video':
+ case 'audio':
+ // Restore native video controls
+ player.core.toggleNativeControls(true);
+
+ // Clean up
+ cleanUp();
+
+ break;
+ }
+
+ function cleanUp() {
+ // Default to restore original element
+ if (!utils.is.boolean(restore)) {
+ restore = true;
+ }
+
+ // Callback
+ if (utils.is.function(callback)) {
+ callback.call(player.original);
+ }
+
+ // Bail if we don't need to restore the original element
+ if (!restore) {
+ return;
+ }
+
+ // Replace the container with the original element provided
+ player.elements.container.parentNode.replaceChild(player.original, player.elements.container);
+
+ // Reset overflow (incase destroyed while fullscreen)
+ document.body.style.overflow = '';
+
+ // Event
+ player.core.trigger(player.original, 'destroyed', true);
+ }
+
+ // Allow chaining
+ return player;
+ };
+
+ // Get the duration (or custom if set)
+ Player.prototype.getDuration = function() {
+ var player = this;
+
+ // It should be a number, but parse it just incase
+ var duration = parseInt(player.config.duration);
+
+ // True duration
+ var mediaDuration = 0;
+
+ // Only if duration available
+ if (player.media.duration !== null && !isNaN(player.media.duration)) {
+ mediaDuration = player.media.duration;
+ }
+
+ // If custom duration is funky, use regular duration
+ return (isNaN(duration) ? mediaDuration : duration);
+ };
return Player;
-}));
+});