From 1e7756a2ee0403458701440e00ae19ec549e71ed Mon Sep 17 00:00:00 2001 From: Stephen Cameron Date: Tue, 8 Jun 2021 15:57:11 +0200 Subject: [PATCH] Wait #4620 @0.75 --- .gitignore | 1 + Ecureuil/Essentiel-2021/Essentiel-2021.zip | Bin 141063 -> 0 bytes Ecureuil/Essentiel-2021/index.html | 69 +- .../Essentiel-2021/landing-2021-01-27.zip | Bin 147439 -> 0 bytes Ecureuil/Essentiel-2021/magnific-popup.css | 374 + Ecureuil/Essentiel-2021/magnific-popup.js | 3 + Ecureuil/Essentiel-2021/video-js.css | 1307 + Ecureuil/Essentiel-2021/video.js | 26878 ++++++++++++++++ 8 files changed, 28630 insertions(+), 2 deletions(-) delete mode 100644 Ecureuil/Essentiel-2021/Essentiel-2021.zip delete mode 100644 Ecureuil/Essentiel-2021/landing-2021-01-27.zip create mode 100755 Ecureuil/Essentiel-2021/magnific-popup.css create mode 100755 Ecureuil/Essentiel-2021/magnific-popup.js create mode 100755 Ecureuil/Essentiel-2021/video-js.css create mode 100755 Ecureuil/Essentiel-2021/video.js diff --git a/.gitignore b/.gitignore index d3cfac9..a837d6c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # Created by .ignore support plugin (hsz.mobi) .idea .gitignore +.DS_Store /AccordHotel-p80/AccordHotel-p80.zip diff --git a/Ecureuil/Essentiel-2021/Essentiel-2021.zip b/Ecureuil/Essentiel-2021/Essentiel-2021.zip deleted file mode 100644 index f066918cff7877d873b706c931bb30f482c500de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 141063 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
_{;14UwN+2Bmu&JhVx-!!EZ)9+h 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

suLs&Nx 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'indispensable 2021 - Caisse d'Epargne + + + + @@ -347,8 +363,16 @@ - + Découvrez la version 2021 en images +

@@ -461,7 +485,9 @@ + + + + // Video player + popup + $('document').ready(function() { + + $('.video').magnificPopup({ + type: 'inline', + midClick: true, + callbacks: { + close: function() { + // Pause videos when popup closes + var videos = Array.prototype.slice.apply(document.querySelectorAll('video')); + videos.forEach(function(video) { + video.pause(); + }); + } + } + }); + + $('.video').on('click', function(event) { + + event.preventDefault(); + + var player = videojs($(this).data('video')); + + player.ready(function() { + var duration_time = Math.floor(this.duration()); + this.on('timeupdate', function() { + var current_time = Math.floor(this.currentTime()); + if ( current_time > 0 && ( current_time == duration_time ) ) { + this.currentTime(0); // Rewind to beginning for subsequent plays + $.magnificPopup.close(); + } + }); + }); + + player.play(); + }); + + }); + \ No newline at end of file diff --git a/Ecureuil/Essentiel-2021/landing-2021-01-27.zip b/Ecureuil/Essentiel-2021/landing-2021-01-27.zip deleted file mode 100644 index 170e6ee0915af0ff2a91f7d8a27e54c4a914036f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147439 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 diff --git a/Ecureuil/Essentiel-2021/magnific-popup.css b/Ecureuil/Essentiel-2021/magnific-popup.css new file mode 100755 index 0000000..8a43d52 --- /dev/null +++ b/Ecureuil/Essentiel-2021/magnific-popup.css @@ -0,0 +1,374 @@ +/* Magnific Popup CSS */ +.mfp-bg { + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1042; + overflow: hidden; + position: fixed; + background: #0b0b0b; + opacity: 0.8; + filter: alpha(opacity=80); } + +.mfp-wrap { + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1043; + position: fixed; + outline: none !important; + -webkit-backface-visibility: hidden; } + +.mfp-container { + text-align: center; + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + padding: 0 8px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } + +.mfp-container:before { + content: ''; + display: inline-block; + height: 100%; + vertical-align: middle; } + +.mfp-align-top .mfp-container:before { + display: none; } + +.mfp-content { + position: relative; + display: inline-block; + vertical-align: middle; + margin: 0 auto; + text-align: left; + z-index: 1045; } + +.mfp-inline-holder .mfp-content, .mfp-ajax-holder .mfp-content { + width: 100%; + cursor: auto; } + +.mfp-ajax-cur { + cursor: progress; } + +.mfp-zoom-out-cur, .mfp-zoom-out-cur .mfp-image-holder .mfp-close { + cursor: -moz-zoom-out; + cursor: -webkit-zoom-out; + cursor: zoom-out; } + +.mfp-zoom { + cursor: pointer; + cursor: -webkit-zoom-in; + cursor: -moz-zoom-in; + cursor: zoom-in; } + +.mfp-auto-cursor .mfp-content { + cursor: auto; } + +.mfp-close, .mfp-arrow, .mfp-preloader, .mfp-counter { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; } + +.mfp-loading.mfp-figure { + display: none; } + +.mfp-hide { + display: none !important; } + +.mfp-preloader { + color: #CCC; + position: absolute; + top: 50%; + width: auto; + text-align: center; + margin-top: -0.8em; + left: 8px; + right: 8px; + z-index: 1044; } + .mfp-preloader a { + color: #CCC; } + .mfp-preloader a:hover { + color: #FFF; } + +.mfp-s-ready .mfp-preloader { + display: none; } + +.mfp-s-error .mfp-content { + display: none; } + +button.mfp-close, button.mfp-arrow { + overflow: visible; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; + display: block; + outline: none; + padding: 0; + z-index: 1046; + -webkit-box-shadow: none; + box-shadow: none; } +button::-moz-focus-inner { + padding: 0; + border: 0; } + +.mfp-close { + width: 44px; + height: 44px; + line-height: 44px; + position: absolute; + right: 0; + top: 0; + text-decoration: none; + text-align: center; + opacity: 0.65; + filter: alpha(opacity=65); + padding: 0 0 18px 10px; + color: #FFF; + font-style: normal; + font-size: 28px; + font-family: Arial, Baskerville, monospace; } + .mfp-close:hover, .mfp-close:focus { + opacity: 1; + filter: alpha(opacity=100); } + .mfp-close:active { + top: 1px; } + +.mfp-close-btn-in .mfp-close { + color: #333; } + +.mfp-image-holder .mfp-close, .mfp-iframe-holder .mfp-close { + color: #FFF; + right: -6px; + text-align: right; + padding-right: 6px; + width: 100%; } + +.mfp-counter { + position: absolute; + top: 0; + right: 0; + color: #CCC; + font-size: 12px; + line-height: 18px; + white-space: nowrap; } + +.mfp-arrow { + position: absolute; + opacity: 0.65; + filter: alpha(opacity=65); + margin: 0; + top: 50%; + margin-top: -55px; + padding: 0; + width: 90px; + height: 110px; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } + .mfp-arrow:active { + margin-top: -54px; } + .mfp-arrow:hover, .mfp-arrow:focus { + opacity: 1; + filter: alpha(opacity=100); } + .mfp-arrow:before, .mfp-arrow:after, .mfp-arrow .mfp-b, .mfp-arrow .mfp-a { + content: ''; + display: block; + width: 0; + height: 0; + position: absolute; + left: 0; + top: 0; + margin-top: 35px; + margin-left: 35px; + border: medium inset transparent; } + .mfp-arrow:after, .mfp-arrow .mfp-a { + border-top-width: 13px; + border-bottom-width: 13px; + top: 8px; } + .mfp-arrow:before, .mfp-arrow .mfp-b { + border-top-width: 21px; + border-bottom-width: 21px; + opacity: 0.7; } + +.mfp-arrow-left { + left: 0; } + .mfp-arrow-left:after, .mfp-arrow-left .mfp-a { + border-right: 17px solid #FFF; + margin-left: 31px; } + .mfp-arrow-left:before, .mfp-arrow-left .mfp-b { + margin-left: 25px; + border-right: 27px solid #3F3F3F; } + +.mfp-arrow-right { + right: 0; } + .mfp-arrow-right:after, .mfp-arrow-right .mfp-a { + border-left: 17px solid #FFF; + margin-left: 39px; } + .mfp-arrow-right:before, .mfp-arrow-right .mfp-b { + border-left: 27px solid #3F3F3F; } + +.mfp-iframe-holder { + padding-top: 40px; + padding-bottom: 40px; } + .mfp-iframe-holder .mfp-content { + line-height: 0; + width: 100%; + max-width: 900px; } + .mfp-iframe-holder .mfp-close { + top: -40px; } + +.mfp-iframe-scaler { + width: 100%; + height: 0; + overflow: hidden; + padding-top: 56.25%; } + .mfp-iframe-scaler iframe { + position: absolute; + display: block; + top: 0; + left: 0; + width: 100%; + height: 100%; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); + background: #000; } + +/* Main image in popup */ +img.mfp-img { + width: auto; + max-width: 100%; + height: auto; + display: block; + line-height: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 40px 0 40px; + margin: 0 auto; } + +/* The shadow behind the image */ +.mfp-figure { + line-height: 0; } + .mfp-figure:after { + content: ''; + position: absolute; + left: 0; + top: 40px; + bottom: 40px; + display: block; + right: 0; + width: auto; + height: auto; + z-index: -1; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); + background: #444; } + .mfp-figure small { + color: #BDBDBD; + display: block; + font-size: 12px; + line-height: 14px; } + .mfp-figure figure { + margin: 0; } + +.mfp-bottom-bar { + margin-top: -36px; + position: absolute; + top: 100%; + left: 0; + width: 100%; + cursor: auto; } + +.mfp-title { + text-align: left; + line-height: 18px; + color: #F3F3F3; + word-wrap: break-word; + padding-right: 36px; } + +.mfp-image-holder .mfp-content { + max-width: 100%; } + +.mfp-gallery .mfp-image-holder .mfp-figure { + cursor: pointer; } + +@media screen and (max-width: 800px) and (orientation: landscape), screen and (max-height: 300px) { + /** + * Remove all paddings around the image on small screen + */ + .mfp-img-mobile .mfp-image-holder { + padding-left: 0; + padding-right: 0; } + .mfp-img-mobile img.mfp-img { + padding: 0; } + .mfp-img-mobile .mfp-figure:after { + top: 0; + bottom: 0; } + .mfp-img-mobile .mfp-figure small { + display: inline; + margin-left: 5px; } + .mfp-img-mobile .mfp-bottom-bar { + background: rgba(0, 0, 0, 0.6); + bottom: 0; + margin: 0; + top: auto; + padding: 3px 5px; + position: fixed; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } + .mfp-img-mobile .mfp-bottom-bar:empty { + padding: 0; } + .mfp-img-mobile .mfp-counter { + right: 5px; + top: 3px; } + .mfp-img-mobile .mfp-close { + top: 0; + right: 0; + width: 35px; + height: 35px; + line-height: 35px; + background: rgba(0, 0, 0, 0.6); + position: fixed; + text-align: center; + padding: 0; } + } + +@media all and (max-width: 900px) { + .mfp-arrow { + -webkit-transform: scale(0.75); + transform: scale(0.75); } + + .mfp-arrow-left { + -webkit-transform-origin: 0; + transform-origin: 0; } + + .mfp-arrow-right { + -webkit-transform-origin: 100%; + transform-origin: 100%; } + + .mfp-container { + padding-left: 6px; + padding-right: 6px; } + } + +.mfp-ie7 .mfp-img { + padding: 0; } +.mfp-ie7 .mfp-bottom-bar { + width: 600px; + left: 50%; + margin-left: -300px; + margin-top: 5px; + padding-bottom: 5px; } +.mfp-ie7 .mfp-container { + padding: 0; } +.mfp-ie7 .mfp-content { + padding-top: 44px; } +.mfp-ie7 .mfp-close { + top: 0; + right: 0; + padding-top: 0; } \ No newline at end of file diff --git a/Ecureuil/Essentiel-2021/magnific-popup.js b/Ecureuil/Essentiel-2021/magnific-popup.js new file mode 100755 index 0000000..dd86291 --- /dev/null +++ b/Ecureuil/Essentiel-2021/magnific-popup.js @@ -0,0 +1,3 @@ +// Magnific Popup v1.1.0 by Dmitry Semenov +// http://bit.ly/magnific-popup#build=inline +(function(a){typeof define=="function"&&define.amd?define(["jquery"],a):typeof exports=="object"?a(require("jquery")):a(window.jQuery||window.Zepto)})(function(a){var b="Close",c="BeforeClose",d="AfterClose",e="BeforeAppend",f="MarkupParse",g="Open",h="Change",i="mfp",j="."+i,k="mfp-ready",l="mfp-removing",m="mfp-prevent-close",n,o=function(){},p=!!window.jQuery,q,r=a(window),s,t,u,v,w=function(a,b){n.ev.on(i+a+j,b)},x=function(b,c,d,e){var f=document.createElement("div");return f.className="mfp-"+b,d&&(f.innerHTML=d),e?c&&c.appendChild(f):(f=a(f),c&&f.appendTo(c)),f},y=function(b,c){n.ev.triggerHandler(i+b,c),n.st.callbacks&&(b=b.charAt(0).toLowerCase()+b.slice(1),n.st.callbacks[b]&&n.st.callbacks[b].apply(n,a.isArray(c)?c:[c]))},z=function(b){if(b!==v||!n.currTemplate.closeBtn)n.currTemplate.closeBtn=a(n.st.closeMarkup.replace("%title%",n.st.tClose)),v=b;return n.currTemplate.closeBtn},A=function(){a.magnificPopup.instance||(n=new o,n.init(),a.magnificPopup.instance=n)},B=function(){var a=document.createElement("p").style,b=["ms","O","Moz","Webkit"];if(a.transition!==undefined)return!0;while(b.length)if(b.pop()+"Transition"in a)return!0;return!1};o.prototype={constructor:o,init:function(){var b=navigator.appVersion;n.isLowIE=n.isIE8=document.all&&!document.addEventListener,n.isAndroid=/android/gi.test(b),n.isIOS=/iphone|ipad|ipod/gi.test(b),n.supportsTransition=B(),n.probablyMobile=n.isAndroid||n.isIOS||/(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent),s=a(document),n.popupsCache={}},open:function(b){var c;if(b.isObj===!1){n.items=b.items.toArray(),n.index=0;var d=b.items,e;for(c=0;c(a||r.height())},_setFocus:function(){(n.st.focus?n.content.find(n.st.focus).eq(0):n.wrap).focus()},_onFocusIn:function(b){if(b.target!==n.wrap[0]&&!a.contains(n.wrap[0],b.target))return n._setFocus(),!1},_parseMarkup:function(b,c,d){var e;d.data&&(c=a.extend(d.data,c)),y(f,[b,c,d]),a.each(c,function(c,d){if(d===undefined||d===!1)return!0;e=c.split("_");if(e.length>1){var f=b.find(j+"-"+e[0]);if(f.length>0){var g=e[1];g==="replaceWith"?f[0]!==d[0]&&f.replaceWith(d):g==="img"?f.is("img")?f.attr("src",d):f.replaceWith(a("").attr("src",d).attr("class",f.attr("class"))):f.attr(e[1],d)}}else b.find(j+"-"+c).html(d)})},_getScrollbarSize:function(){if(n.scrollbarSize===undefined){var a=document.createElement("div");a.style.cssText="width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;",document.body.appendChild(a),n.scrollbarSize=a.offsetWidth-a.clientWidth,document.body.removeChild(a)}return n.scrollbarSize}},a.magnificPopup={instance:null,proto:o.prototype,modules:[],open:function(b,c){return A(),b?b=a.extend(!0,{},b):b={},b.isObj=!0,b.index=c||0,this.instance.open(b)},close:function(){return a.magnificPopup.instance&&a.magnificPopup.instance.close()},registerModule:function(b,c){c.options&&(a.magnificPopup.defaults[b]=c.options),a.extend(this.proto,c.proto),this.modules.push(b)},defaults:{disableOn:0,key:null,midClick:!1,mainClass:"",preloader:!0,focus:"",closeOnContentClick:!1,closeOnBgClick:!0,closeBtnInside:!0,showCloseBtn:!0,enableEscapeKey:!0,modal:!1,alignTop:!1,removalDelay:0,prependTo:null,fixedContentPos:"auto",fixedBgPos:"auto",overflowY:"auto",closeMarkup:'',tClose:"Close (Esc)",tLoading:"Loading...",autoFocusLast:!0}},a.fn.magnificPopup=function(b){A();var c=a(this);if(typeof b=="string")if(b==="open"){var d,e=p?c.data("magnificPopup"):c[0].magnificPopup,f=parseInt(arguments[1],10)||0;e.items?d=e.items[f]:(d=c,e.delegate&&(d=d.find(e.delegate)),d=d.eq(f)),n._openClick({mfpEl:d},c,e)}else n.isOpen&&n[b].apply(n,Array.prototype.slice.call(arguments,1));else b=a.extend(!0,{},b),p?c.data("magnificPopup",b):c[0].magnificPopup=b,n.addGroup(c,b);return c};var C="inline",D,E,F,G=function(){F&&(E.after(F.addClass(D)).detach(),F=null)};a.magnificPopup.registerModule(C,{options:{hiddenClass:"hide",markup:"",tNotFound:"Content not found"},proto:{initInline:function(){n.types.push(C),w(b+"."+C,function(){G()})},getInline:function(b,c){G();if(b.src){var d=n.st.inline,e=a(b.src);if(e.length){var f=e[0].parentNode;f&&f.tagName&&(E||(D=d.hiddenClass,E=x(D),D="mfp-"+D),F=e.after(E).detach().removeClass(D)),n.updateStatus("ready")}else n.updateStatus("error",d.tNotFound),e=a("
");return b.inlineElement=e,e}return n.updateStatus("ready"),n._parseMarkup(c,{},b),c}}});var H,I=function(){return H===undefined&&(H=document.createElement("p").style.MozTransform!==undefined),H};a.magnificPopup.registerModule("zoom",{options:{enabled:!1,easing:"ease-in-out",duration:300,opener:function(a){return a.is("img")?a:a.find("img")}},proto:{initZoom:function(){var a=n.st.zoom,d=".zoom",e;if(!a.enabled||!n.supportsTransition)return;var f=a.duration,g=function(b){var c=b.clone().removeAttr("style").removeAttr("class").addClass("mfp-animated-image"),d="all "+a.duration/1e3+"s "+a.easing,e={position:"fixed",zIndex:9999,left:0,top:0,"-webkit-backface-visibility":"hidden"},f="transition";return e["-webkit-"+f]=e["-moz-"+f]=e["-o-"+f]=e[f]=d,c.css(e),c},h=function(){n.content.css("visibility","visible")},i,j;w("BuildControls"+d,function(){if(n._allowZoom()){clearTimeout(i),n.content.css("visibility","hidden"),e=n._getItemToZoom();if(!e){h();return}j=g(e),j.css(n._getOffset()),n.wrap.append(j),i=setTimeout(function(){j.css(n._getOffset(!0)),i=setTimeout(function(){h(),setTimeout(function(){j.remove(),e=j=null,y("ZoomAnimationEnded")},16)},f)},16)}}),w(c+d,function(){if(n._allowZoom()){clearTimeout(i),n.st.removalDelay=f;if(!e){e=n._getItemToZoom();if(!e)return;j=g(e)}j.css(n._getOffset(!0)),n.wrap.append(j),n.content.css("visibility","hidden"),setTimeout(function(){j.css(n._getOffset())},16)}}),w(b+d,function(){n._allowZoom()&&(h(),j&&j.remove(),e=null)})},_allowZoom:function(){return n.currItem.type==="image"},_getItemToZoom:function(){return n.currItem.hasSize?n.currItem.img:!1},_getOffset:function(b){var c;b?c=n.currItem.img:c=n.st.zoom.opener(n.currItem.el||n.currItem);var d=c.offset(),e=parseInt(c.css("padding-top"),10),f=parseInt(c.css("padding-bottom"),10);d.top-=a(window).scrollTop()-e;var g={width:c.width(),height:(p?c.innerHeight():c[0].offsetHeight)-f-e};return I()?g["-moz-transform"]=g.transform="translate("+d.left+"px,"+d.top+"px)":(g.left=d.left,g.top=d.top),g}}}),A()}) \ No newline at end of file diff --git a/Ecureuil/Essentiel-2021/video-js.css b/Ecureuil/Essentiel-2021/video-js.css new file mode 100755 index 0000000..1f40119 --- /dev/null +++ b/Ecureuil/Essentiel-2021/video-js.css @@ -0,0 +1,1307 @@ +.video-js .vjs-big-play-button:before, .video-js .vjs-control:before, .video-js .vjs-modal-dialog, .vjs-modal-dialog .vjs-modal-dialog-content { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; } + +.video-js .vjs-big-play-button:before, .video-js .vjs-control:before { + text-align: center; } + +@font-face { + font-family: VideoJS; + src: url("font/VideoJS.eot?#iefix") format("eot"); } + +@font-face { + font-family: VideoJS; + src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAA54AAoAAAAAFmgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAAA9AAAAD4AAABWUZFeBWNtYXAAAAE0AAAAOgAAAUriMBC2Z2x5ZgAAAXAAAAouAAAPUFvx6AdoZWFkAAALoAAAACsAAAA2DIPpX2hoZWEAAAvMAAAAGAAAACQOogcgaG10eAAAC+QAAAAPAAAAfNkAAABsb2NhAAAL9AAAAEAAAABAMMg06m1heHAAAAw0AAAAHwAAACABMAB5bmFtZQAADFQAAAElAAACCtXH9aBwb3N0AAANfAAAAPwAAAGBZkSN43icY2BkZ2CcwMDKwMFSyPKMgYHhF4RmjmEIZzzHwMDEwMrMgBUEpLmmMDh8ZPwoxw7iLmSHCDOCCADvEAo+AAB4nGNgYGBmgGAZBkYGEHAB8hjBfBYGDSDNBqQZGZgYGD7K/f8PUvCREUTzM0DVAwEjG8OIBwCPdwbVAAB4nI1Xe1CU1xX/zv1eLItLln0JwrIfC7sJGET2hRJ2N1GUoBJE8AESQEEhmBHjaB7UuBMTO4GMaSu7aY3RNlOdRPNqO2pqRmuTaSZtR6JJILUZk00a/4imjpmiecB303O/XUgMJOPufvd+99xzzz33nN855y4HHH7EfrGfIxwHRiANvF/sH71I9BzHszmpW+rGOQOXxXE6YhI4PoMT8zkT4cDFuf1cwMrZJI5cglM0HKVv0MaUFDgIFfg9mJJCG+kbKn1JkqBOVaFOkuhLpARq8fu0Nnc9/zdvfY9PxXW4PdH0C6N+PCejhorxFjAqRjgFRXSINEARbBGsoxcFK7IJmr4OycFJnInL59zIXwxui80fkGRbEHyosMWaATJKUfCskmwJQsAWANkmnIGOhlf514h7U8HNIv3owoHB0WMt0Eb3sx0guLi5pq/8Ny1q6969fKR9X9GBV6dPv6dp04K99SOwtmyPl47ApRa6n4ZpP1yjr5fn7MmYP/vXLUJs715UguklHBaHOZHZmG1N9FAIW2mf0MqWCIdo/8RZ1yGfxKUldDcGIbFA7ICO+vqOMSPTh/ZrSqgHi/bB/O8E8Mnzp+M+acxfpsTShBwej26TiGxBn7m4eEIO+Rueu6Hj+IFBnh88cAEUEQ//nVLx5C7kf+yIR47QEe+eMlhz9SqsGbe3hh2R03NGzoY6O42Kz8l7fB6fAk6LYnTyFo/FYyT6GGyNx2Jx2sdH4rA1Fo/HyCXaFyOp8dhYBCfJb2NIn1ImE6CYNGmgSTb52DawJR6jfXEmDU4xyTEmpgHHOIStoxfjSGdkbsK2w2jbdMQG4sgAstEONgURYCwGHhEhhscioQaAhhCf7McifEQc0l6+mxj9nI+gmSdiQ0Zbm7gZnIO7GSMEXG6UDAVocxAV8GcEXCKg1a02RcTtwANWRGIAyElor6n/+ZU2yOB3+T77Hb1MLqhn4KHVnQBjJnqe9QZSon6Kc5DxAD2vMdPL/BXSmQGwspa67z9wLUjdi9TN7QC7lyyBr9rpt7uXVC1CMpyjKRoXnGPHTuiaPLsNdc2dbAFQLAooPkXEh33FodHl4XpC6sPCIa0ftUIhHSYXVSu5iME+DIXsbZJ51BeidCgajcai43jU9nVzoSn2dPqcFvSoxSzJzgRKAx47WMRxOrIj3Wf0+hndxhJTiOkSEqxar3b3RKM9hY64oxBA64ieURLvCfpkDb8siBdUJ1bgT+urJ5PGfewQrmm5R5+0HmfyIPySD7OYkT0WxRePah8oEiyjlxIP74thVoRTURpmL6QhGuWS+QDjdANXjIM8SQa/1w128ODx0Qp4aLMNg9+JL3joUn8AMxW+aLNiuKjarn4uyyTdXjOzZTsh21uwldUvJoYza+zELALfu3p1L8/3krtyZ0Ag058J3hxHghvbGZn0dHZy6Mim/7Blre4lpHd1c28yVqRViO153F2oIWoXCIKbL4Z0cM1iaQn9mI5KuV2SzEvWXJDMNtkANpMdQoDDhIdD4A/YrP6Aye9ysxyE+uOEAcTDorgvVZJjcua043PnZ/PmdDqcbibZlXOOT8uSo7Kof0YUn9GL+Jo17ficymxiTofC6znUso0DhAxs1Fo+kF+d36vLmgZ8mk5cdGv2mwYj5k3Dm9m3LhJ1aVRNm6HrTbLgYAoWXDhDd/u4PGy5CT+xGMdiaBovewUCF/1BiWNljI9MLn7jeScpg+WyH6mfU62eVDql7hsrmvx1ezp/YldE2LhjbkiDnAn8tGy/MW3IXRMYJduvq9HpmIcKuFt+JCtgdGEGKAcF6UacVwIYbVPGfw/+YuNBS4cx/CUHcnyfc+wRDMtTr72mMSBjT/yn/GKSdeDWQUCH6Xoqq5R10RE60gV6erUL0iCti16d0hZjxut4QI/rEpgSh6WjnJXdBXRg1GKCucGJPtFqM27aD1tOqqKonsQ2KsFSSmEpmvRlsR+TcD9OFwrqXxIclL4sJTnGMSuG8KpkZvKdeVIOKDyWSyPLV16/p1QMPbP8NihwUzr47bdnXtwtjdCvqqpO0H+pOvIl3Pzv46e5CT/tQjklXCXXym1AaWY7bzHLkuDMc7ldKCvgxzLn8wYkJLBhEDyK7MT8bTbwbkxbfp+3mKAGsmTBpabSIEECzMIcQlzOPAMKsxMs7uhsnxPLuofPDTc1hkuq6MX9j16YU7CqegcYHbmWYuvAP6tCS97tgWf7dlQvnl25YPavXLVZvrzQPeHCpZmzzEUVq/xzu5sChnSTPTW7oOYmh69z4zL/gk3b+O6hoa733uviP82vnFcbqWlc9tDmZa23LVzaV1yXURi+JX+28NeBuj3+O8IrQ080Vm1eWB4OKjPmrJu7c1udWynvKF6/vs479lSW9+5gZkn+dKfellNGDPllzeULustz+A0bPvhgw7lkvEUwn/N4Ty7U7nhGsEpFkOfy+kutbOh1JQxhVDJumoW11hnkPThznh6FFlhfT+ra1x9sF56kx5YuDzVY9PQYAYA7iblw4frQ4TPCk2MK/xGU3rlmze62trHz6lsko+v+So/do74PT8KVkpJfOErKcv8znrMGsHTNxoEkWy1mYgDB6XBbPaWsuiS6CryGaL6zCjaXBgvtkuyXBua1wOKnh+k7L9AvPnYWffxK18FcJbuosGf3/Jo7amY+CE1vppzY+UTrva0FXc1i55pKQ/YjVL187N5fCn1kW5uot/1hi+DiZ+5atnJR9E+prvydJ9ZZ5mwOpU5gM4KYysMBQ71UzPuMTl9QQOyUo5nwioeYCPjFklrbK6s6X+ypUZ6rum9+CZYzWRiBJfSP0xzzSmrg7f86g0DKVj/wwFzieD9rRfPGFbeKMl05pn5j9/rsQJJ2iEgRrpohlyBo3f4QK7Kl+EcAYZgAoNVmZWXK704YAa3FwBxgSGUOs5htvGRz4Sgj3yFkSJFBuv/sxu5yk998T8WDJzvv/2RX19HtTUW1S+wpKRKRjJ6zzz/1/OPdFdWGlAKbvzS4PHOtURikg9AGz0LbIB85S/cPOpoXvuue8/iV2H1vPTy3ddvOeZ37HGmO3OmSzVzR+NS53+84dHlFhXPLqtzSO+5ruHM2vXtBdxP87LOzKAD359j/INYIbyPabIi3Cq6Wa+SaGe78diIzu7qcblcAa6/fJRvNopXFJnO+U9KKM5bqH5LM0iQSVmpPCPDu7ZT4Aoubz3709EBTyrTDjyx8MQXgUH1nqm7TWng4TzE4i4AsKskBITXfSyC4Fkl5MxnJDiKSIDSJAsGvd1y+/eNDp2e+A+5d8HeiiunrTkT6TqWLIs+/QRoWr98s0qj8uuzLuS22Ytufg3rdTaHn1m46sfgGKHXt0MGnLaRHdnwN37tvHcWKo2V6lnPxL4UvUQcRdOzmZSQs8X5CH5OxXMXpkATuDz8Et0SH4uyCRR+TjmBDP1GvsVrWEGVzEj33YVQ9jAtIKpqsl/s/0xrocwAAeJxjYGRgYADig3cEzsTz23xl4GZnAIHLRucNkWl2BrA4BwMTiAIAF4IITwB4nGNgZGBgZwCChWASxGZkQAXyABOUANh4nGNnYGBgHyAMADa8ANoAAAAAAAAOAFAAZgCyAMYA5gEeAUgBdAGcAfICLgKOAroDCgOOA7AD6gQ4BHwEuAToBQwFogXoBjYGbAbaB3IHqHicY2BkYGCQZ8hlYGcAASYg5gJCBob/YD4DABbVAaoAeJxdkE1qg0AYhl8Tk9AIoVDaVSmzahcF87PMARLIMoFAl0ZHY1BHdBJIT9AT9AQ9RQ9Qeqy+yteNMzDzfM+88w0K4BY/cNAMB6N2bUaPPBLukybCLvleeAAPj8JD+hfhMV7hC3u4wxs7OO4NzQSZcI/8Ltwnfwi75E/hAR7wJTyk/xYeY49fYQ/PztM+jbTZ7LY6OWdBJdX/pqs6NYWa+zMxa13oKrA6Uoerqi/JwtpYxZXJ1coUVmeZUWVlTjq0/tHacjmdxuL90OR8O0UEDYMNdtiSEpz5XQGqzlm30kzUdAYFFOb8R7NOZk0q2lwAyz1i7oAr1xoXvrOgtYhZx8wY5KRV269JZ5yGpmzPTjQhvY9je6vEElPOuJP3mWKnP5M3V+YAAAB4nG2P2XLCMAxFfYFspGUp3Te+IB9lHJF4cOzUS2n/voaEGR6qB+lKo+WITdhga/a/bRnDBFPMkCBFhhwF5ihxg1sssMQKa9xhg3s84BFPeMYLXvGGd3zgE9tZr/hveXKVkFYoSnoeHJXfRoWOqi54mo9ameNFdrK+dLSyaVf7oJQTlkhXpD3Z5XXhR/rUfQVuKXO91Jps4cLOS6/I5YL3XhodRRsVWZe4NnZOhWnSAWgxhMoEr6SmzZieF43Mk7ZOBdeCVGrp9Eu+54J2xhySplfB5XHwQLXUmT9KH6+kPnQ7ZYuIEzNyfs1DLU1VU4SWZ6LkXGHsD1ZKbMw=) format("woff"), url(data:application/x-font-ttf;charset=utf-8;base64,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FjY3PgE3LgEnIwYfAR4BFw4BBTM/ARUzESMGAyUVJwMchM2UWwgNq4JHrQgBAapUaAoJcWMBfiIhDiMrAQJLMB0BBAokNAIBPmMiIQ4iLAECSzAeAQUKJDQBP2MiIQ4iLAECSzAeAQUKJDQBAT75g+5B4arNLNIBJ44ByQL9BQ9mvYCKwA8FBQMDwwJVTGdzBf6VB8IHNR08lld9uT4LCRA/qGNxvUwHNR08lld9uT4LCRA/qGNxvUwHNR08lld9uT4LCRA/qGNxvVJkAWUDDEf+tYP5AQAAAAEAAAAABiAGtgAbAAABBAADER4BFzMRITU2ADcWABcVIREzPgE3EQIAA4D+4v6FBwJ/X+D+1QYBJ97eAScG/tXgX38CB/6FBrUH/oX+4v32X38CAlWV3gEnBgb+2d6V/asCf18CCgEeAXsAAAAAEADGAAEAAAAAAAEABwAAAAEAAAAAAAIABwAHAAEAAAAAAAMABwAOAAEAAAAAAAQABwAVAAEAAAAAAAUACwAcAAEAAAAAAAYABwAnAAEAAAAAAAoAKwAuAAEAAAAAAAsAEwBZAAMAAQQJAAEADgBsAAMAAQQJAAIADgB6AAMAAQQJAAMADgCIAAMAAQQJAAQADgCWAAMAAQQJAAUAFgCkAAMAAQQJAAYADgC6AAMAAQQJAAoAVgDIAAMAAQQJAAsAJgEeVmlkZW9KU1JlZ3VsYXJWaWRlb0pTVmlkZW9KU1ZlcnNpb24gMS4wVmlkZW9KU0dlbmVyYXRlZCBieSBzdmcydHRmIGZyb20gRm9udGVsbG8gcHJvamVjdC5odHRwOi8vZm9udGVsbG8uY29tAFYAaQBkAGUAbwBKAFMAUgBlAGcAdQBsAGEAcgBWAGkAZABlAG8ASgBTAFYAaQBkAGUAbwBKAFMAVgBlAHIAcwBpAG8AbgAgADEALgAwAFYAaQBkAGUAbwBKAFMARwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABzAHYAZwAyAHQAdABmACAAZgByAG8AbQAgAEYAbwBuAHQAZQBsAGwAbwAgAHAAcgBvAGoAZQBjAHQALgBoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAAAAAgAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfAAABAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMBFAEVARYBFwEYARkBGgEbARwBHQEeAR8EcGxheQtwbGF5LWNpcmNsZQVwYXVzZQt2b2x1bWUtbXV0ZQp2b2x1bWUtbG93CnZvbHVtZS1taWQLdm9sdW1lLWhpZ2gQZnVsbHNjcmVlbi1lbnRlcg9mdWxsc2NyZWVuLWV4aXQGc3F1YXJlB3NwaW5uZXIJc3VidGl0bGVzCGNhcHRpb25zCGNoYXB0ZXJzBXNoYXJlA2NvZwZjaXJjbGUOY2lyY2xlLW91dGxpbmUTY2lyY2xlLWlubmVyLWNpcmNsZQJoZAZjYW5jZWwGcmVwbGF5CGZhY2Vib29rBWdwbHVzCGxpbmtlZGluB3R3aXR0ZXIGdHVtYmxyCXBpbnRlcmVzdBFhdWRpby1kZXNjcmlwdGlvbgVhdWRpbwAAAAAA) format("truetype"); + font-weight: normal; + font-style: normal; } + +.vjs-icon-play, .video-js .vjs-big-play-button, .video-js .vjs-play-control { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-play:before, .video-js .vjs-big-play-button:before, .video-js .vjs-play-control:before { + content: "\f101"; } + +.vjs-icon-play-circle { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-play-circle:before { + content: "\f102"; } + +.vjs-icon-pause, .video-js .vjs-play-control.vjs-playing { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-pause:before, .video-js .vjs-play-control.vjs-playing:before { + content: "\f103"; } + +.vjs-icon-volume-mute, .video-js .vjs-mute-control.vjs-vol-0, +.video-js .vjs-volume-menu-button.vjs-vol-0 { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-volume-mute:before, .video-js .vjs-mute-control.vjs-vol-0:before, + .video-js .vjs-volume-menu-button.vjs-vol-0:before { + content: "\f104"; } + +.vjs-icon-volume-low, .video-js .vjs-mute-control.vjs-vol-1, +.video-js .vjs-volume-menu-button.vjs-vol-1 { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-volume-low:before, .video-js .vjs-mute-control.vjs-vol-1:before, + .video-js .vjs-volume-menu-button.vjs-vol-1:before { + content: "\f105"; } + +.vjs-icon-volume-mid, .video-js .vjs-mute-control.vjs-vol-2, +.video-js .vjs-volume-menu-button.vjs-vol-2 { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-volume-mid:before, .video-js .vjs-mute-control.vjs-vol-2:before, + .video-js .vjs-volume-menu-button.vjs-vol-2:before { + content: "\f106"; } + +.vjs-icon-volume-high, .video-js .vjs-mute-control, +.video-js .vjs-volume-menu-button { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-volume-high:before, .video-js .vjs-mute-control:before, + .video-js .vjs-volume-menu-button:before { + content: "\f107"; } + +.vjs-icon-fullscreen-enter, .video-js .vjs-fullscreen-control { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-fullscreen-enter:before, .video-js .vjs-fullscreen-control:before { + content: "\f108"; } + +.vjs-icon-fullscreen-exit, .video-js.vjs-fullscreen .vjs-fullscreen-control { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-fullscreen-exit:before, .video-js.vjs-fullscreen .vjs-fullscreen-control:before { + content: "\f109"; } + +.vjs-icon-square { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-square:before { + content: "\f10a"; } + +.vjs-icon-spinner { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-spinner:before { + content: "\f10b"; } + +.vjs-icon-subtitles, .video-js .vjs-subtitles-button { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-subtitles:before, .video-js .vjs-subtitles-button:before { + content: "\f10c"; } + +.vjs-icon-captions, .video-js .vjs-captions-button { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-captions:before, .video-js .vjs-captions-button:before { + content: "\f10d"; } + +.vjs-icon-chapters, .video-js .vjs-chapters-button { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-chapters:before, .video-js .vjs-chapters-button:before { + content: "\f10e"; } + +.vjs-icon-share { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-share:before { + content: "\f10f"; } + +.vjs-icon-cog { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-cog:before { + content: "\f110"; } + +.vjs-icon-circle, .video-js .vjs-mouse-display, .video-js .vjs-play-progress, .video-js .vjs-volume-level { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-circle:before, .video-js .vjs-mouse-display:before, .video-js .vjs-play-progress:before, .video-js .vjs-volume-level:before { + content: "\f111"; } + +.vjs-icon-circle-outline { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-circle-outline:before { + content: "\f112"; } + +.vjs-icon-circle-inner-circle { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-circle-inner-circle:before { + content: "\f113"; } + +.vjs-icon-hd { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-hd:before { + content: "\f114"; } + +.vjs-icon-cancel, .video-js .vjs-control.vjs-close-button { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-cancel:before, .video-js .vjs-control.vjs-close-button:before { + content: "\f115"; } + +.vjs-icon-replay { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-replay:before { + content: "\f116"; } + +.vjs-icon-facebook { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-facebook:before { + content: "\f117"; } + +.vjs-icon-gplus { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-gplus:before { + content: "\f118"; } + +.vjs-icon-linkedin { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-linkedin:before { + content: "\f119"; } + +.vjs-icon-twitter { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-twitter:before { + content: "\f11a"; } + +.vjs-icon-tumblr { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-tumblr:before { + content: "\f11b"; } + +.vjs-icon-pinterest { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-pinterest:before { + content: "\f11c"; } + +.vjs-icon-audio-description, .video-js .vjs-descriptions-button { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-audio-description:before, .video-js .vjs-descriptions-button:before { + content: "\f11d"; } + +.vjs-icon-audio, .video-js .vjs-audio-button { + font-family: VideoJS; + font-weight: normal; + font-style: normal; } + .vjs-icon-audio:before, .video-js .vjs-audio-button:before { + content: "\f11e"; } + +.video-js { + display: block; + vertical-align: top; + box-sizing: border-box; + color: #fff; + background-color: #000; + position: relative; + padding: 0; + font-size: 10px; + line-height: 1; + font-weight: normal; + font-style: normal; + font-family: Arial, Helvetica, sans-serif; } + .video-js:-moz-full-screen { + position: absolute; } + .video-js:-webkit-full-screen { + width: 100% !important; + height: 100% !important; } + +.video-js *, +.video-js *:before, +.video-js *:after { + box-sizing: inherit; } + +.video-js ul { + font-family: inherit; + font-size: inherit; + line-height: inherit; + list-style-position: outside; + margin-left: 0; + margin-right: 0; + margin-top: 0; + margin-bottom: 0; } + +.video-js.vjs-fluid, +.video-js.vjs-16-9, +.video-js.vjs-4-3 { + width: 100%; + max-width: 100%; + height: 0; } + +.video-js.vjs-16-9 { + padding-top: 56.25%; } + +.video-js.vjs-4-3 { + padding-top: 75%; } + +.video-js.vjs-fill { + width: 100%; + height: 100%; } + +.video-js .vjs-tech { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; } + +body.vjs-full-window { + padding: 0; + margin: 0; + height: 100%; + overflow-y: auto; } + +.vjs-full-window .video-js.vjs-fullscreen { + position: fixed; + overflow: hidden; + z-index: 1000; + left: 0; + top: 0; + bottom: 0; + right: 0; } + +.video-js.vjs-fullscreen { + width: 100% !important; + height: 100% !important; + padding-top: 0 !important; } + +.video-js.vjs-fullscreen.vjs-user-inactive { + cursor: none; } + +.vjs-hidden { + display: none !important; } + +.vjs-disabled { + opacity: 0.5; + cursor: default; } + +.video-js .vjs-offscreen { + height: 1px; + left: -9999px; + position: absolute; + top: 0; + width: 1px; } + +.vjs-lock-showing { + display: block !important; + opacity: 1; + visibility: visible; } + +.vjs-no-js { + padding: 20px; + color: #fff; + background-color: #000; + font-size: 18px; + font-family: Arial, Helvetica, sans-serif; + text-align: center; + width: 300px; + height: 150px; + margin: 0px auto; } + +.vjs-no-js a, +.vjs-no-js a:visited { + color: #66A8CC; } + +.video-js .vjs-big-play-button { + font-size: 3em; + line-height: 1.5em; + height: 1.5em; + width: 3em; + display: block; + position: absolute; + top: 10px; + left: 10px; + padding: 0; + cursor: pointer; + opacity: 1; + border: 0.06666em solid #fff; + background-color: #2B333F; + background-color: rgba(43, 51, 63, 0.7); + -webkit-border-radius: 0.3em; + -moz-border-radius: 0.3em; + border-radius: 0.3em; + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -o-transition: all 0.4s; + transition: all 0.4s; } + +.vjs-big-play-centered .vjs-big-play-button { + top: 50%; + left: 50%; + margin-top: -0.75em; + margin-left: -1.5em; } + +.video-js:hover .vjs-big-play-button, +.video-js .vjs-big-play-button:focus { + outline: 0; + border-color: #fff; + background-color: #73859f; + background-color: rgba(115, 133, 159, 0.5); + -webkit-transition: all 0s; + -moz-transition: all 0s; + -o-transition: all 0s; + transition: all 0s; } + +.vjs-controls-disabled .vjs-big-play-button, +.vjs-has-started .vjs-big-play-button, +.vjs-using-native-controls .vjs-big-play-button, +.vjs-error .vjs-big-play-button { + display: none; } + +.vjs-has-started.vjs-paused.vjs-show-big-play-button-on-pause .vjs-big-play-button { + display: block; } + +.video-js button { + background: none; + border: none; + color: inherit; + display: inline-block; + overflow: visible; + font-size: inherit; + line-height: inherit; + text-transform: none; + text-decoration: none; + transition: none; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; } + +.video-js .vjs-control.vjs-close-button { + cursor: pointer; + height: 3em; + position: absolute; + right: 0; + top: 0.5em; + z-index: 2; } + +.vjs-menu-button { + cursor: pointer; } + +.vjs-menu-button.vjs-disabled { + cursor: default; } + +.vjs-workinghover .vjs-menu-button.vjs-disabled:hover .vjs-menu { + display: none; } + +.vjs-menu .vjs-menu-content { + display: block; + padding: 0; + margin: 0; + overflow: auto; + font-family: Arial, Helvetica, sans-serif; } + +.vjs-scrubbing .vjs-menu-button:hover .vjs-menu { + display: none; } + +.vjs-menu li { + list-style: none; + margin: 0; + padding: 0.2em 0; + line-height: 1.4em; + font-size: 1.2em; + text-align: center; + text-transform: lowercase; } + +.vjs-menu li.vjs-menu-item:focus, +.vjs-menu li.vjs-menu-item:hover { + outline: 0; + background-color: #73859f; + background-color: rgba(115, 133, 159, 0.5); } + +.vjs-menu li.vjs-selected, +.vjs-menu li.vjs-selected:focus, +.vjs-menu li.vjs-selected:hover { + background-color: #fff; + color: #2B333F; } + +.vjs-menu li.vjs-menu-title { + text-align: center; + text-transform: uppercase; + font-size: 1em; + line-height: 2em; + padding: 0; + margin: 0 0 0.3em 0; + font-weight: bold; + cursor: default; } + +.vjs-menu-button-popup .vjs-menu { + display: none; + position: absolute; + bottom: 0; + width: 10em; + left: -3em; + height: 0em; + margin-bottom: 1.5em; + border-top-color: rgba(43, 51, 63, 0.7); } + +.vjs-menu-button-popup .vjs-menu .vjs-menu-content { + background-color: #2B333F; + background-color: rgba(43, 51, 63, 0.7); + position: absolute; + width: 100%; + bottom: 1.5em; + max-height: 15em; } + +.vjs-workinghover .vjs-menu-button-popup:hover .vjs-menu, +.vjs-menu-button-popup .vjs-menu.vjs-lock-showing { + display: block; } + +.video-js .vjs-menu-button-inline { + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -o-transition: all 0.4s; + transition: all 0.4s; + overflow: hidden; } + +.video-js .vjs-menu-button-inline:before { + width: 2.222222222em; } + +.video-js .vjs-menu-button-inline:hover, +.video-js .vjs-menu-button-inline:focus, +.video-js .vjs-menu-button-inline.vjs-slider-active, +.video-js.vjs-no-flex .vjs-menu-button-inline { + width: 12em; } + +.video-js .vjs-menu-button-inline.vjs-slider-active { + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; } + +.vjs-menu-button-inline .vjs-menu { + opacity: 0; + height: 100%; + width: auto; + position: absolute; + left: 4em; + top: 0; + padding: 0; + margin: 0; + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -o-transition: all 0.4s; + transition: all 0.4s; } + +.vjs-menu-button-inline:hover .vjs-menu, +.vjs-menu-button-inline:focus .vjs-menu, +.vjs-menu-button-inline.vjs-slider-active .vjs-menu { + display: block; + opacity: 1; } + +.vjs-no-flex .vjs-menu-button-inline .vjs-menu { + display: block; + opacity: 1; + position: relative; + width: auto; } + +.vjs-no-flex .vjs-menu-button-inline:hover .vjs-menu, +.vjs-no-flex .vjs-menu-button-inline:focus .vjs-menu, +.vjs-no-flex .vjs-menu-button-inline.vjs-slider-active .vjs-menu { + width: auto; } + +.vjs-menu-button-inline .vjs-menu-content { + width: auto; + height: 100%; + margin: 0; + overflow: hidden; } + +.video-js .vjs-control-bar { + display: none; + width: 100%; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 3.0em; + background-color: #2B333F; + background-color: rgba(43, 51, 63, 0.7); } + +.vjs-has-started .vjs-control-bar { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + visibility: visible; + opacity: 1; + -webkit-transition: visibility 0.1s, opacity 0.1s; + -moz-transition: visibility 0.1s, opacity 0.1s; + -o-transition: visibility 0.1s, opacity 0.1s; + transition: visibility 0.1s, opacity 0.1s; } + +.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { + visibility: visible; + opacity: 0; + -webkit-transition: visibility 1s, opacity 1s; + -moz-transition: visibility 1s, opacity 1s; + -o-transition: visibility 1s, opacity 1s; + transition: visibility 1s, opacity 1s; } + +.vjs-controls-disabled .vjs-control-bar, +.vjs-using-native-controls .vjs-control-bar, +.vjs-error .vjs-control-bar { + display: none !important; } + +.vjs-audio.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { + opacity: 1; + visibility: visible; } + +.vjs-has-started.vjs-no-flex .vjs-control-bar { + display: table; } + +.video-js .vjs-control { + outline: none; + position: relative; + text-align: center; + margin: 0; + padding: 0; + height: 100%; + width: 4em; + -webkit-box-flex: none; + -moz-box-flex: none; + -webkit-flex: none; + -ms-flex: none; + flex: none; } + .video-js .vjs-control:before { + font-size: 1.8em; + line-height: 1.67; } + +.video-js .vjs-control:focus:before, +.video-js .vjs-control:hover:before, +.video-js .vjs-control:focus { + text-shadow: 0em 0em 1em white; } + +.video-js .vjs-control-text { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; } + +.vjs-no-flex .vjs-control { + display: table-cell; + vertical-align: middle; } + +.video-js .vjs-custom-control-spacer { + display: none; } + +.video-js .vjs-progress-control { + -webkit-box-flex: auto; + -moz-box-flex: auto; + -webkit-flex: auto; + -ms-flex: auto; + flex: auto; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + min-width: 4em; } + +.vjs-live .vjs-progress-control { + display: none; } + +.video-js .vjs-progress-holder { + -webkit-box-flex: auto; + -moz-box-flex: auto; + -webkit-flex: auto; + -ms-flex: auto; + flex: auto; + -webkit-transition: all 0.2s; + -moz-transition: all 0.2s; + -o-transition: all 0.2s; + transition: all 0.2s; + height: 0.3em; } + +.video-js .vjs-progress-control:hover .vjs-progress-holder { + font-size: 1.666666666666666666em; } + +/* If we let the font size grow as much as everything else, the current time tooltip ends up + ginormous. If you'd like to enable the current time tooltip all the time, this should be disabled + to avoid a weird hitch when you roll off the hover. */ +.video-js .vjs-progress-control:hover .vjs-time-tooltip, +.video-js .vjs-progress-control:hover .vjs-mouse-display:after, +.video-js .vjs-progress-control:hover .vjs-play-progress:after { + font-family: Arial, Helvetica, sans-serif; + visibility: visible; + font-size: 0.6em; } + +.video-js .vjs-progress-holder .vjs-play-progress, +.video-js .vjs-progress-holder .vjs-load-progress, +.video-js .vjs-progress-holder .vjs-tooltip-progress-bar, +.video-js .vjs-progress-holder .vjs-load-progress div { + position: absolute; + display: block; + height: 100%; + margin: 0; + padding: 0; + width: 0; + left: 0; + top: 0; } + +.video-js .vjs-mouse-display:before { + display: none; } + +.video-js .vjs-play-progress { + background-color: #fff; } + .video-js .vjs-play-progress:before { + position: absolute; + top: -0.333333333333333em; + right: -0.5em; + font-size: 0.9em; } + +.video-js .vjs-time-tooltip, +.video-js .vjs-mouse-display:after, +.video-js .vjs-play-progress:after { + visibility: hidden; + pointer-events: none; + position: absolute; + top: -3.4em; + right: -1.9em; + font-size: 0.9em; + color: #000; + content: attr(data-current-time); + padding: 6px 8px 8px 8px; + background-color: #fff; + background-color: rgba(255, 255, 255, 0.8); + -webkit-border-radius: 0.3em; + -moz-border-radius: 0.3em; + border-radius: 0.3em; } + +.video-js .vjs-time-tooltip, +.video-js .vjs-play-progress:before, +.video-js .vjs-play-progress:after { + z-index: 1; } + +.video-js .vjs-progress-control .vjs-keep-tooltips-inside:after { + display: none; } + +.video-js .vjs-load-progress { + background: #bfc7d3; + background: rgba(115, 133, 159, 0.5); } + +.video-js .vjs-load-progress div { + background: white; + background: rgba(115, 133, 159, 0.75); } + +.video-js.vjs-no-flex .vjs-progress-control { + width: auto; } + +.video-js .vjs-time-tooltip { + display: inline-block; + height: 2.4em; + position: relative; + float: right; + right: -1.9em; } + +.vjs-tooltip-progress-bar { + visibility: hidden; } + +.video-js .vjs-progress-control .vjs-mouse-display { + display: none; + position: absolute; + width: 1px; + height: 100%; + background-color: #000; + z-index: 1; } + +.vjs-no-flex .vjs-progress-control .vjs-mouse-display { + z-index: 0; } + +.video-js .vjs-progress-control:hover .vjs-mouse-display { + display: block; } + +.video-js.vjs-user-inactive .vjs-progress-control .vjs-mouse-display, +.video-js.vjs-user-inactive .vjs-progress-control .vjs-mouse-display:after { + visibility: hidden; + opacity: 0; + -webkit-transition: visibility 1s, opacity 1s; + -moz-transition: visibility 1s, opacity 1s; + -o-transition: visibility 1s, opacity 1s; + transition: visibility 1s, opacity 1s; } + +.video-js.vjs-user-inactive.vjs-no-flex .vjs-progress-control .vjs-mouse-display, +.video-js.vjs-user-inactive.vjs-no-flex .vjs-progress-control .vjs-mouse-display:after { + display: none; } + +.vjs-mouse-display .vjs-time-tooltip, +.video-js .vjs-progress-control .vjs-mouse-display:after { + color: #fff; + background-color: #000; + background-color: rgba(0, 0, 0, 0.8); } + +.video-js .vjs-slider { + outline: 0; + position: relative; + cursor: pointer; + padding: 0; + margin: 0 0.45em 0 0.45em; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-color: #73859f; + background-color: rgba(115, 133, 159, 0.5); } + +.video-js .vjs-slider:focus { + text-shadow: 0em 0em 1em white; + -webkit-box-shadow: 0 0 1em #fff; + -moz-box-shadow: 0 0 1em #fff; + box-shadow: 0 0 1em #fff; } + +.video-js .vjs-mute-control, +.video-js .vjs-volume-menu-button { + cursor: pointer; + -webkit-box-flex: none; + -moz-box-flex: none; + -webkit-flex: none; + -ms-flex: none; + flex: none; } + +.video-js .vjs-volume-control { + width: 5em; + -webkit-box-flex: none; + -moz-box-flex: none; + -webkit-flex: none; + -ms-flex: none; + flex: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; } + +.video-js .vjs-volume-bar { + margin: 1.35em 0.45em; } + +.vjs-volume-bar.vjs-slider-horizontal { + width: 5em; + height: 0.3em; } + +.vjs-volume-bar.vjs-slider-vertical { + width: 0.3em; + height: 5em; + margin: 1.35em auto; } + +.video-js .vjs-volume-level { + position: absolute; + bottom: 0; + left: 0; + background-color: #fff; } + .video-js .vjs-volume-level:before { + position: absolute; + font-size: 0.9em; } + +.vjs-slider-vertical .vjs-volume-level { + width: 0.3em; } + .vjs-slider-vertical .vjs-volume-level:before { + top: -0.5em; + left: -0.3em; } + +.vjs-slider-horizontal .vjs-volume-level { + height: 0.3em; } + .vjs-slider-horizontal .vjs-volume-level:before { + top: -0.3em; + right: -0.5em; } + +.vjs-volume-bar.vjs-slider-vertical .vjs-volume-level { + height: 100%; } + +.vjs-volume-bar.vjs-slider-horizontal .vjs-volume-level { + width: 100%; } + +.vjs-menu-button-popup.vjs-volume-menu-button .vjs-menu { + display: block; + width: 0; + height: 0; + border-top-color: transparent; } + +.vjs-menu-button-popup.vjs-volume-menu-button-vertical .vjs-menu { + left: 0.5em; + height: 8em; } + +.vjs-menu-button-popup.vjs-volume-menu-button-horizontal .vjs-menu { + left: -2em; } + +.vjs-menu-button-popup.vjs-volume-menu-button .vjs-menu-content { + height: 0; + width: 0; + overflow-x: hidden; + overflow-y: hidden; } + +.vjs-volume-menu-button-vertical:hover .vjs-menu-content, +.vjs-volume-menu-button-vertical:focus .vjs-menu-content, +.vjs-volume-menu-button-vertical.vjs-slider-active .vjs-menu-content, +.vjs-volume-menu-button-vertical .vjs-lock-showing .vjs-menu-content { + height: 8em; + width: 2.9em; } + +.vjs-volume-menu-button-horizontal:hover .vjs-menu-content, +.vjs-volume-menu-button-horizontal:focus .vjs-menu-content, +.vjs-volume-menu-button-horizontal .vjs-slider-active .vjs-menu-content, +.vjs-volume-menu-button-horizontal .vjs-lock-showing .vjs-menu-content { + height: 2.9em; + width: 8em; } + +.vjs-volume-menu-button.vjs-menu-button-inline .vjs-menu-content { + background-color: transparent !important; } + +.vjs-poster { + display: inline-block; + vertical-align: middle; + background-repeat: no-repeat; + background-position: 50% 50%; + background-size: contain; + background-color: #000000; + cursor: pointer; + margin: 0; + padding: 0; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + height: 100%; } + +.vjs-poster img { + display: block; + vertical-align: middle; + margin: 0 auto; + max-height: 100%; + padding: 0; + width: 100%; } + +.vjs-has-started .vjs-poster { + display: none; } + +.vjs-audio.vjs-has-started .vjs-poster { + display: block; } + +.vjs-using-native-controls .vjs-poster { + display: none; } + +.video-js .vjs-live-control { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: flex-start; + -webkit-align-items: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + -webkit-box-flex: auto; + -moz-box-flex: auto; + -webkit-flex: auto; + -ms-flex: auto; + flex: auto; + font-size: 1em; + line-height: 3em; } + +.vjs-no-flex .vjs-live-control { + display: table-cell; + width: auto; + text-align: left; } + +.video-js .vjs-time-control { + -webkit-box-flex: none; + -moz-box-flex: none; + -webkit-flex: none; + -ms-flex: none; + flex: none; + font-size: 1em; + line-height: 3em; + min-width: 2em; + width: auto; + padding-left: 1em; + padding-right: 1em; } + +.vjs-live .vjs-time-control { + display: none; } + +.video-js .vjs-current-time, +.vjs-no-flex .vjs-current-time { + display: none; } + +.video-js .vjs-duration, +.vjs-no-flex .vjs-duration { + display: none; } + +.vjs-time-divider { + display: none; + line-height: 3em; } + +.vjs-live .vjs-time-divider { + display: none; } + +.video-js .vjs-play-control { + cursor: pointer; + -webkit-box-flex: none; + -moz-box-flex: none; + -webkit-flex: none; + -ms-flex: none; + flex: none; } + +.vjs-text-track-display { + position: absolute; + bottom: 3em; + left: 0; + right: 0; + top: 0; + pointer-events: none; } + +.video-js.vjs-user-inactive.vjs-playing .vjs-text-track-display { + bottom: 1em; } + +.video-js .vjs-text-track { + font-size: 1.4em; + text-align: center; + margin-bottom: 0.1em; + background-color: #000; + background-color: rgba(0, 0, 0, 0.5); } + +.vjs-subtitles { + color: #fff; } + +.vjs-captions { + color: #fc6; } + +.vjs-tt-cue { + display: block; } + +video::-webkit-media-text-track-display { + -moz-transform: translateY(-3em); + -ms-transform: translateY(-3em); + -o-transform: translateY(-3em); + -webkit-transform: translateY(-3em); + transform: translateY(-3em); } + +.video-js.vjs-user-inactive.vjs-playing video::-webkit-media-text-track-display { + -moz-transform: translateY(-1.5em); + -ms-transform: translateY(-1.5em); + -o-transform: translateY(-1.5em); + -webkit-transform: translateY(-1.5em); + transform: translateY(-1.5em); } + +.video-js .vjs-fullscreen-control { + cursor: pointer; + -webkit-box-flex: none; + -moz-box-flex: none; + -webkit-flex: none; + -ms-flex: none; + flex: none; } + +.vjs-playback-rate .vjs-playback-rate-value { + font-size: 1.5em; + line-height: 2; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + text-align: center; } + +.vjs-playback-rate .vjs-menu { + width: 4em; + left: 0em; } + +.vjs-error .vjs-error-display .vjs-modal-dialog-content { + font-size: 1.4em; + text-align: center; } + +.vjs-error .vjs-error-display:before { + color: #fff; + content: 'X'; + font-family: Arial, Helvetica, sans-serif; + font-size: 4em; + left: 0; + line-height: 1; + margin-top: -0.5em; + position: absolute; + text-shadow: 0.05em 0.05em 0.1em #000; + text-align: center; + top: 50%; + vertical-align: middle; + width: 100%; } + +.vjs-loading-spinner { + display: none; + position: absolute; + top: 50%; + left: 50%; + margin: -25px 0 0 -25px; + opacity: 0.85; + text-align: left; + border: 6px solid rgba(43, 51, 63, 0.7); + box-sizing: border-box; + background-clip: padding-box; + width: 50px; + height: 50px; + border-radius: 25px; } + +.vjs-seeking .vjs-loading-spinner, +.vjs-waiting .vjs-loading-spinner { + display: block; } + +.vjs-loading-spinner:before, +.vjs-loading-spinner:after { + content: ""; + position: absolute; + margin: -6px; + box-sizing: inherit; + width: inherit; + height: inherit; + border-radius: inherit; + opacity: 1; + border: inherit; + border-color: transparent; + border-top-color: white; } + +.vjs-seeking .vjs-loading-spinner:before, +.vjs-seeking .vjs-loading-spinner:after, +.vjs-waiting .vjs-loading-spinner:before, +.vjs-waiting .vjs-loading-spinner:after { + -webkit-animation: vjs-spinner-spin 1.1s cubic-bezier(0.6, 0.2, 0, 0.8) infinite, vjs-spinner-fade 1.1s linear infinite; + animation: vjs-spinner-spin 1.1s cubic-bezier(0.6, 0.2, 0, 0.8) infinite, vjs-spinner-fade 1.1s linear infinite; } + +.vjs-seeking .vjs-loading-spinner:before, +.vjs-waiting .vjs-loading-spinner:before { + border-top-color: white; } + +.vjs-seeking .vjs-loading-spinner:after, +.vjs-waiting .vjs-loading-spinner:after { + border-top-color: white; + -webkit-animation-delay: 0.44s; + animation-delay: 0.44s; } + +@keyframes vjs-spinner-spin { + 100% { + transform: rotate(360deg); } } + +@-webkit-keyframes vjs-spinner-spin { + 100% { + -webkit-transform: rotate(360deg); } } + +@keyframes vjs-spinner-fade { + 0% { + border-top-color: #73859f; } + 20% { + border-top-color: #73859f; } + 35% { + border-top-color: white; } + 60% { + border-top-color: #73859f; } + 100% { + border-top-color: #73859f; } } + +@-webkit-keyframes vjs-spinner-fade { + 0% { + border-top-color: #73859f; } + 20% { + border-top-color: #73859f; } + 35% { + border-top-color: white; } + 60% { + border-top-color: #73859f; } + 100% { + border-top-color: #73859f; } } + +.vjs-chapters-button .vjs-menu ul { + width: 24em; } + +.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-custom-control-spacer { + -webkit-box-flex: auto; + -moz-box-flex: auto; + -webkit-flex: auto; + -ms-flex: auto; + flex: auto; } + +.video-js.vjs-layout-tiny:not(.vjs-fullscreen).vjs-no-flex .vjs-custom-control-spacer { + width: auto; } + +.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-current-time, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-time-divider, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-duration, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-remaining-time, +.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-playback-rate, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-progress-control, +.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-mute-control, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-volume-control, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-volume-menu-button, +.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-chapters-button, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-descriptions-button, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-captions-button, +.video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-subtitles-button, .video-js.vjs-layout-tiny:not(.vjs-fullscreen) .vjs-audio-button { + display: none; } + +.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-current-time, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-time-divider, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-duration, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-remaining-time, +.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-playback-rate, +.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-mute-control, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-volume-control, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-volume-menu-button, +.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-chapters-button, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-descriptions-button, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-captions-button, +.video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-subtitles-button, .video-js.vjs-layout-x-small:not(.vjs-fullscreen) .vjs-audio-button { + display: none; } + +.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-current-time, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-time-divider, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-duration, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-remaining-time, +.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-playback-rate, +.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-mute-control, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-volume-control, +.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-chapters-button, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-descriptions-button, .video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-captions-button, +.video-js.vjs-layout-small:not(.vjs-fullscreen) .vjs-subtitles-button .vjs-audio-button { + display: none; } + +.vjs-caption-settings { + position: relative; + top: 1em; + background-color: #2B333F; + background-color: rgba(43, 51, 63, 0.75); + color: #fff; + margin: 0 auto; + padding: 0.5em; + height: 16em; + font-size: 12px; + width: 40em; } + +.vjs-caption-settings .vjs-tracksettings { + top: 0; + bottom: 1em; + left: 0; + right: 0; + position: absolute; + overflow: auto; } + +.vjs-caption-settings .vjs-tracksettings-colors, +.vjs-caption-settings .vjs-tracksettings-font { + float: left; } + +.vjs-caption-settings .vjs-tracksettings-colors:after, +.vjs-caption-settings .vjs-tracksettings-font:after, +.vjs-caption-settings .vjs-tracksettings-controls:after { + clear: both; } + +.vjs-caption-settings .vjs-tracksettings-controls { + position: absolute; + bottom: 1em; + right: 1em; } + +.vjs-caption-settings .vjs-tracksetting { + margin: 5px; + padding: 3px; + min-height: 40px; + border: none; } + +.vjs-caption-settings .vjs-tracksetting label, +.vjs-caption-settings .vjs-tracksetting legend { + display: block; + width: 100px; + margin-bottom: 5px; } + +.vjs-caption-settings .vjs-tracksetting span { + display: inline; + margin-left: 5px; + vertical-align: top; + float: right; } + +.vjs-caption-settings .vjs-tracksetting > div { + margin-bottom: 5px; + min-height: 20px; } + +.vjs-caption-settings .vjs-tracksetting > div:last-child { + margin-bottom: 0; + padding-bottom: 0; + min-height: 0; } + +.vjs-caption-settings label > input { + margin-right: 10px; } + +.vjs-caption-settings fieldset { + margin-top: 1em; + margin-left: .5em; } + +.vjs-caption-settings fieldset .vjs-label { + position: absolute; + clip: rect(1px 1px 1px 1px); + /* for Internet Explorer */ + clip: rect(1px, 1px, 1px, 1px); + padding: 0; + border: 0; + height: 1px; + width: 1px; + overflow: hidden; } + +.vjs-caption-settings input[type="button"] { + width: 40px; + height: 40px; } + +.video-js .vjs-modal-dialog { + background: rgba(0, 0, 0, 0.8); + background: -webkit-linear-gradient(-90deg, rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0)); + background: linear-gradient(180deg, rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0)); } + +.vjs-modal-dialog .vjs-modal-dialog-content { + font-size: 1.2em; + line-height: 1.5; + padding: 20px 24px; + z-index: 1; } + +@media print { + .video-js > *:not(.vjs-tech):not(.vjs-poster) { + visibility: hidden; } } + +@media \0screen { + .vjs-user-inactive.vjs-playing .vjs-control-bar :before { + content: ""; + } +} + +@media \0screen { + .vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { + visibility: hidden; + } +} diff --git a/Ecureuil/Essentiel-2021/video.js b/Ecureuil/Essentiel-2021/video.js new file mode 100755 index 0000000..3876988 --- /dev/null +++ b/Ecureuil/Essentiel-2021/video.js @@ -0,0 +1,26878 @@ +/** + * @license + * Video.js 5.20.2 + * Copyright Brightcove, Inc. + * Available under Apache License Version 2.0 + * + * + * Includes vtt.js + * Available under Apache License Version 2.0 + * + */ + +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.videojs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0 && arguments[0] !== undefined ? arguments[0] : 'button'; + var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + props = (0, _obj.assign)({ + className: this.buildCSSClass() + }, props); + + if (tag !== 'button') { + _log2['default'].warn('Creating a Button with an HTML element of ' + tag + ' is deprecated; use ClickableComponent instead.'); + + // Add properties for clickable element which is not a native HTML button + props = (0, _obj.assign)({ + tabIndex: 0 + }, props); + + // Add ARIA attributes for clickable element which is not a native HTML button + attributes = (0, _obj.assign)({ + role: 'button' + }, attributes); + } + + // Add attributes for button element + attributes = (0, _obj.assign)({ + + // Necessary since the default button type is "submit" + 'type': 'button', + + // let the screen reader user know that the text of the button may change + 'aria-live': 'polite' + }, attributes); + + var el = _component2['default'].prototype.createEl.call(this, tag, props, attributes); + + this.createControlTextEl(el); + + return el; + }; + + /** + * Add a child `Component` inside of this `Button`. + * + * @param {string|Component} child + * The name or instance of a child to add. + * + * @param {Object} [options={}] + * The key/value store of options that will get passed to children of + * the child. + * + * @return {Component} + * The `Component` that gets added as a child. When using a string the + * `Component` will get created by this process. + * + * @deprecated since version 5 + */ + + + Button.prototype.addChild = function addChild(child) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var className = this.constructor.name; + + _log2['default'].warn('Adding an actionable (user controllable) child to a Button (' + className + ') is not supported; use a ClickableComponent instead.'); + + // Avoid the error message generated by ClickableComponent's addChild method + return _component2['default'].prototype.addChild.call(this, child, options); + }; + + /** + * Enable the `Button` element so that it can be activated or clicked. Use this with + * {@link Button#disable}. + */ + + + Button.prototype.enable = function enable() { + _ClickableComponent.prototype.enable.call(this); + this.el_.removeAttribute('disabled'); + }; + + /** + * Enable the `Button` element so that it cannot be activated or clicked. Use this with + * {@link Button#enable}. + */ + + + Button.prototype.disable = function disable() { + _ClickableComponent.prototype.disable.call(this); + this.el_.setAttribute('disabled', 'disabled'); + }; + + /** + * This gets called when a `Button` has focus and `keydown` is triggered via a key + * press. + * + * @param {EventTarget~Event} event + * The event that caused this function to get called. + * + * @listens keydown + */ + + + Button.prototype.handleKeyPress = function handleKeyPress(event) { + + // Ignore Space (32) or Enter (13) key operation, which is handled by the browser for a button. + if (event.which === 32 || event.which === 13) { + return; + } + + // Pass keypress handling up for unsupported keys + _ClickableComponent.prototype.handleKeyPress.call(this, event); + }; + + return Button; +}(_clickableComponent2['default']); + +_component2['default'].registerComponent('Button', Button); +exports['default'] = Button; + +},{"3":3,"5":5,"86":86,"88":88}],3:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _events = _dereq_(82); + +var Events = _interopRequireWildcard(_events); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _log = _dereq_(86); + +var _log2 = _interopRequireDefault(_log); + +var _document = _dereq_(94); + +var _document2 = _interopRequireDefault(_document); + +var _obj = _dereq_(88); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file button.js + */ + + +/** + * Clickable Component which is clickable or keyboard actionable, + * but is not a native HTML button. + * + * @extends Component + */ +var ClickableComponent = function (_Component) { + _inherits(ClickableComponent, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function ClickableComponent(player, options) { + _classCallCheck(this, ClickableComponent); + + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.emitTapEvents(); + + _this.enable(); + return _this; + } + + /** + * Create the `Component`s DOM element. + * + * @param {string} [tag=div] + * The element's node type. + * + * @param {Object} [props={}] + * An object of properties that should be set on the element. + * + * @param {Object} [attributes={}] + * An object of attributes that should be set on the element. + * + * @return {Element} + * The element that gets created. + */ + + + ClickableComponent.prototype.createEl = function createEl() { + var tag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div'; + var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + props = (0, _obj.assign)({ + className: this.buildCSSClass(), + tabIndex: 0 + }, props); + + if (tag === 'button') { + _log2['default'].error('Creating a ClickableComponent with an HTML element of ' + tag + ' is not supported; use a Button instead.'); + } + + // Add ARIA attributes for clickable element which is not a native HTML button + attributes = (0, _obj.assign)({ + 'role': 'button', + + // let the screen reader user know that the text of the element may change + 'aria-live': 'polite' + }, attributes); + + this.tabIndex_ = props.tabIndex; + + var el = _Component.prototype.createEl.call(this, tag, props, attributes); + + this.createControlTextEl(el); + + return el; + }; + + /** + * Create a control text element on this `Component` + * + * @param {Element} [el] + * Parent element for the control text. + * + * @return {Element} + * The control text element that gets created. + */ + + + ClickableComponent.prototype.createControlTextEl = function createControlTextEl(el) { + this.controlTextEl_ = Dom.createEl('span', { + className: 'vjs-control-text' + }); + + if (el) { + el.appendChild(this.controlTextEl_); + } + + this.controlText(this.controlText_, el); + + return this.controlTextEl_; + }; + + /** + * Get or set the localize text to use for the controls on the `Component`. + * + * @param {string} [text] + * Control text for element. + * + * @param {Element} [el=this.el()] + * Element to set the title on. + * + * @return {string|ClickableComponent} + * - The control text when getting + * - Returns itself when setting; method can be chained. + */ + + + ClickableComponent.prototype.controlText = function controlText(text) { + var el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.el(); + + if (!text) { + return this.controlText_ || 'Need Text'; + } + + var localizedText = this.localize(text); + + this.controlText_ = text; + this.controlTextEl_.innerHTML = localizedText; + + if (!this.nonIconControl) { + // Set title attribute if only an icon is shown + el.setAttribute('title', localizedText); + } + + return this; + }; + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + ClickableComponent.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-control vjs-button ' + _Component.prototype.buildCSSClass.call(this); + }; + + /** + * Enable this `Component`s element. + * + * @return {ClickableComponent} + * Returns itself; method can be chained. + */ + + + ClickableComponent.prototype.enable = function enable() { + this.removeClass('vjs-disabled'); + this.el_.setAttribute('aria-disabled', 'false'); + if (typeof this.tabIndex_ !== 'undefined') { + this.el_.setAttribute('tabIndex', this.tabIndex_); + } + this.off(['tap', 'click'], this.handleClick); + this.off('focus', this.handleFocus); + this.off('blur', this.handleBlur); + this.on(['tap', 'click'], this.handleClick); + this.on('focus', this.handleFocus); + this.on('blur', this.handleBlur); + return this; + }; + + /** + * Disable this `Component`s element. + * + * @return {ClickableComponent} + * Returns itself; method can be chained. + */ + + + ClickableComponent.prototype.disable = function disable() { + this.addClass('vjs-disabled'); + this.el_.setAttribute('aria-disabled', 'true'); + if (typeof this.tabIndex_ !== 'undefined') { + this.el_.removeAttribute('tabIndex'); + } + this.off(['tap', 'click'], this.handleClick); + this.off('focus', this.handleFocus); + this.off('blur', this.handleBlur); + return this; + }; + + /** + * This gets called when a `ClickableComponent` gets: + * - Clicked (via the `click` event, listening starts in the constructor) + * - Tapped (via the `tap` event, listening starts in the constructor) + * - The following things happen in order: + * 1. {@link ClickableComponent#handleFocus} is called via a `focus` event on the + * `ClickableComponent`. + * 2. {@link ClickableComponent#handleFocus} adds a listener for `keydown` on using + * {@link ClickableComponent#handleKeyPress}. + * 3. `ClickableComponent` has not had a `blur` event (`blur` means that focus was lost). The user presses + * the space or enter key. + * 4. {@link ClickableComponent#handleKeyPress} calls this function with the `keydown` + * event as a parameter. + * + * @param {EventTarget~Event} event + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + * @abstract + */ + + + ClickableComponent.prototype.handleClick = function handleClick(event) {}; + + /** + * This gets called when a `ClickableComponent` gains focus via a `focus` event. + * Turns on listening for `keydown` events. When they happen it + * calls `this.handleKeyPress`. + * + * @param {EventTarget~Event} event + * The `focus` event that caused this function to be called. + * + * @listens focus + */ + + + ClickableComponent.prototype.handleFocus = function handleFocus(event) { + Events.on(_document2['default'], 'keydown', Fn.bind(this, this.handleKeyPress)); + }; + + /** + * Called when this ClickableComponent has focus and a key gets pressed down. By + * default it will call `this.handleClick` when the key is space or enter. + * + * @param {EventTarget~Event} event + * The `keydown` event that caused this function to be called. + * + * @listens keydown + */ + + + ClickableComponent.prototype.handleKeyPress = function handleKeyPress(event) { + + // Support Space (32) or Enter (13) key operation to fire a click event + if (event.which === 32 || event.which === 13) { + event.preventDefault(); + this.handleClick(event); + } else if (_Component.prototype.handleKeyPress) { + + // Pass keypress handling up for unsupported keys + _Component.prototype.handleKeyPress.call(this, event); + } + }; + + /** + * Called when a `ClickableComponent` loses focus. Turns off the listener for + * `keydown` events. Which Stops `this.handleKeyPress` from getting called. + * + * @param {EventTarget~Event} event + * The `blur` event that caused this function to be called. + * + * @listens blur + */ + + + ClickableComponent.prototype.handleBlur = function handleBlur(event) { + Events.off(_document2['default'], 'keydown', Fn.bind(this, this.handleKeyPress)); + }; + + return ClickableComponent; +}(_component2['default']); + +_component2['default'].registerComponent('ClickableComponent', ClickableComponent); +exports['default'] = ClickableComponent; + +},{"5":5,"81":81,"82":82,"83":83,"86":86,"88":88,"94":94}],4:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _button = _dereq_(2); + +var _button2 = _interopRequireDefault(_button); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file close-button.js + */ + + +/** + * The `CloseButton` is a `{@link Button}` that fires a `close` event when + * it gets clicked. + * + * @extends Button + */ +var CloseButton = function (_Button) { + _inherits(CloseButton, _Button); + + /** + * Creates an instance of the this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function CloseButton(player, options) { + _classCallCheck(this, CloseButton); + + var _this = _possibleConstructorReturn(this, _Button.call(this, player, options)); + + _this.controlText(options && options.controlText || _this.localize('Close')); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + CloseButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-close-button ' + _Button.prototype.buildCSSClass.call(this); + }; + + /** + * This gets called when a `CloseButton` gets clicked. See + * {@link ClickableComponent#handleClick} for more information on when this will be + * triggered + * + * @param {EventTarget~Event} event + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + * @fires CloseButton#close + */ + + + CloseButton.prototype.handleClick = function handleClick(event) { + + /** + * Triggered when the a `CloseButton` is clicked. + * + * @event CloseButton#close + * @type {EventTarget~Event} + * + * @property {boolean} [bubbles=false] + * set to false so that the close event does not + * bubble up to parents if there is no listener + */ + this.trigger({ type: 'close', bubbles: false }); + }; + + return CloseButton; +}(_button2['default']); + +_component2['default'].registerComponent('CloseButton', CloseButton); +exports['default'] = CloseButton; + +},{"2":2,"5":5}],5:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _window = _dereq_(95); + +var _window2 = _interopRequireDefault(_window); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _guid = _dereq_(85); + +var Guid = _interopRequireWildcard(_guid); + +var _events = _dereq_(82); + +var Events = _interopRequireWildcard(_events); + +var _log = _dereq_(86); + +var _log2 = _interopRequireDefault(_log); + +var _toTitleCase = _dereq_(91); + +var _toTitleCase2 = _interopRequireDefault(_toTitleCase); + +var _mergeOptions = _dereq_(87); + +var _mergeOptions2 = _interopRequireDefault(_mergeOptions); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** + * Player Component - Base class for all UI objects + * + * @file component.js + */ + + +/** + * Base class for all UI Components. + * Components are UI objects which represent both a javascript object and an element + * in the DOM. They can be children of other components, and can have + * children themselves. + * + * Components can also use methods from {@link EventTarget} + */ +var Component = function () { + + /** + * A callback that is called when a component is ready. Does not have any + * paramters and any callback value will be ignored. + * + * @callback Component~ReadyCallback + * @this Component + */ + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + # + * @param {Object[]} [options.children] + * An array of children objects to intialize this component with. Children objects have + * a name property that will be used if more than one component of the same type needs to be + * added. + * + * @param {Component~ReadyCallback} [ready] + * Function that gets called when the `Component` is ready. + */ + function Component(player, options, ready) { + _classCallCheck(this, Component); + + // The component might be the player itself and we can't pass `this` to super + if (!player && this.play) { + this.player_ = player = this; // eslint-disable-line + } else { + this.player_ = player; + } + + // Make a copy of prototype.options_ to protect against overriding defaults + this.options_ = (0, _mergeOptions2['default'])({}, this.options_); + + // Updated options with supplied options + options = this.options_ = (0, _mergeOptions2['default'])(this.options_, options); + + // Get ID from options or options element if one is supplied + this.id_ = options.id || options.el && options.el.id; + + // If there was no ID from the options, generate one + if (!this.id_) { + // Don't require the player ID function in the case of mock players + var id = player && player.id && player.id() || 'no_player'; + + this.id_ = id + '_component_' + Guid.newGUID(); + } + + this.name_ = options.name || null; + + // Create element if one wasn't provided in options + if (options.el) { + this.el_ = options.el; + } else if (options.createEl !== false) { + this.el_ = this.createEl(); + } + + this.children_ = []; + this.childIndex_ = {}; + this.childNameIndex_ = {}; + + // Add any child components in options + if (options.initChildren !== false) { + this.initChildren(); + } + + this.ready(ready); + // Don't want to trigger ready here or it will before init is actually + // finished for all children that run this constructor + + if (options.reportTouchActivity !== false) { + this.enableTouchActivity(); + } + } + + /** + * Dispose of the `Component` and all child components. + * + * @fires Component#dispose + */ + + + Component.prototype.dispose = function dispose() { + + /** + * Triggered when a `Component` is disposed. + * + * @event Component#dispose + * @type {EventTarget~Event} + * + * @property {boolean} [bubbles=false] + * set to false so that the close event does not + * bubble up + */ + this.trigger({ type: 'dispose', bubbles: false }); + + // Dispose all children. + if (this.children_) { + for (var i = this.children_.length - 1; i >= 0; i--) { + if (this.children_[i].dispose) { + this.children_[i].dispose(); + } + } + } + + // Delete child references + this.children_ = null; + this.childIndex_ = null; + this.childNameIndex_ = null; + + // Remove all event listeners. + this.off(); + + // Remove element from DOM + if (this.el_.parentNode) { + this.el_.parentNode.removeChild(this.el_); + } + + Dom.removeElData(this.el_); + this.el_ = null; + }; + + /** + * Return the {@link Player} that the `Component` has attached to. + * + * @return {Player} + * The player that this `Component` has attached to. + */ + + + Component.prototype.player = function player() { + return this.player_; + }; + + /** + * Deep merge of options objects with new options. + * > Note: When both `obj` and `options` contain properties whose values are objects. + * The two properties get merged using {@link module:mergeOptions} + * + * @param {Object} obj + * The object that contains new options. + * + * @return {Object} + * A new object of `this.options_` and `obj` merged together. + * + * @deprecated since version 5 + */ + + + Component.prototype.options = function options(obj) { + _log2['default'].warn('this.options() has been deprecated and will be moved to the constructor in 6.0'); + + if (!obj) { + return this.options_; + } + + this.options_ = (0, _mergeOptions2['default'])(this.options_, obj); + return this.options_; + }; + + /** + * Get the `Component`s DOM element + * + * @return {Element} + * The DOM element for this `Component`. + */ + + + Component.prototype.el = function el() { + return this.el_; + }; + + /** + * Create the `Component`s DOM element. + * + * @param {string} [tagName] + * Element's DOM node type. e.g. 'div' + * + * @param {Object} [properties] + * An object of properties that should be set. + * + * @param {Object} [attributes] + * An object of attributes that should be set. + * + * @return {Element} + * The element that gets created. + */ + + + Component.prototype.createEl = function createEl(tagName, properties, attributes) { + return Dom.createEl(tagName, properties, attributes); + }; + + /** + * Localize a string given the string in english. + * + * @param {string} string + * The string to localize. + * + * @return {string} + * The localized string or if no localization exists the english string. + */ + + + Component.prototype.localize = function localize(string) { + var code = this.player_.language && this.player_.language(); + var languages = this.player_.languages && this.player_.languages(); + + if (!code || !languages) { + return string; + } + + var language = languages[code]; + + if (language && language[string]) { + return language[string]; + } + + var primaryCode = code.split('-')[0]; + var primaryLang = languages[primaryCode]; + + if (primaryLang && primaryLang[string]) { + return primaryLang[string]; + } + + return string; + }; + + /** + * Return the `Component`s DOM element. This is where children get inserted. + * This will usually be the the same as the element returned in {@link Component#el}. + * + * @return {Element} + * The content element for this `Component`. + */ + + + Component.prototype.contentEl = function contentEl() { + return this.contentEl_ || this.el_; + }; + + /** + * Get this `Component`s ID + * + * @return {string} + * The id of this `Component` + */ + + + Component.prototype.id = function id() { + return this.id_; + }; + + /** + * Get the `Component`s name. The name gets used to reference the `Component` + * and is set during registration. + * + * @return {string} + * The name of this `Component`. + */ + + + Component.prototype.name = function name() { + return this.name_; + }; + + /** + * Get an array of all child components + * + * @return {Array} + * The children + */ + + + Component.prototype.children = function children() { + return this.children_; + }; + + /** + * Returns the child `Component` with the given `id`. + * + * @param {string} id + * The id of the child `Component` to get. + * + * @return {Component|undefined} + * The child `Component` with the given `id` or undefined. + */ + + + Component.prototype.getChildById = function getChildById(id) { + return this.childIndex_[id]; + }; + + /** + * Returns the child `Component` with the given `name`. + * + * @param {string} name + * The name of the child `Component` to get. + * + * @return {Component|undefined} + * The child `Component` with the given `name` or undefined. + */ + + + Component.prototype.getChild = function getChild(name) { + if (!name) { + return; + } + + name = (0, _toTitleCase2['default'])(name); + + return this.childNameIndex_[name]; + }; + + /** + * Add a child `Component` inside the current `Component`. + * + * + * @param {string|Component} child + * The name or instance of a child to add. + * + * @param {Object} [options={}] + * The key/value store of options that will get passed to children of + * the child. + * + * @param {number} [index=this.children_.length] + * The index to attempt to add a child into. + * + * @return {Component} + * The `Component` that gets added as a child. When using a string the + * `Component` will get created by this process. + */ + + + Component.prototype.addChild = function addChild(child) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.children_.length; + + var component = void 0; + var componentName = void 0; + + // If child is a string, create component with options + if (typeof child === 'string') { + componentName = (0, _toTitleCase2['default'])(child); + + // Options can also be specified as a boolean, + // so convert to an empty object if false. + if (!options) { + options = {}; + } + + // Same as above, but true is deprecated so show a warning. + if (options === true) { + _log2['default'].warn('Initializing a child component with `true` is deprecated.' + 'Children should be defined in an array when possible, ' + 'but if necessary use an object instead of `true`.'); + options = {}; + } + + var componentClassName = options.componentClass || componentName; + + // Set name through options + options.name = componentName; + + // Create a new object & element for this controls set + // If there's no .player_, this is a player + var ComponentClass = Component.getComponent(componentClassName); + + if (!ComponentClass) { + throw new Error('Component ' + componentClassName + ' does not exist'); + } + + // data stored directly on the videojs object may be + // misidentified as a component to retain + // backwards-compatibility with 4.x. check to make sure the + // component class can be instantiated. + if (typeof ComponentClass !== 'function') { + return null; + } + + component = new ComponentClass(this.player_ || this, options); + + // child is a component instance + } else { + component = child; + } + + this.children_.splice(index, 0, component); + + if (typeof component.id === 'function') { + this.childIndex_[component.id()] = component; + } + + // If a name wasn't used to create the component, check if we can use the + // name function of the component + componentName = componentName || component.name && (0, _toTitleCase2['default'])(component.name()); + + if (componentName) { + this.childNameIndex_[componentName] = component; + } + + // Add the UI object's element to the container div (box) + // Having an element is not required + if (typeof component.el === 'function' && component.el()) { + var childNodes = this.contentEl().children; + var refNode = childNodes[index] || null; + + this.contentEl().insertBefore(component.el(), refNode); + } + + // Return so it can stored on parent object if desired. + return component; + }; + + /** + * Remove a child `Component` from this `Component`s list of children. Also removes + * the child `Component`s element from this `Component`s element. + * + * @param {Component} component + * The child `Component` to remove. + */ + + + Component.prototype.removeChild = function removeChild(component) { + if (typeof component === 'string') { + component = this.getChild(component); + } + + if (!component || !this.children_) { + return; + } + + var childFound = false; + + for (var i = this.children_.length - 1; i >= 0; i--) { + if (this.children_[i] === component) { + childFound = true; + this.children_.splice(i, 1); + break; + } + } + + if (!childFound) { + return; + } + + this.childIndex_[component.id()] = null; + this.childNameIndex_[component.name()] = null; + + var compEl = component.el(); + + if (compEl && compEl.parentNode === this.contentEl()) { + this.contentEl().removeChild(component.el()); + } + }; + + /** + * Add and initialize default child `Component`s based upon options. + */ + + + Component.prototype.initChildren = function initChildren() { + var _this = this; + + var children = this.options_.children; + + if (children) { + // `this` is `parent` + var parentOptions = this.options_; + + var handleAdd = function handleAdd(child) { + var name = child.name; + var opts = child.opts; + + // Allow options for children to be set at the parent options + // e.g. videojs(id, { controlBar: false }); + // instead of videojs(id, { children: { controlBar: false }); + if (parentOptions[name] !== undefined) { + opts = parentOptions[name]; + } + + // Allow for disabling default components + // e.g. options['children']['posterImage'] = false + if (opts === false) { + return; + } + + // Allow options to be passed as a simple boolean if no configuration + // is necessary. + if (opts === true) { + opts = {}; + } + + // We also want to pass the original player options + // to each component as well so they don't need to + // reach back into the player for options later. + opts.playerOptions = _this.options_.playerOptions; + + // Create and add the child component. + // Add a direct reference to the child by name on the parent instance. + // If two of the same component are used, different names should be supplied + // for each + var newChild = _this.addChild(name, opts); + + if (newChild) { + _this[name] = newChild; + } + }; + + // Allow for an array of children details to passed in the options + var workingChildren = void 0; + var Tech = Component.getComponent('Tech'); + + if (Array.isArray(children)) { + workingChildren = children; + } else { + workingChildren = Object.keys(children); + } + + workingChildren + // children that are in this.options_ but also in workingChildren would + // give us extra children we do not want. So, we want to filter them out. + .concat(Object.keys(this.options_).filter(function (child) { + return !workingChildren.some(function (wchild) { + if (typeof wchild === 'string') { + return child === wchild; + } + return child === wchild.name; + }); + })).map(function (child) { + var name = void 0; + var opts = void 0; + + if (typeof child === 'string') { + name = child; + opts = children[name] || _this.options_[name] || {}; + } else { + name = child.name; + opts = child; + } + + return { name: name, opts: opts }; + }).filter(function (child) { + // we have to make sure that child.name isn't in the techOrder since + // techs are registerd as Components but can't aren't compatible + // See https://github.com/videojs/video.js/issues/2772 + var c = Component.getComponent(child.opts.componentClass || (0, _toTitleCase2['default'])(child.name)); + + return c && !Tech.isTech(c); + }).forEach(handleAdd); + } + }; + + /** + * Builds the default DOM class name. Should be overriden by sub-components. + * + * @return {string} + * The DOM class name for this object. + * + * @abstract + */ + + + Component.prototype.buildCSSClass = function buildCSSClass() { + // Child classes can include a function that does: + // return 'CLASS NAME' + this._super(); + return ''; + }; + + /** + * Add an `event listener` to this `Component`s element. + * + * The benefit of using this over the following: + * - `VjsEvents.on(otherElement, 'eventName', myFunc)` + * - `otherComponent.on('eventName', myFunc)` + * + * 1. Is that the listeners will get cleaned up when either component gets disposed. + * 1. It will also bind `myComponent` as the context of `myFunc`. + * > NOTE: If you remove the element from the DOM that has used `on` you need to + * clean up references using: `myComponent.trigger(el, 'dispose')` + * This will also allow the browser to garbage collect it. In special + * cases such as with `window` and `document`, which are both permanent, + * this is not necessary. + * + * @param {string|Component|string[]} [first] + * The event name, and array of event names, or another `Component`. + * + * @param {EventTarget~EventListener|string|string[]} [second] + * The listener function, an event name, or an Array of events names. + * + * @param {EventTarget~EventListener} [third] + * The event handler if `first` is a `Component` and `second` is an event name + * or an Array of event names. + * + * @return {Component} + * Returns itself; method can be chained. + * + * @listens Component#dispose + */ + + + Component.prototype.on = function on(first, second, third) { + var _this2 = this; + + if (typeof first === 'string' || Array.isArray(first)) { + Events.on(this.el_, first, Fn.bind(this, second)); + + // Targeting another component or element + } else { + var target = first; + var type = second; + var fn = Fn.bind(this, third); + + // When this component is disposed, remove the listener from the other component + var removeOnDispose = function removeOnDispose() { + return _this2.off(target, type, fn); + }; + + // Use the same function ID so we can remove it later it using the ID + // of the original listener + removeOnDispose.guid = fn.guid; + this.on('dispose', removeOnDispose); + + // If the other component is disposed first we need to clean the reference + // to the other component in this component's removeOnDispose listener + // Otherwise we create a memory leak. + var cleanRemover = function cleanRemover() { + return _this2.off('dispose', removeOnDispose); + }; + + // Add the same function ID so we can easily remove it later + cleanRemover.guid = fn.guid; + + // Check if this is a DOM node + if (first.nodeName) { + // Add the listener to the other element + Events.on(target, type, fn); + Events.on(target, 'dispose', cleanRemover); + + // Should be a component + // Not using `instanceof Component` because it makes mock players difficult + } else if (typeof first.on === 'function') { + // Add the listener to the other component + target.on(type, fn); + target.on('dispose', cleanRemover); + } + } + + return this; + }; + + /** + * Remove an event listener from this `Component`s element. If the second argument is + * exluded all listeners for the type passed in as the first argument will be removed. + * + * @param {string|Component|string[]} [first] + * The event name, and array of event names, or another `Component`. + * + * @param {EventTarget~EventListener|string|string[]} [second] + * The listener function, an event name, or an Array of events names. + * + * @param {EventTarget~EventListener} [third] + * The event handler if `first` is a `Component` and `second` is an event name + * or an Array of event names. + * + * @return {Component} + * Returns itself; method can be chained. + */ + + + Component.prototype.off = function off(first, second, third) { + if (!first || typeof first === 'string' || Array.isArray(first)) { + Events.off(this.el_, first, second); + } else { + var target = first; + var type = second; + // Ensure there's at least a guid, even if the function hasn't been used + var fn = Fn.bind(this, third); + + // Remove the dispose listener on this component, + // which was given the same guid as the event listener + this.off('dispose', fn); + + if (first.nodeName) { + // Remove the listener + Events.off(target, type, fn); + // Remove the listener for cleaning the dispose listener + Events.off(target, 'dispose', fn); + } else { + target.off(type, fn); + target.off('dispose', fn); + } + } + + return this; + }; + + /** + * Add an event listener that gets triggered only once and then gets removed. + * + * @param {string|Component|string[]} [first] + * The event name, and array of event names, or another `Component`. + * + * @param {EventTarget~EventListener|string|string[]} [second] + * The listener function, an event name, or an Array of events names. + * + * @param {EventTarget~EventListener} [third] + * The event handler if `first` is a `Component` and `second` is an event name + * or an Array of event names. + * + * @return {Component} + * Returns itself; method can be chained. + */ + + + Component.prototype.one = function one(first, second, third) { + var _this3 = this, + _arguments = arguments; + + if (typeof first === 'string' || Array.isArray(first)) { + Events.one(this.el_, first, Fn.bind(this, second)); + } else { + var target = first; + var type = second; + var fn = Fn.bind(this, third); + + var newFunc = function newFunc() { + _this3.off(target, type, newFunc); + fn.apply(null, _arguments); + }; + + // Keep the same function ID so we can remove it later + newFunc.guid = fn.guid; + + this.on(target, type, newFunc); + } + + return this; + }; + + /** + * Trigger an event on an element. + * + * @param {EventTarget~Event|Object|string} event + * The event name, and Event, or an event-like object with a type attribute + * set to the event name. + * + * @param {Object} [hash] + * Data hash to pass along with the event + * + * @return {Component} + * Returns itself; method can be chained. + */ + + + Component.prototype.trigger = function trigger(event, hash) { + Events.trigger(this.el_, event, hash); + return this; + }; + + /** + * Bind a listener to the component's ready state. If the ready event has already + * happened it will trigger the function immediately. + * + * @param {Component~ReadyCallback} fn + * A function to call when ready is triggered. + * + * @param {boolean} [sync=false] + * Execute the listener synchronously if `Component` is ready. + * + * @return {Component} + * Returns itself; method can be chained. + */ + + + Component.prototype.ready = function ready(fn) { + var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (fn) { + if (this.isReady_) { + if (sync) { + fn.call(this); + } else { + // Call the function asynchronously by default for consistency + this.setTimeout(fn, 1); + } + } else { + this.readyQueue_ = this.readyQueue_ || []; + this.readyQueue_.push(fn); + } + } + return this; + }; + + /** + * Trigger all the ready listeners for this `Component`. + * + * @fires Component#ready + */ + + + Component.prototype.triggerReady = function triggerReady() { + this.isReady_ = true; + + // Ensure ready is triggerd asynchronously + this.setTimeout(function () { + var readyQueue = this.readyQueue_; + + // Reset Ready Queue + this.readyQueue_ = []; + + if (readyQueue && readyQueue.length > 0) { + readyQueue.forEach(function (fn) { + fn.call(this); + }, this); + } + + // Allow for using event listeners also + /** + * Triggered when a `Component` is ready. + * + * @event Component#ready + * @type {EventTarget~Event} + */ + this.trigger('ready'); + }, 1); + }; + + /** + * Find a single DOM element matching a `selector`. This can be within the `Component`s + * `contentEl()` or another custom context. + * + * @param {string} selector + * A valid CSS selector, which will be passed to `querySelector`. + * + * @param {Element|string} [context=this.contentEl()] + * A DOM element within which to query. Can also be a selector string in + * which case the first matching element will get used as context. If + * missing `this.contentEl()` gets used. If `this.contentEl()` returns + * nothing it falls back to `document`. + * + * @return {Element|null} + * the dom element that was found, or null + * + * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors) + */ + + + Component.prototype.$ = function $(selector, context) { + return Dom.$(selector, context || this.contentEl()); + }; + + /** + * Finds all DOM element matching a `selector`. This can be within the `Component`s + * `contentEl()` or another custom context. + * + * @param {string} selector + * A valid CSS selector, which will be passed to `querySelectorAll`. + * + * @param {Element|string} [context=this.contentEl()] + * A DOM element within which to query. Can also be a selector string in + * which case the first matching element will get used as context. If + * missing `this.contentEl()` gets used. If `this.contentEl()` returns + * nothing it falls back to `document`. + * + * @return {NodeList} + * a list of dom elements that were found + * + * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors) + */ + + + Component.prototype.$$ = function $$(selector, context) { + return Dom.$$(selector, context || this.contentEl()); + }; + + /** + * Check if a component's element has a CSS class name. + * + * @param {string} classToCheck + * CSS class name to check. + * + * @return {boolean} + * - True if the `Component` has the class. + * - False if the `Component` does not have the class` + */ + + + Component.prototype.hasClass = function hasClass(classToCheck) { + return Dom.hasElClass(this.el_, classToCheck); + }; + + /** + * Add a CSS class name to the `Component`s element. + * + * @param {string} classToAdd + * CSS class name to add + * + * @return {Component} + * Returns itself; method can be chained. + */ + + + Component.prototype.addClass = function addClass(classToAdd) { + Dom.addElClass(this.el_, classToAdd); + return this; + }; + + /** + * Remove a CSS class name from the `Component`s element. + * + * @param {string} classToRemove + * CSS class name to remove + * + * @return {Component} + * Returns itself; method can be chained. + */ + + + Component.prototype.removeClass = function removeClass(classToRemove) { + Dom.removeElClass(this.el_, classToRemove); + return this; + }; + + /** + * Add or remove a CSS class name from the component's element. + * - `classToToggle` gets added when {@link Component#hasClass} would return false. + * - `classToToggle` gets removed when {@link Component#hasClass} would return true. + * + * @param {string} classToToggle + * The class to add or remove based on (@link Component#hasClass} + * + * @param {boolean|Dom~predicate} [predicate] + * An {@link Dom~predicate} function or a boolean + * + * @return {Component} + * Returns itself; method can be chained. + */ + + + Component.prototype.toggleClass = function toggleClass(classToToggle, predicate) { + Dom.toggleElClass(this.el_, classToToggle, predicate); + return this; + }; + + /** + * Show the `Component`s element if it is hidden by removing the + * 'vjs-hidden' class name from it. + * + * @return {Component} + * Returns itself; method can be chained. + */ + + + Component.prototype.show = function show() { + this.removeClass('vjs-hidden'); + return this; + }; + + /** + * Hide the `Component`s element if it is currently showing by adding the + * 'vjs-hidden` class name to it. + * + * @return {Component} + * Returns itself; method can be chained. + */ + + + Component.prototype.hide = function hide() { + this.addClass('vjs-hidden'); + return this; + }; + + /** + * Lock a `Component`s element in its visible state by adding the 'vjs-lock-showing' + * class name to it. Used during fadeIn/fadeOut. + * + * @return {Component} + * Returns itself; method can be chained. + * + * @private + */ + + + Component.prototype.lockShowing = function lockShowing() { + this.addClass('vjs-lock-showing'); + return this; + }; + + /** + * Unlock a `Component`s element from its visible state by removing the 'vjs-lock-showing' + * class name from it. Used during fadeIn/fadeOut. + * + * @return {Component} + * Returns itself; method can be chained. + * + * @private + */ + + + Component.prototype.unlockShowing = function unlockShowing() { + this.removeClass('vjs-lock-showing'); + return this; + }; + + /** + * Get the value of an attribute on the `Component`s element. + * + * @param {string} attribute + * Name of the attribute to get the value from. + * + * @return {string|null} + * - The value of the attribute that was asked for. + * - Can be an empty string on some browsers if the attribute does not exist + * or has no value + * - Most browsers will return null if the attibute does not exist or has + * no value. + * + * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute} + */ + + + Component.prototype.getAttribute = function getAttribute(attribute) { + return Dom.getAttribute(this.el_, attribute); + }; + + /** + * Set the value of an attribute on the `Component`'s element + * + * @param {string} attribute + * Name of the attribute to set. + * + * @param {string} value + * Value to set the attribute to. + * + * @return {Component} + * Returns itself; method can be chained. + * + * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute} + */ + + + Component.prototype.setAttribute = function setAttribute(attribute, value) { + Dom.setAttribute(this.el_, attribute, value); + return this; + }; + + /** + * Remove an attribute from the `Component`s element. + * + * @param {string} attribute + * Name of the attribute to remove. + * + * @return {Component} + * Returns itself; method can be chained. + * + * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute} + */ + + + Component.prototype.removeAttribute = function removeAttribute(attribute) { + Dom.removeAttribute(this.el_, attribute); + return this; + }; + + /** + * Get or set the width of the component based upon the CSS styles. + * See {@link Component#dimension} for more detailed information. + * + * @param {number|string} [num] + * The width that you want to set postfixed with '%', 'px' or nothing. + * + * @param {boolean} [skipListeners] + * Skip the resize event trigger + * + * @return {Component|number|string} + * - The width when getting, zero if there is no width. Can be a string + * postpixed with '%' or 'px'. + * - Returns itself when setting; method can be chained. + */ + + + Component.prototype.width = function width(num, skipListeners) { + return this.dimension('width', num, skipListeners); + }; + + /** + * Get or set the height of the component based upon the CSS styles. + * See {@link Component#dimension} for more detailed information. + * + * @param {number|string} [num] + * The height that you want to set postfixed with '%', 'px' or nothing. + * + * @param {boolean} [skipListeners] + * Skip the resize event trigger + * + * @return {Component|number|string} + * - The width when getting, zero if there is no width. Can be a string + * postpixed with '%' or 'px'. + * - Returns itself when setting; method can be chained. + */ + + + Component.prototype.height = function height(num, skipListeners) { + return this.dimension('height', num, skipListeners); + }; + + /** + * Set both the width and height of the `Component` element at the same time. + * + * @param {number|string} width + * Width to set the `Component`s element to. + * + * @param {number|string} height + * Height to set the `Component`s element to. + * + * @return {Component} + * Returns itself; method can be chained. + */ + + + Component.prototype.dimensions = function dimensions(width, height) { + // Skip resize listeners on width for optimization + return this.width(width, true).height(height); + }; + + /** + * Get or set width or height of the `Component` element. This is the shared code + * for the {@link Component#width} and {@link Component#height}. + * + * Things to know: + * - If the width or height in an number this will return the number postfixed with 'px'. + * - If the width/height is a percent this will return the percent postfixed with '%' + * - Hidden elements have a width of 0 with `window.getComputedStyle`. This function + * defaults to the `Component`s `style.width` and falls back to `window.getComputedStyle`. + * See [this]{@link http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/} + * for more information + * - If you want the computed style of the component, use {@link Component#currentWidth} + * and {@link {Component#currentHeight} + * + * @fires Component#resize + * + * @param {string} widthOrHeight + 8 'width' or 'height' + * + * @param {number|string} [num] + 8 New dimension + * + * @param {boolean} [skipListeners] + * Skip resize event trigger + * + * @return {Component} + * - the dimension when getting or 0 if unset + * - Returns itself when setting; method can be chained. + */ + + + Component.prototype.dimension = function dimension(widthOrHeight, num, skipListeners) { + if (num !== undefined) { + // Set to zero if null or literally NaN (NaN !== NaN) + if (num === null || num !== num) { + num = 0; + } + + // Check if using css width/height (% or px) and adjust + if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) { + this.el_.style[widthOrHeight] = num; + } else if (num === 'auto') { + this.el_.style[widthOrHeight] = ''; + } else { + this.el_.style[widthOrHeight] = num + 'px'; + } + + // skipListeners allows us to avoid triggering the resize event when setting both width and height + if (!skipListeners) { + /** + * Triggered when a component is resized. + * + * @event Component#resize + * @type {EventTarget~Event} + */ + this.trigger('resize'); + } + + // Return component + return this; + } + + // Not setting a value, so getting it + // Make sure element exists + if (!this.el_) { + return 0; + } + + // Get dimension value from style + var val = this.el_.style[widthOrHeight]; + var pxIndex = val.indexOf('px'); + + if (pxIndex !== -1) { + // Return the pixel value with no 'px' + return parseInt(val.slice(0, pxIndex), 10); + } + + // No px so using % or no style was set, so falling back to offsetWidth/height + // If component has display:none, offset will return 0 + // TODO: handle display:none and no dimension style using px + return parseInt(this.el_['offset' + (0, _toTitleCase2['default'])(widthOrHeight)], 10); + }; + + /** + * Get the width or the height of the `Component` elements computed style. Uses + * `window.getComputedStyle`. + * + * @param {string} widthOrHeight + * A string containing 'width' or 'height'. Whichever one you want to get. + * + * @return {number} + * The dimension that gets asked for or 0 if nothing was set + * for that dimension. + */ + + + Component.prototype.currentDimension = function currentDimension(widthOrHeight) { + var computedWidthOrHeight = 0; + + if (widthOrHeight !== 'width' && widthOrHeight !== 'height') { + throw new Error('currentDimension only accepts width or height value'); + } + + if (typeof _window2['default'].getComputedStyle === 'function') { + var computedStyle = _window2['default'].getComputedStyle(this.el_); + + computedWidthOrHeight = computedStyle.getPropertyValue(widthOrHeight) || computedStyle[widthOrHeight]; + } + + // remove 'px' from variable and parse as integer + computedWidthOrHeight = parseFloat(computedWidthOrHeight); + + // if the computed value is still 0, it's possible that the browser is lying + // and we want to check the offset values. + // This code also runs on IE8 and wherever getComputedStyle doesn't exist. + if (computedWidthOrHeight === 0) { + var rule = 'offset' + (0, _toTitleCase2['default'])(widthOrHeight); + + computedWidthOrHeight = this.el_[rule]; + } + + return computedWidthOrHeight; + }; + + /** + * An object that contains width and height values of the `Component`s + * computed style. Uses `window.getComputedStyle`. + * + * @typedef {Object} Component~DimensionObject + * + * @property {number} width + * The width of the `Component`s computed style. + * + * @property {number} height + * The height of the `Component`s computed style. + */ + + /** + * Get an object that contains width and height values of the `Component`s + * computed style. + * + * @return {Component~DimensionObject} + * The dimensions of the components element + */ + + + Component.prototype.currentDimensions = function currentDimensions() { + return { + width: this.currentDimension('width'), + height: this.currentDimension('height') + }; + }; + + /** + * Get the width of the `Component`s computed style. Uses `window.getComputedStyle`. + * + * @return {number} width + * The width of the `Component`s computed style. + */ + + + Component.prototype.currentWidth = function currentWidth() { + return this.currentDimension('width'); + }; + + /** + * Get the height of the `Component`s computed style. Uses `window.getComputedStyle`. + * + * @return {number} height + * The height of the `Component`s computed style. + */ + + + Component.prototype.currentHeight = function currentHeight() { + return this.currentDimension('height'); + }; + + /** + * Set the focus to this component + */ + + + Component.prototype.focus = function focus() { + this.el_.focus(); + }; + + /** + * Remove the focus from this component + */ + + + Component.prototype.blur = function blur() { + this.el_.blur(); + }; + + /** + * Emit a 'tap' events when touch event support gets detected. This gets used to + * support toggling the controls through a tap on the video. They get enabled + * because every sub-component would have extra overhead otherwise. + * + * @private + * @fires Component#tap + * @listens Component#touchstart + * @listens Component#touchmove + * @listens Component#touchleave + * @listens Component#touchcancel + * @listens Component#touchend + */ + + + Component.prototype.emitTapEvents = function emitTapEvents() { + // Track the start time so we can determine how long the touch lasted + var touchStart = 0; + var firstTouch = null; + + // Maximum movement allowed during a touch event to still be considered a tap + // Other popular libs use anywhere from 2 (hammer.js) to 15, + // so 10 seems like a nice, round number. + var tapMovementThreshold = 10; + + // The maximum length a touch can be while still being considered a tap + var touchTimeThreshold = 200; + + var couldBeTap = void 0; + + this.on('touchstart', function (event) { + // If more than one finger, don't consider treating this as a click + if (event.touches.length === 1) { + // Copy pageX/pageY from the object + firstTouch = { + pageX: event.touches[0].pageX, + pageY: event.touches[0].pageY + }; + // Record start time so we can detect a tap vs. "touch and hold" + touchStart = new Date().getTime(); + // Reset couldBeTap tracking + couldBeTap = true; + } + }); + + this.on('touchmove', function (event) { + // If more than one finger, don't consider treating this as a click + if (event.touches.length > 1) { + couldBeTap = false; + } else if (firstTouch) { + // Some devices will throw touchmoves for all but the slightest of taps. + // So, if we moved only a small distance, this could still be a tap + var xdiff = event.touches[0].pageX - firstTouch.pageX; + var ydiff = event.touches[0].pageY - firstTouch.pageY; + var touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff); + + if (touchDistance > tapMovementThreshold) { + couldBeTap = false; + } + } + }); + + var noTap = function noTap() { + couldBeTap = false; + }; + + // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s + this.on('touchleave', noTap); + this.on('touchcancel', noTap); + + // When the touch ends, measure how long it took and trigger the appropriate + // event + this.on('touchend', function (event) { + firstTouch = null; + // Proceed only if the touchmove/leave/cancel event didn't happen + if (couldBeTap === true) { + // Measure how long the touch lasted + var touchTime = new Date().getTime() - touchStart; + + // Make sure the touch was less than the threshold to be considered a tap + if (touchTime < touchTimeThreshold) { + // Don't let browser turn this into a click + event.preventDefault(); + /** + * Triggered when a `Component` is tapped. + * + * @event Component#tap + * @type {EventTarget~Event} + */ + this.trigger('tap'); + // It may be good to copy the touchend event object and change the + // type to tap, if the other event properties aren't exact after + // Events.fixEvent runs (e.g. event.target) + } + } + }); + }; + + /** + * This function reports user activity whenever touch events happen. This can get + * turned off by any sub-components that wants touch events to act another way. + * + * Report user touch activity when touch events occur. User activity gets used to + * determine when controls should show/hide. It is simple when it comes to mouse + * events, because any mouse event should show the controls. So we capture mouse + * events that bubble up to the player and report activity when that happens. + * With touch events it isn't as easy as `touchstart` and `touchend` toggle player + * controls. So touch events can't help us at the player level either. + * + * User activity gets checked asynchronously. So what could happen is a tap event + * on the video turns the controls off. Then the `touchend` event bubbles up to + * the player. Which, if it reported user activity, would turn the controls right + * back on. We also don't want to completely block touch events from bubbling up. + * Furthermore a `touchmove` event and anything other than a tap, should not turn + * controls back on. + * + * @listens Component#touchstart + * @listens Component#touchmove + * @listens Component#touchend + * @listens Component#touchcancel + */ + + + Component.prototype.enableTouchActivity = function enableTouchActivity() { + // Don't continue if the root player doesn't support reporting user activity + if (!this.player() || !this.player().reportUserActivity) { + return; + } + + // listener for reporting that the user is active + var report = Fn.bind(this.player(), this.player().reportUserActivity); + + var touchHolding = void 0; + + this.on('touchstart', function () { + report(); + // For as long as the they are touching the device or have their mouse down, + // we consider them active even if they're not moving their finger or mouse. + // So we want to continue to update that they are active + this.clearInterval(touchHolding); + // report at the same interval as activityCheck + touchHolding = this.setInterval(report, 250); + }); + + var touchEnd = function touchEnd(event) { + report(); + // stop the interval that maintains activity if the touch is holding + this.clearInterval(touchHolding); + }; + + this.on('touchmove', report); + this.on('touchend', touchEnd); + this.on('touchcancel', touchEnd); + }; + + /** + * A callback that has no parameters and is bound into `Component`s context. + * + * @callback Component~GenericCallback + * @this Component + */ + + /** + * Creates a function that runs after an `x` millisecond timeout. This function is a + * wrapper around `window.setTimeout`. There are a few reasons to use this one + * instead though: + * 1. It gets cleared via {@link Component#clearTimeout} when + * {@link Component#dispose} gets called. + * 2. The function callback will gets turned into a {@link Component~GenericCallback} + * + * > Note: You can use `window.clearTimeout` on the id returned by this function. This + * will cause its dispose listener not to get cleaned up! Please use + * {@link Component#clearTimeout} or {@link Component#dispose}. + * + * @param {Component~GenericCallback} fn + * The function that will be run after `timeout`. + * + * @param {number} timeout + * Timeout in milliseconds to delay before executing the specified function. + * + * @return {number} + * Returns a timeout ID that gets used to identify the timeout. It can also + * get used in {@link Component#clearTimeout} to clear the timeout that + * was set. + * + * @listens Component#dispose + * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout} + */ + + + Component.prototype.setTimeout = function setTimeout(fn, timeout) { + fn = Fn.bind(this, fn); + + var timeoutId = _window2['default'].setTimeout(fn, timeout); + var disposeFn = function disposeFn() { + this.clearTimeout(timeoutId); + }; + + disposeFn.guid = 'vjs-timeout-' + timeoutId; + + this.on('dispose', disposeFn); + + return timeoutId; + }; + + /** + * Clears a timeout that gets created via `window.setTimeout` or + * {@link Component#setTimeout}. If you set a timeout via {@link Component#setTimeout} + * use this function instead of `window.clearTimout`. If you don't your dispose + * listener will not get cleaned up until {@link Component#dispose}! + * + * @param {number} timeoutId + * The id of the timeout to clear. The return value of + * {@link Component#setTimeout} or `window.setTimeout`. + * + * @return {number} + * Returns the timeout id that was cleared. + * + * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout} + */ + + + Component.prototype.clearTimeout = function clearTimeout(timeoutId) { + _window2['default'].clearTimeout(timeoutId); + + var disposeFn = function disposeFn() {}; + + disposeFn.guid = 'vjs-timeout-' + timeoutId; + + this.off('dispose', disposeFn); + + return timeoutId; + }; + + /** + * Creates a function that gets run every `x` milliseconds. This function is a wrapper + * around `window.setInterval`. There are a few reasons to use this one instead though. + * 1. It gets cleared via {@link Component#clearInterval} when + * {@link Component#dispose} gets called. + * 2. The function callback will be a {@link Component~GenericCallback} + * + * @param {Component~GenericCallback} fn + * The function to run every `x` seconds. + * + * @param {number} interval + * Execute the specified function every `x` milliseconds. + * + * @return {number} + * Returns an id that can be used to identify the interval. It can also be be used in + * {@link Component#clearInterval} to clear the interval. + * + * @listens Component#dispose + * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval} + */ + + + Component.prototype.setInterval = function setInterval(fn, interval) { + fn = Fn.bind(this, fn); + + var intervalId = _window2['default'].setInterval(fn, interval); + + var disposeFn = function disposeFn() { + this.clearInterval(intervalId); + }; + + disposeFn.guid = 'vjs-interval-' + intervalId; + + this.on('dispose', disposeFn); + + return intervalId; + }; + + /** + * Clears an interval that gets created via `window.setInterval` or + * {@link Component#setInterval}. If you set an inteval via {@link Component#setInterval} + * use this function instead of `window.clearInterval`. If you don't your dispose + * listener will not get cleaned up until {@link Component#dispose}! + * + * @param {number} intervalId + * The id of the interval to clear. The return value of + * {@link Component#setInterval} or `window.setInterval`. + * + * @return {number} + * Returns the interval id that was cleared. + * + * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval} + */ + + + Component.prototype.clearInterval = function clearInterval(intervalId) { + _window2['default'].clearInterval(intervalId); + + var disposeFn = function disposeFn() {}; + + disposeFn.guid = 'vjs-interval-' + intervalId; + + this.off('dispose', disposeFn); + + return intervalId; + }; + + /** + * Register a `Component` with `videojs` given the name and the component. + * + * > NOTE: {@link Tech}s should not be registered as a `Component`. {@link Tech}s + * should be registered using {@link Tech.registerTech} or + * {@link videojs:videojs.registerTech}. + * + * > NOTE: This function can also be seen on videojs as + * {@link videojs:videojs.registerComponent}. + * + * @param {string} name + * The name of the `Component` to register. + * + * @param {Component} comp + * The `Component` class to register. + * + * @return {Component} + * The `Component` that was registered. + */ + + + Component.registerComponent = function registerComponent(name, comp) { + if (!name) { + return; + } + + name = (0, _toTitleCase2['default'])(name); + + if (!Component.components_) { + Component.components_ = {}; + } + + if (name === 'Player' && Component.components_[name]) { + var Player = Component.components_[name]; + + // If we have players that were disposed, then their name will still be + // in Players.players. So, we must loop through and verify that the value + // for each item is not null. This allows registration of the Player component + // after all players have been disposed or before any were created. + if (Player.players && Object.keys(Player.players).length > 0 && Object.keys(Player.players).map(function (playerName) { + return Player.players[playerName]; + }).every(Boolean)) { + throw new Error('Can not register Player component after player has been created'); + } + } + + Component.components_[name] = comp; + + return comp; + }; + + /** + * Get a `Component` based on the name it was registered with. + * + * @param {string} name + * The Name of the component to get. + * + * @return {Component} + * The `Component` that got registered under the given name. + * + * @deprecated In `videojs` 6 this will not return `Component`s that were not + * registered using {@link Component.registerComponent}. Currently we + * check the global `videojs` object for a `Component` name and + * return that if it exists. + */ + + + Component.getComponent = function getComponent(name) { + if (!name) { + return; + } + + name = (0, _toTitleCase2['default'])(name); + + if (Component.components_ && Component.components_[name]) { + return Component.components_[name]; + } + + if (_window2['default'] && _window2['default'].videojs && _window2['default'].videojs[name]) { + _log2['default'].warn('The ' + name + ' component was added to the videojs object when it should be registered using videojs.registerComponent(name, component)'); + + return _window2['default'].videojs[name]; + } + }; + + /** + * Sets up the constructor using the supplied init method or uses the init of the + * parent object. + * + * @param {Object} [props={}] + * An object of properties. + * + * @return {Object} + * the extended object. + * + * @deprecated since version 5 + */ + + + Component.extend = function extend(props) { + props = props || {}; + + _log2['default'].warn('Component.extend({}) has been deprecated, ' + ' use videojs.extend(Component, {}) instead'); + + // Set up the constructor using the supplied init method + // or using the init of the parent object + // Make sure to check the unobfuscated version for external libs + var init = props.init || props.init || this.prototype.init || this.prototype.init || function () {}; + // In Resig's simple class inheritance (previously used) the constructor + // is a function that calls `this.init.apply(arguments)` + // However that would prevent us from using `ParentObject.call(this);` + // in a Child constructor because the `this` in `this.init` + // would still refer to the Child and cause an infinite loop. + // We would instead have to do + // `ParentObject.prototype.init.apply(this, arguments);` + // Bleh. We're not creating a _super() function, so it's good to keep + // the parent constructor reference simple. + var subObj = function subObj() { + init.apply(this, arguments); + }; + + // Inherit from this object's prototype + subObj.prototype = Object.create(this.prototype); + // Reset the constructor property for subObj otherwise + // instances of subObj would have the constructor of the parent Object + subObj.prototype.constructor = subObj; + + // Make the class extendable + subObj.extend = Component.extend; + + // Extend subObj's prototype with functions and other properties from props + for (var name in props) { + if (props.hasOwnProperty(name)) { + subObj.prototype[name] = props[name]; + } + } + + return subObj; + }; + + return Component; +}(); + +Component.registerComponent('Component', Component); +exports['default'] = Component; + +},{"81":81,"82":82,"83":83,"85":85,"86":86,"87":87,"91":91,"95":95}],6:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _trackButton = _dereq_(36); + +var _trackButton2 = _interopRequireDefault(_trackButton); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _audioTrackMenuItem = _dereq_(7); + +var _audioTrackMenuItem2 = _interopRequireDefault(_audioTrackMenuItem); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file audio-track-button.js + */ + + +/** + * The base class for buttons that toggle specific {@link AudioTrack} types. + * + * @extends TrackButton + */ +var AudioTrackButton = function (_TrackButton) { + _inherits(AudioTrackButton, _TrackButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options={}] + * The key/value store of player options. + */ + function AudioTrackButton(player) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, AudioTrackButton); + + options.tracks = player.audioTracks && player.audioTracks(); + + var _this = _possibleConstructorReturn(this, _TrackButton.call(this, player, options)); + + _this.el_.setAttribute('aria-label', 'Audio Menu'); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + AudioTrackButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-audio-button ' + _TrackButton.prototype.buildCSSClass.call(this); + }; + + /** + * Create a menu item for each audio track + * + * @param {AudioTrackMenuItem[]} [items=[]] + * An array of existing menu items to use. + * + * @return {AudioTrackMenuItem[]} + * An array of menu items + */ + + + AudioTrackButton.prototype.createItems = function createItems() { + var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + + // if there's only one audio track, there no point in showing it + this.hideThreshold_ = 1; + + var tracks = this.player_.audioTracks && this.player_.audioTracks(); + + if (!tracks) { + return items; + } + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + items.push(new _audioTrackMenuItem2['default'](this.player_, { + track: track, + // MenuItem is selectable + selectable: true + })); + } + + return items; + }; + + return AudioTrackButton; +}(_trackButton2['default']); + +/** + * The text that should display over the `AudioTrackButton`s controls. Added for localization. + * + * @type {string} + * @private + */ + + +AudioTrackButton.prototype.controlText_ = 'Audio Track'; +_component2['default'].registerComponent('AudioTrackButton', AudioTrackButton); +exports['default'] = AudioTrackButton; + +},{"36":36,"5":5,"7":7}],7:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _menuItem = _dereq_(48); + +var _menuItem2 = _interopRequireDefault(_menuItem); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file audio-track-menu-item.js + */ + + +/** + * An {@link AudioTrack} {@link MenuItem} + * + * @extends MenuItem + */ +var AudioTrackMenuItem = function (_MenuItem) { + _inherits(AudioTrackMenuItem, _MenuItem); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function AudioTrackMenuItem(player, options) { + _classCallCheck(this, AudioTrackMenuItem); + + var track = options.track; + var tracks = player.audioTracks(); + + // Modify options for parent MenuItem class's init. + options.label = track.label || track.language || 'Unknown'; + options.selected = track.enabled; + + var _this = _possibleConstructorReturn(this, _MenuItem.call(this, player, options)); + + _this.track = track; + + if (tracks) { + var changeHandler = Fn.bind(_this, _this.handleTracksChange); + + tracks.addEventListener('change', changeHandler); + _this.on('dispose', function () { + tracks.removeEventListener('change', changeHandler); + }); + } + return _this; + } + + /** + * This gets called when an `AudioTrackMenuItem is "clicked". See {@link ClickableComponent} + * for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + AudioTrackMenuItem.prototype.handleClick = function handleClick(event) { + var tracks = this.player_.audioTracks(); + + _MenuItem.prototype.handleClick.call(this, event); + + if (!tracks) { + return; + } + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + track.enabled = track === this.track; + } + }; + + /** + * Handle any {@link AudioTrack} change. + * + * @param {EventTarget~Event} [event] + * The {@link AudioTrackList#change} event that caused this to run. + * + * @listens AudioTrackList#change + */ + + + AudioTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) { + this.selected(this.track.enabled); + }; + + return AudioTrackMenuItem; +}(_menuItem2['default']); + +_component2['default'].registerComponent('AudioTrackMenuItem', AudioTrackMenuItem); +exports['default'] = AudioTrackMenuItem; + +},{"48":48,"5":5,"83":83}],8:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +_dereq_(12); + +_dereq_(32); + +_dereq_(33); + +_dereq_(35); + +_dereq_(34); + +_dereq_(10); + +_dereq_(18); + +_dereq_(9); + +_dereq_(38); + +_dereq_(40); + +_dereq_(11); + +_dereq_(25); + +_dereq_(27); + +_dereq_(29); + +_dereq_(24); + +_dereq_(6); + +_dereq_(13); + +_dereq_(21); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file control-bar.js + */ + + +// Required children + + +/** + * Container of main controls. + * + * @extends Component + */ +var ControlBar = function (_Component) { + _inherits(ControlBar, _Component); + + function ControlBar() { + _classCallCheck(this, ControlBar); + + return _possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + ControlBar.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-control-bar', + dir: 'ltr' + }, { + // The control bar is a group, so it can contain menuitems + role: 'group' + }); + }; + + return ControlBar; +}(_component2['default']); + +/** + * Default options for `ControlBar` + * + * @type {Object} + * @private + */ + + +ControlBar.prototype.options_ = { + children: ['playToggle', 'volumeMenuButton', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'descriptionsButton', 'subtitlesButton', 'captionsButton', 'audioTrackButton', 'fullscreenToggle'] +}; + +_component2['default'].registerComponent('ControlBar', ControlBar); +exports['default'] = ControlBar; + +},{"10":10,"11":11,"12":12,"13":13,"18":18,"21":21,"24":24,"25":25,"27":27,"29":29,"32":32,"33":33,"34":34,"35":35,"38":38,"40":40,"5":5,"6":6,"9":9}],9:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _button = _dereq_(2); + +var _button2 = _interopRequireDefault(_button); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file fullscreen-toggle.js + */ + + +/** + * Toggle fullscreen video + * + * @extends Button + */ +var FullscreenToggle = function (_Button) { + _inherits(FullscreenToggle, _Button); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function FullscreenToggle(player, options) { + _classCallCheck(this, FullscreenToggle); + + var _this = _possibleConstructorReturn(this, _Button.call(this, player, options)); + + _this.on(player, 'fullscreenchange', _this.handleFullscreenChange); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + FullscreenToggle.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-fullscreen-control ' + _Button.prototype.buildCSSClass.call(this); + }; + + /** + * Handles fullscreenchange on the player and change control text accordingly. + * + * @param {EventTarget~Event} [event] + * The {@link Player#fullscreenchange} event that caused this function to be + * called. + * + * @listens Player#fullscreenchange + */ + + + FullscreenToggle.prototype.handleFullscreenChange = function handleFullscreenChange(event) { + if (this.player_.isFullscreen()) { + this.controlText('Non-Fullscreen'); + } else { + this.controlText('Fullscreen'); + } + }; + + /** + * This gets called when an `FullscreenToggle` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + FullscreenToggle.prototype.handleClick = function handleClick(event) { + if (!this.player_.isFullscreen()) { + this.player_.requestFullscreen(); + } else { + this.player_.exitFullscreen(); + } + }; + + return FullscreenToggle; +}(_button2['default']); + +/** + * The text that should display over the `FullscreenToggle`s controls. Added for localization. + * + * @type {string} + * @private + */ + + +FullscreenToggle.prototype.controlText_ = 'Fullscreen'; + +_component2['default'].registerComponent('FullscreenToggle', FullscreenToggle); +exports['default'] = FullscreenToggle; + +},{"2":2,"5":5}],10:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file live-display.js + */ + + +// TODO - Future make it click to snap to live + +/** + * Displays the live indicator when duration is Infinity. + * + * @extends Component + */ +var LiveDisplay = function (_Component) { + _inherits(LiveDisplay, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function LiveDisplay(player, options) { + _classCallCheck(this, LiveDisplay); + + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.updateShowing(); + _this.on(_this.player(), 'durationchange', _this.updateShowing); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + LiveDisplay.prototype.createEl = function createEl() { + var el = _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-live-control vjs-control' + }); + + this.contentEl_ = Dom.createEl('div', { + className: 'vjs-live-display', + innerHTML: '' + this.localize('Stream Type') + '' + this.localize('LIVE') + }, { + 'aria-live': 'off' + }); + + el.appendChild(this.contentEl_); + return el; + }; + + /** + * Check the duration to see if the LiveDisplay should be showing or not. Then show/hide + * it accordingly + * + * @param {EventTarget~Event} [event] + * The {@link Player#durationchange} event that caused this function to run. + * + * @listens Player#durationchange + */ + + + LiveDisplay.prototype.updateShowing = function updateShowing(event) { + if (this.player().duration() === Infinity) { + this.show(); + } else { + this.hide(); + } + }; + + return LiveDisplay; +}(_component2['default']); + +_component2['default'].registerComponent('LiveDisplay', LiveDisplay); +exports['default'] = LiveDisplay; + +},{"5":5,"81":81}],11:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _button = _dereq_(2); + +var _button2 = _interopRequireDefault(_button); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file mute-toggle.js + */ + + +/** + * A button component for muting the audio. + * + * @extends Button + */ +var MuteToggle = function (_Button) { + _inherits(MuteToggle, _Button); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function MuteToggle(player, options) { + _classCallCheck(this, MuteToggle); + + var _this = _possibleConstructorReturn(this, _Button.call(this, player, options)); + + _this.on(player, 'volumechange', _this.update); + + // hide mute toggle if the current tech doesn't support volume control + if (player.tech_ && player.tech_.featuresVolumeControl === false) { + _this.addClass('vjs-hidden'); + } + + _this.on(player, 'loadstart', function () { + // We need to update the button to account for a default muted state. + this.update(); + + if (player.tech_.featuresVolumeControl === false) { + this.addClass('vjs-hidden'); + } else { + this.removeClass('vjs-hidden'); + } + }); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + MuteToggle.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-mute-control ' + _Button.prototype.buildCSSClass.call(this); + }; + + /** + * This gets called when an `MuteToggle` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + MuteToggle.prototype.handleClick = function handleClick(event) { + this.player_.muted(this.player_.muted() ? false : true); + }; + + /** + * Update the state of volume. + * + * @param {EventTarget~Event} [event] + * The {@link Player#loadstart} event if this function was called through an + * event. + * + * @listens Player#loadstart + */ + + + MuteToggle.prototype.update = function update(event) { + var vol = this.player_.volume(); + var level = 3; + + if (this.player_.muted()) { + level = 0; + } else if (vol < 0.33) { + level = 1; + } else if (vol < 0.67) { + level = 2; + } + + // Don't rewrite the button text if the actual text doesn't change. + // This causes unnecessary and confusing information for screen reader users. + // This check is needed because this function gets called every time the volume level is changed. + var toMute = this.player_.muted() ? 'Unmute' : 'Mute'; + + if (this.controlText() !== toMute) { + this.controlText(toMute); + } + + // TODO improve muted icon classes + for (var i = 0; i < 4; i++) { + Dom.removeElClass(this.el_, 'vjs-vol-' + i); + } + Dom.addElClass(this.el_, 'vjs-vol-' + level); + }; + + return MuteToggle; +}(_button2['default']); + +/** + * The text that should display over the `MuteToggle`s controls. Added for localization. + * + * @type {string} + * @private + */ + + +MuteToggle.prototype.controlText_ = 'Mute'; + +_component2['default'].registerComponent('MuteToggle', MuteToggle); +exports['default'] = MuteToggle; + +},{"2":2,"5":5,"81":81}],12:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _button = _dereq_(2); + +var _button2 = _interopRequireDefault(_button); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file play-toggle.js + */ + + +/** + * Button to toggle between play and pause. + * + * @extends Button + */ +var PlayToggle = function (_Button) { + _inherits(PlayToggle, _Button); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function PlayToggle(player, options) { + _classCallCheck(this, PlayToggle); + + var _this = _possibleConstructorReturn(this, _Button.call(this, player, options)); + + _this.on(player, 'play', _this.handlePlay); + _this.on(player, 'pause', _this.handlePause); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + PlayToggle.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-play-control ' + _Button.prototype.buildCSSClass.call(this); + }; + + /** + * This gets called when an `PlayToggle` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + PlayToggle.prototype.handleClick = function handleClick(event) { + if (this.player_.paused()) { + this.player_.play(); + } else { + this.player_.pause(); + } + }; + + /** + * Add the vjs-playing class to the element so it can change appearance. + * + * @param {EventTarget~Event} [event] + * The event that caused this function to run. + * + * @listens Player#play + */ + + + PlayToggle.prototype.handlePlay = function handlePlay(event) { + this.removeClass('vjs-paused'); + this.addClass('vjs-playing'); + // change the button text to "Pause" + this.controlText('Pause'); + }; + + /** + * Add the vjs-paused class to the element so it can change appearance. + * + * @param {EventTarget~Event} [event] + * The event that caused this function to run. + * + * @listens Player#pause + */ + + + PlayToggle.prototype.handlePause = function handlePause(event) { + this.removeClass('vjs-playing'); + this.addClass('vjs-paused'); + // change the button text to "Play" + this.controlText('Play'); + }; + + return PlayToggle; +}(_button2['default']); + +/** + * The text that should display over the `PlayToggle`s controls. Added for localization. + * + * @type {string} + * @private + */ + + +PlayToggle.prototype.controlText_ = 'Play'; + +_component2['default'].registerComponent('PlayToggle', PlayToggle); +exports['default'] = PlayToggle; + +},{"2":2,"5":5}],13:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _menuButton = _dereq_(47); + +var _menuButton2 = _interopRequireDefault(_menuButton); + +var _menu = _dereq_(49); + +var _menu2 = _interopRequireDefault(_menu); + +var _playbackRateMenuItem = _dereq_(14); + +var _playbackRateMenuItem2 = _interopRequireDefault(_playbackRateMenuItem); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file playback-rate-menu-button.js + */ + + +/** + * The component for controlling the playback rate. + * + * @extends MenuButton + */ +var PlaybackRateMenuButton = function (_MenuButton) { + _inherits(PlaybackRateMenuButton, _MenuButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function PlaybackRateMenuButton(player, options) { + _classCallCheck(this, PlaybackRateMenuButton); + + var _this = _possibleConstructorReturn(this, _MenuButton.call(this, player, options)); + + _this.updateVisibility(); + _this.updateLabel(); + + _this.on(player, 'loadstart', _this.updateVisibility); + _this.on(player, 'ratechange', _this.updateLabel); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + PlaybackRateMenuButton.prototype.createEl = function createEl() { + var el = _MenuButton.prototype.createEl.call(this); + + this.labelEl_ = Dom.createEl('div', { + className: 'vjs-playback-rate-value', + innerHTML: 1.0 + }); + + el.appendChild(this.labelEl_); + + return el; + }; + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + PlaybackRateMenuButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-playback-rate ' + _MenuButton.prototype.buildCSSClass.call(this); + }; + + /** + * Create the playback rate menu + * + * @return {Menu} + * Menu object populated with {@link PlaybackRateMenuItem}s + */ + + + PlaybackRateMenuButton.prototype.createMenu = function createMenu() { + var menu = new _menu2['default'](this.player()); + var rates = this.playbackRates(); + + if (rates) { + for (var i = rates.length - 1; i >= 0; i--) { + menu.addChild(new _playbackRateMenuItem2['default'](this.player(), { rate: rates[i] + 'x' })); + } + } + + return menu; + }; + + /** + * Updates ARIA accessibility attributes + */ + + + PlaybackRateMenuButton.prototype.updateARIAAttributes = function updateARIAAttributes() { + // Current playback rate + this.el().setAttribute('aria-valuenow', this.player().playbackRate()); + }; + + /** + * This gets called when an `PlaybackRateMenuButton` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + PlaybackRateMenuButton.prototype.handleClick = function handleClick(event) { + // select next rate option + var currentRate = this.player().playbackRate(); + var rates = this.playbackRates(); + + // this will select first one if the last one currently selected + var newRate = rates[0]; + + for (var i = 0; i < rates.length; i++) { + if (rates[i] > currentRate) { + newRate = rates[i]; + break; + } + } + this.player().playbackRate(newRate); + }; + + /** + * Get possible playback rates + * + * @return {Array} + * All possible playback rates + */ + + + PlaybackRateMenuButton.prototype.playbackRates = function playbackRates() { + return this.options_.playbackRates || this.options_.playerOptions && this.options_.playerOptions.playbackRates; + }; + + /** + * Get whether playback rates is supported by the tech + * and an array of playback rates exists + * + * @return {boolean} + * Whether changing playback rate is supported + */ + + + PlaybackRateMenuButton.prototype.playbackRateSupported = function playbackRateSupported() { + return this.player().tech_ && this.player().tech_.featuresPlaybackRate && this.playbackRates() && this.playbackRates().length > 0; + }; + + /** + * Hide playback rate controls when they're no playback rate options to select + * + * @param {EventTarget~Event} [event] + * The event that caused this function to run. + * + * @listens Player#loadstart + */ + + + PlaybackRateMenuButton.prototype.updateVisibility = function updateVisibility(event) { + if (this.playbackRateSupported()) { + this.removeClass('vjs-hidden'); + } else { + this.addClass('vjs-hidden'); + } + }; + + /** + * Update button label when rate changed + * + * @param {EventTarget~Event} [event] + * The event that caused this function to run. + * + * @listens Player#ratechange + */ + + + PlaybackRateMenuButton.prototype.updateLabel = function updateLabel(event) { + if (this.playbackRateSupported()) { + this.labelEl_.innerHTML = this.player().playbackRate() + 'x'; + } + }; + + return PlaybackRateMenuButton; +}(_menuButton2['default']); + +/** + * The text that should display over the `FullscreenToggle`s controls. Added for localization. + * + * @type {string} + * @private + */ + + +PlaybackRateMenuButton.prototype.controlText_ = 'Playback Rate'; + +_component2['default'].registerComponent('PlaybackRateMenuButton', PlaybackRateMenuButton); +exports['default'] = PlaybackRateMenuButton; + +},{"14":14,"47":47,"49":49,"5":5,"81":81}],14:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _menuItem = _dereq_(48); + +var _menuItem2 = _interopRequireDefault(_menuItem); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file playback-rate-menu-item.js + */ + + +/** + * The specific menu item type for selecting a playback rate. + * + * @extends MenuItem + */ +var PlaybackRateMenuItem = function (_MenuItem) { + _inherits(PlaybackRateMenuItem, _MenuItem); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function PlaybackRateMenuItem(player, options) { + _classCallCheck(this, PlaybackRateMenuItem); + + var label = options.rate; + var rate = parseFloat(label, 10); + + // Modify options for parent MenuItem class's init. + options.label = label; + options.selected = rate === 1; + options.selectable = true; + + var _this = _possibleConstructorReturn(this, _MenuItem.call(this, player, options)); + + _this.label = label; + _this.rate = rate; + + _this.on(player, 'ratechange', _this.update); + return _this; + } + + /** + * This gets called when an `PlaybackRateMenuItem` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + PlaybackRateMenuItem.prototype.handleClick = function handleClick(event) { + _MenuItem.prototype.handleClick.call(this); + this.player().playbackRate(this.rate); + }; + + /** + * Update the PlaybackRateMenuItem when the playbackrate changes. + * + * @param {EventTarget~Event} [event] + * The `ratechange` event that caused this function to run. + * + * @listens Player#ratechange + */ + + + PlaybackRateMenuItem.prototype.update = function update(event) { + this.selected(this.player().playbackRate() === this.rate); + }; + + return PlaybackRateMenuItem; +}(_menuItem2['default']); + +/** + * The text that should display over the `PlaybackRateMenuItem`s controls. Added for localization. + * + * @type {string} + * @private + */ + + +PlaybackRateMenuItem.prototype.contentElType = 'button'; + +_component2['default'].registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem); +exports['default'] = PlaybackRateMenuItem; + +},{"48":48,"5":5}],15:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file load-progress-bar.js + */ + + +/** + * Shows loading progress + * + * @extends Component + */ +var LoadProgressBar = function (_Component) { + _inherits(LoadProgressBar, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function LoadProgressBar(player, options) { + _classCallCheck(this, LoadProgressBar); + + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.partEls_ = []; + _this.on(player, 'progress', _this.update); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + LoadProgressBar.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-load-progress', + innerHTML: '' + this.localize('Loaded') + ': 0%' + }); + }; + + /** + * Update progress bar + * + * @param {EventTarget~Event} [event] + * The `progress` event that caused this function to run. + * + * @listens Player#progress + */ + + + LoadProgressBar.prototype.update = function update(event) { + var buffered = this.player_.buffered(); + var duration = this.player_.duration(); + var bufferedEnd = this.player_.bufferedEnd(); + var children = this.partEls_; + + // get the percent width of a time compared to the total end + var percentify = function percentify(time, end) { + // no NaN + var percent = time / end || 0; + + return (percent >= 1 ? 1 : percent) * 100 + '%'; + }; + + // update the width of the progress bar + this.el_.style.width = percentify(bufferedEnd, duration); + + // add child elements to represent the individual buffered time ranges + for (var i = 0; i < buffered.length; i++) { + var start = buffered.start(i); + var end = buffered.end(i); + var part = children[i]; + + if (!part) { + part = this.el_.appendChild(Dom.createEl()); + children[i] = part; + } + + // set the percent based on the width of the progress bar (bufferedEnd) + part.style.left = percentify(start, bufferedEnd); + part.style.width = percentify(end - start, bufferedEnd); + } + + // remove unused buffered range elements + for (var _i = children.length; _i > buffered.length; _i--) { + this.el_.removeChild(children[_i - 1]); + } + children.length = buffered.length; + }; + + return LoadProgressBar; +}(_component2['default']); + +_component2['default'].registerComponent('LoadProgressBar', LoadProgressBar); +exports['default'] = LoadProgressBar; + +},{"5":5,"81":81}],16:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _formatTime = _dereq_(84); + +var _formatTime2 = _interopRequireDefault(_formatTime); + +var _computedStyle = _dereq_(80); + +var _computedStyle2 = _interopRequireDefault(_computedStyle); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file mouse-time-display.js + */ + + +/** + * The Mouse Time Display component shows the time you will seek to + * when hovering over the progress bar + * + * @extends Component + */ +var MouseTimeDisplay = function (_Component) { + _inherits(MouseTimeDisplay, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function MouseTimeDisplay(player, options) { + _classCallCheck(this, MouseTimeDisplay); + + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) { + _this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside; + } + + if (_this.keepTooltipsInside) { + _this.tooltip = Dom.createEl('div', { className: 'vjs-time-tooltip' }); + _this.el().appendChild(_this.tooltip); + _this.addClass('vjs-keep-tooltips-inside'); + } + + _this.update(0, 0); + + player.on('ready', function () { + _this.on(player.controlBar.progressControl.el(), 'mousemove', Fn.throttle(Fn.bind(_this, _this.handleMouseMove), 25)); + }); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + MouseTimeDisplay.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-mouse-display' + }); + }; + + /** + * Handle the mouse move event on the `MouseTimeDisplay`. + * + * @param {EventTarget~Event} event + * The `mousemove` event that caused this to event to run. + * + * @listen mousemove + */ + + + MouseTimeDisplay.prototype.handleMouseMove = function handleMouseMove(event) { + var duration = this.player_.duration(); + var newTime = this.calculateDistance(event) * duration; + var position = event.pageX - Dom.findElPosition(this.el().parentNode).left; + + this.update(newTime, position); + }; + + /** + * Update the time and posistion of the `MouseTimeDisplay`. + * + * @param {number} newTime + * Time to change the `MouseTimeDisplay` to. + * + * @param {nubmer} position + * Postion from the left of the in pixels. + */ + + + MouseTimeDisplay.prototype.update = function update(newTime, position) { + var time = (0, _formatTime2['default'])(newTime, this.player_.duration()); + + this.el().style.left = position + 'px'; + this.el().setAttribute('data-current-time', time); + + if (this.keepTooltipsInside) { + var clampedPosition = this.clampPosition_(position); + var difference = position - clampedPosition + 1; + var tooltipWidth = parseFloat((0, _computedStyle2['default'])(this.tooltip, 'width')); + var tooltipWidthHalf = tooltipWidth / 2; + + this.tooltip.innerHTML = time; + this.tooltip.style.right = '-' + (tooltipWidthHalf - difference) + 'px'; + } + }; + + /** + * Get the mouse pointers x coordinate in pixels. + * + * @param {EventTarget~Event} [event] + * The `mousemove` event that was passed to this function by + * {@link MouseTimeDisplay#handleMouseMove} + * + * @return {number} + * THe x position in pixels of the mouse pointer. + */ + + + MouseTimeDisplay.prototype.calculateDistance = function calculateDistance(event) { + return Dom.getPointerPosition(this.el().parentNode, event).x; + }; + + /** + * This takes in a horizontal position for the bar and returns a clamped position. + * Clamped position means that it will keep the position greater than half the width + * of the tooltip and smaller than the player width minus half the width o the tooltip. + * It will only clamp the position if `keepTooltipsInside` option is set. + * + * @param {number} position + * The position the bar wants to be + * + * @return {number} + * The (potentially) new clamped position. + * + * @private + */ + + + MouseTimeDisplay.prototype.clampPosition_ = function clampPosition_(position) { + if (!this.keepTooltipsInside) { + return position; + } + + var playerWidth = parseFloat((0, _computedStyle2['default'])(this.player().el(), 'width')); + var tooltipWidth = parseFloat((0, _computedStyle2['default'])(this.tooltip, 'width')); + var tooltipWidthHalf = tooltipWidth / 2; + var actualPosition = position; + + if (position < tooltipWidthHalf) { + actualPosition = Math.ceil(tooltipWidthHalf); + } else if (position > playerWidth - tooltipWidthHalf) { + actualPosition = Math.floor(playerWidth - tooltipWidthHalf); + } + + return actualPosition; + }; + + return MouseTimeDisplay; +}(_component2['default']); + +_component2['default'].registerComponent('MouseTimeDisplay', MouseTimeDisplay); +exports['default'] = MouseTimeDisplay; + +},{"5":5,"80":80,"81":81,"83":83,"84":84}],17:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _formatTime = _dereq_(84); + +var _formatTime2 = _interopRequireDefault(_formatTime); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file play-progress-bar.js + */ + + +/** + * Shows play progress + * + * @extends Component + */ +var PlayProgressBar = function (_Component) { + _inherits(PlayProgressBar, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function PlayProgressBar(player, options) { + _classCallCheck(this, PlayProgressBar); + + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.updateDataAttr(); + _this.on(player, 'timeupdate', _this.updateDataAttr); + player.ready(Fn.bind(_this, _this.updateDataAttr)); + + if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) { + _this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside; + } + + if (_this.keepTooltipsInside) { + _this.addClass('vjs-keep-tooltips-inside'); + } + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + PlayProgressBar.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-play-progress vjs-slider-bar', + innerHTML: '' + this.localize('Progress') + ': 0%' + }); + }; + + /** + * Update the data-current-time attribute on the `PlayProgressBar`. + * + * @param {EventTarget~Event} [event] + * The `timeupdate` event that caused this to run. + * + * @listens Player#timeupdate + */ + + + PlayProgressBar.prototype.updateDataAttr = function updateDataAttr(event) { + var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); + + this.el_.setAttribute('data-current-time', (0, _formatTime2['default'])(time, this.player_.duration())); + }; + + return PlayProgressBar; +}(_component2['default']); + +_component2['default'].registerComponent('PlayProgressBar', PlayProgressBar); +exports['default'] = PlayProgressBar; + +},{"5":5,"83":83,"84":84}],18:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +_dereq_(19); + +_dereq_(16); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file progress-control.js + */ + + +/** + * The Progress Control component contains the seek bar, load progress, + * and play progress. + * + * @extends Component + */ +var ProgressControl = function (_Component) { + _inherits(ProgressControl, _Component); + + function ProgressControl() { + _classCallCheck(this, ProgressControl); + + return _possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + ProgressControl.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-progress-control vjs-control' + }); + }; + + return ProgressControl; +}(_component2['default']); + +/** + * Default options for `ProgressControl` + * + * @type {Object} + * @private + */ + + +ProgressControl.prototype.options_ = { + children: ['seekBar'] +}; + +_component2['default'].registerComponent('ProgressControl', ProgressControl); +exports['default'] = ProgressControl; + +},{"16":16,"19":19,"5":5}],19:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _slider = _dereq_(57); + +var _slider2 = _interopRequireDefault(_slider); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _formatTime = _dereq_(84); + +var _formatTime2 = _interopRequireDefault(_formatTime); + +var _computedStyle = _dereq_(80); + +var _computedStyle2 = _interopRequireDefault(_computedStyle); + +_dereq_(15); + +_dereq_(17); + +_dereq_(20); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file seek-bar.js + */ + + +/** + * Seek Bar and holder for the progress bars + * + * @extends Slider + */ +var SeekBar = function (_Slider) { + _inherits(SeekBar, _Slider); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function SeekBar(player, options) { + _classCallCheck(this, SeekBar); + + var _this = _possibleConstructorReturn(this, _Slider.call(this, player, options)); + + _this.on(player, 'timeupdate', _this.updateProgress); + _this.on(player, 'ended', _this.updateProgress); + player.ready(Fn.bind(_this, _this.updateProgress)); + + if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) { + _this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside; + } + + if (_this.keepTooltipsInside) { + _this.tooltipProgressBar = _this.addChild('TooltipProgressBar'); + } + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + SeekBar.prototype.createEl = function createEl() { + return _Slider.prototype.createEl.call(this, 'div', { + className: 'vjs-progress-holder' + }, { + 'aria-label': 'progress bar' + }); + }; + + /** + * Update the seek bars tooltip and width. + * + * @param {EventTarget~Event} [event] + * The `timeupdate` or `ended` event that caused this to run. + * + * @listens Player#timeupdate + * @listens Player#ended + */ + + + SeekBar.prototype.updateProgress = function updateProgress(event) { + this.updateAriaAttributes(this.el_); + + if (this.keepTooltipsInside) { + this.updateAriaAttributes(this.tooltipProgressBar.el_); + this.tooltipProgressBar.el_.style.width = this.bar.el_.style.width; + + var playerWidth = parseFloat((0, _computedStyle2['default'])(this.player().el(), 'width')); + var tooltipWidth = parseFloat((0, _computedStyle2['default'])(this.tooltipProgressBar.tooltip, 'width')); + var tooltipStyle = this.tooltipProgressBar.el().style; + + tooltipStyle.maxWidth = Math.floor(playerWidth - tooltipWidth / 2) + 'px'; + tooltipStyle.minWidth = Math.ceil(tooltipWidth / 2) + 'px'; + tooltipStyle.right = '-' + tooltipWidth / 2 + 'px'; + } + }; + + /** + * Update ARIA accessibility attributes + * + * @param {Element} el + * The element to update with aria accessibility attributes. + */ + + + SeekBar.prototype.updateAriaAttributes = function updateAriaAttributes(el) { + // Allows for smooth scrubbing, when player can't keep up. + var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); + + // machine readable value of progress bar (percentage complete) + el.setAttribute('aria-valuenow', (this.getPercent() * 100).toFixed(2)); + // human readable value of progress bar (time complete) + el.setAttribute('aria-valuetext', (0, _formatTime2['default'])(time, this.player_.duration())); + }; + + /** + * Get percentage of video played + * + * @return {number} + * The percentage played + */ + + + SeekBar.prototype.getPercent = function getPercent() { + var percent = this.player_.currentTime() / this.player_.duration(); + + return percent >= 1 ? 1 : percent; + }; + + /** + * Handle mouse down on seek bar + * + * @param {EventTarget~Event} event + * The `mousedown` event that caused this to run. + * + * @listens mousedown + */ + + + SeekBar.prototype.handleMouseDown = function handleMouseDown(event) { + this.player_.scrubbing(true); + + this.videoWasPlaying = !this.player_.paused(); + this.player_.pause(); + + _Slider.prototype.handleMouseDown.call(this, event); + }; + + /** + * Handle mouse move on seek bar + * + * @param {EventTarget~Event} event + * The `mousemove` event that caused this to run. + * + * @listens mousemove + */ + + + SeekBar.prototype.handleMouseMove = function handleMouseMove(event) { + var newTime = this.calculateDistance(event) * this.player_.duration(); + + // Don't let video end while scrubbing. + if (newTime === this.player_.duration()) { + newTime = newTime - 0.1; + } + + // Set new time (tell player to seek to new time) + this.player_.currentTime(newTime); + }; + + /** + * Handle mouse up on seek bar + * + * @param {EventTarget~Event} event + * The `mouseup` event that caused this to run. + * + * @listens mouseup + */ + + + SeekBar.prototype.handleMouseUp = function handleMouseUp(event) { + _Slider.prototype.handleMouseUp.call(this, event); + + this.player_.scrubbing(false); + if (this.videoWasPlaying) { + this.player_.play(); + } + }; + + /** + * Move more quickly fast forward for keyboard-only users + */ + + + SeekBar.prototype.stepForward = function stepForward() { + // more quickly fast forward for keyboard-only users + this.player_.currentTime(this.player_.currentTime() + 5); + }; + + /** + * Move more quickly rewind for keyboard-only users + */ + + + SeekBar.prototype.stepBack = function stepBack() { + // more quickly rewind for keyboard-only users + this.player_.currentTime(this.player_.currentTime() - 5); + }; + + return SeekBar; +}(_slider2['default']); + +/** + * Default options for the `SeekBar` + * + * @type {Object} + * @private + */ + + +SeekBar.prototype.options_ = { + children: ['loadProgressBar', 'mouseTimeDisplay', 'playProgressBar'], + barName: 'playProgressBar' +}; + +/** + * Call the update event for this Slider when this event happens on the player. + * + * @type {string} + */ +SeekBar.prototype.playerEvent = 'timeupdate'; + +_component2['default'].registerComponent('SeekBar', SeekBar); +exports['default'] = SeekBar; + +},{"15":15,"17":17,"20":20,"5":5,"57":57,"80":80,"83":83,"84":84}],20:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _formatTime = _dereq_(84); + +var _formatTime2 = _interopRequireDefault(_formatTime); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file play-progress-bar.js + */ + + +/** + * Shows play progress + * + * @extends Component + */ +var TooltipProgressBar = function (_Component) { + _inherits(TooltipProgressBar, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function TooltipProgressBar(player, options) { + _classCallCheck(this, TooltipProgressBar); + + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.updateDataAttr(); + _this.on(player, 'timeupdate', _this.updateDataAttr); + player.ready(Fn.bind(_this, _this.updateDataAttr)); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + TooltipProgressBar.prototype.createEl = function createEl() { + var el = _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-tooltip-progress-bar vjs-slider-bar', + innerHTML: '
\n ' + this.localize('Progress') + ': 0%' + }); + + this.tooltip = el.querySelector('.vjs-time-tooltip'); + + return el; + }; + + /** + * Updatet the data-current-time attribute for TooltipProgressBar + * + * @param {EventTarget~Event} [event] + * The `timeupdate` event that caused this function to run. + * + * @listens Player#timeupdate + */ + + + TooltipProgressBar.prototype.updateDataAttr = function updateDataAttr(event) { + var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); + var formattedTime = (0, _formatTime2['default'])(time, this.player_.duration()); + + this.el_.setAttribute('data-current-time', formattedTime); + this.tooltip.innerHTML = formattedTime; + }; + + return TooltipProgressBar; +}(_component2['default']); + +_component2['default'].registerComponent('TooltipProgressBar', TooltipProgressBar); +exports['default'] = TooltipProgressBar; + +},{"5":5,"83":83,"84":84}],21:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _spacer = _dereq_(22); + +var _spacer2 = _interopRequireDefault(_spacer); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file custom-control-spacer.js + */ + + +/** + * Spacer specifically meant to be used as an insertion point for new plugins, etc. + * + * @extends Spacer + */ +var CustomControlSpacer = function (_Spacer) { + _inherits(CustomControlSpacer, _Spacer); + + function CustomControlSpacer() { + _classCallCheck(this, CustomControlSpacer); + + return _possibleConstructorReturn(this, _Spacer.apply(this, arguments)); + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + CustomControlSpacer.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-custom-control-spacer ' + _Spacer.prototype.buildCSSClass.call(this); + }; + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + CustomControlSpacer.prototype.createEl = function createEl() { + var el = _Spacer.prototype.createEl.call(this, { + className: this.buildCSSClass() + }); + + // No-flex/table-cell mode requires there be some content + // in the cell to fill the remaining space of the table. + el.innerHTML = ' '; + return el; + }; + + return CustomControlSpacer; +}(_spacer2['default']); + +_component2['default'].registerComponent('CustomControlSpacer', CustomControlSpacer); +exports['default'] = CustomControlSpacer; + +},{"22":22,"5":5}],22:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file spacer.js + */ + + +/** + * Just an empty spacer element that can be used as an append point for plugins, etc. + * Also can be used to create space between elements when necessary. + * + * @extends Component + */ +var Spacer = function (_Component) { + _inherits(Spacer, _Component); + + function Spacer() { + _classCallCheck(this, Spacer); + + return _possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + Spacer.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-spacer ' + _Component.prototype.buildCSSClass.call(this); + }; + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + Spacer.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: this.buildCSSClass() + }); + }; + + return Spacer; +}(_component2['default']); + +_component2['default'].registerComponent('Spacer', Spacer); + +exports['default'] = Spacer; + +},{"5":5}],23:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _textTrackMenuItem = _dereq_(31); + +var _textTrackMenuItem2 = _interopRequireDefault(_textTrackMenuItem); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file caption-settings-menu-item.js + */ + + +/** + * The menu item for caption track settings menu + * + * @extends TextTrackMenuItem + */ +var CaptionSettingsMenuItem = function (_TextTrackMenuItem) { + _inherits(CaptionSettingsMenuItem, _TextTrackMenuItem); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function CaptionSettingsMenuItem(player, options) { + _classCallCheck(this, CaptionSettingsMenuItem); + + options.track = { + player: player, + kind: options.kind, + label: options.kind + ' settings', + selectable: false, + 'default': false, + mode: 'disabled' + }; + + // CaptionSettingsMenuItem has no concept of 'selected' + options.selectable = false; + + var _this = _possibleConstructorReturn(this, _TextTrackMenuItem.call(this, player, options)); + + _this.addClass('vjs-texttrack-settings'); + _this.controlText(', opens ' + options.kind + ' settings dialog'); + return _this; + } + + /** + * This gets called when an `CaptionSettingsMenuItem` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + CaptionSettingsMenuItem.prototype.handleClick = function handleClick(event) { + this.player().getChild('textTrackSettings').show(); + this.player().getChild('textTrackSettings').el_.focus(); + }; + + return CaptionSettingsMenuItem; +}(_textTrackMenuItem2['default']); + +_component2['default'].registerComponent('CaptionSettingsMenuItem', CaptionSettingsMenuItem); +exports['default'] = CaptionSettingsMenuItem; + +},{"31":31,"5":5}],24:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _textTrackButton = _dereq_(30); + +var _textTrackButton2 = _interopRequireDefault(_textTrackButton); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _captionSettingsMenuItem = _dereq_(23); + +var _captionSettingsMenuItem2 = _interopRequireDefault(_captionSettingsMenuItem); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file captions-button.js + */ + + +/** + * The button component for toggling and selecting captions + * + * @extends TextTrackButton + */ +var CaptionsButton = function (_TextTrackButton) { + _inherits(CaptionsButton, _TextTrackButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} [ready] + * The function to call when this component is ready. + */ + function CaptionsButton(player, options, ready) { + _classCallCheck(this, CaptionsButton); + + var _this = _possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready)); + + _this.el_.setAttribute('aria-label', 'Captions Menu'); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + CaptionsButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-captions-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); + }; + + /** + * Create caption menu items + * + * @return {CaptionSettingsMenuItem[]} + * The array of current menu items. + */ + + + CaptionsButton.prototype.createItems = function createItems() { + var items = []; + + if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks)) { + items.push(new _captionSettingsMenuItem2['default'](this.player_, { kind: this.kind_ })); + + this.hideThreshold_ += 1; + } + + return _TextTrackButton.prototype.createItems.call(this, items); + }; + + return CaptionsButton; +}(_textTrackButton2['default']); + +/** + * `kind` of TextTrack to look for to associate it with this menu. + * + * @type {string} + * @private + */ + + +CaptionsButton.prototype.kind_ = 'captions'; + +/** + * The text that should display over the `CaptionsButton`s controls. Added for localization. + * + * @type {string} + * @private + */ +CaptionsButton.prototype.controlText_ = 'Captions'; + +_component2['default'].registerComponent('CaptionsButton', CaptionsButton); +exports['default'] = CaptionsButton; + +},{"23":23,"30":30,"5":5}],25:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _textTrackButton = _dereq_(30); + +var _textTrackButton2 = _interopRequireDefault(_textTrackButton); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _chaptersTrackMenuItem = _dereq_(26); + +var _chaptersTrackMenuItem2 = _interopRequireDefault(_chaptersTrackMenuItem); + +var _toTitleCase = _dereq_(91); + +var _toTitleCase2 = _interopRequireDefault(_toTitleCase); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file chapters-button.js + */ + + +/** + * The button component for toggling and selecting chapters + * Chapters act much differently than other text tracks + * Cues are navigation vs. other tracks of alternative languages + * + * @extends TextTrackButton + */ +var ChaptersButton = function (_TextTrackButton) { + _inherits(ChaptersButton, _TextTrackButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} [ready] + * The function to call when this function is ready. + */ + function ChaptersButton(player, options, ready) { + _classCallCheck(this, ChaptersButton); + + var _this = _possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready)); + + _this.el_.setAttribute('aria-label', 'Chapters Menu'); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + ChaptersButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-chapters-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); + }; + + /** + * Update the menu based on the current state of its items. + * + * @param {EventTarget~Event} [event] + * An event that triggered this function to run. + * + * @listens TextTrackList#addtrack + * @listens TextTrackList#removetrack + * @listens TextTrackList#change + */ + + + ChaptersButton.prototype.update = function update(event) { + if (!this.track_ || event && (event.type === 'addtrack' || event.type === 'removetrack')) { + this.setTrack(this.findChaptersTrack()); + } + _TextTrackButton.prototype.update.call(this); + }; + + /** + * Set the currently selected track for the chapters button. + * + * @param {TextTrack} track + * The new track to select. Nothing will change if this is the currently selected + * track. + */ + + + ChaptersButton.prototype.setTrack = function setTrack(track) { + if (this.track_ === track) { + return; + } + + if (!this.updateHandler_) { + this.updateHandler_ = this.update.bind(this); + } + + // here this.track_ refers to the old track instance + if (this.track_) { + var remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(this.track_); + + if (remoteTextTrackEl) { + remoteTextTrackEl.removeEventListener('load', this.updateHandler_); + } + + this.track_ = null; + } + + this.track_ = track; + + // here this.track_ refers to the new track instance + if (this.track_) { + this.track_.mode = 'hidden'; + + var _remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(this.track_); + + if (_remoteTextTrackEl) { + _remoteTextTrackEl.addEventListener('load', this.updateHandler_); + } + } + }; + + /** + * Find the track object that is currently in use by this ChaptersButton + * + * @return {TextTrack|undefined} + * The current track or undefined if none was found. + */ + + + ChaptersButton.prototype.findChaptersTrack = function findChaptersTrack() { + var tracks = this.player_.textTracks() || []; + + for (var i = tracks.length - 1; i >= 0; i--) { + // We will always choose the last track as our chaptersTrack + var track = tracks[i]; + + if (track.kind === this.kind_) { + return track; + } + } + }; + + /** + * Get the caption for the ChaptersButton based on the track label. This will also + * use the current tracks localized kind as a fallback if a label does not exist. + * + * @return {string} + * The tracks current label or the localized track kind. + */ + + + ChaptersButton.prototype.getMenuCaption = function getMenuCaption() { + if (this.track_ && this.track_.label) { + return this.track_.label; + } + return this.localize((0, _toTitleCase2['default'])(this.kind_)); + }; + + /** + * Create menu from chapter track + * + * @return {Menu} + * New menu for the chapter buttons + */ + + + ChaptersButton.prototype.createMenu = function createMenu() { + this.options_.title = this.getMenuCaption(); + return _TextTrackButton.prototype.createMenu.call(this); + }; + + /** + * Create a menu item for each text track + * + * @return {TextTrackMenuItem[]} + * Array of menu items + */ + + + ChaptersButton.prototype.createItems = function createItems() { + var items = []; + + if (!this.track_) { + return items; + } + + var cues = this.track_.cues; + + if (!cues) { + return items; + } + + for (var i = 0, l = cues.length; i < l; i++) { + var cue = cues[i]; + var mi = new _chaptersTrackMenuItem2['default'](this.player_, { track: this.track_, cue: cue }); + + items.push(mi); + } + + return items; + }; + + return ChaptersButton; +}(_textTrackButton2['default']); + +/** + * `kind` of TextTrack to look for to associate it with this menu. + * + * @type {string} + * @private + */ + + +ChaptersButton.prototype.kind_ = 'chapters'; + +/** + * The text that should display over the `ChaptersButton`s controls. Added for localization. + * + * @type {string} + * @private + */ +ChaptersButton.prototype.controlText_ = 'Chapters'; + +_component2['default'].registerComponent('ChaptersButton', ChaptersButton); +exports['default'] = ChaptersButton; + +},{"26":26,"30":30,"5":5,"91":91}],26:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _menuItem = _dereq_(48); + +var _menuItem2 = _interopRequireDefault(_menuItem); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file chapters-track-menu-item.js + */ + + +/** + * The chapter track menu item + * + * @extends MenuItem + */ +var ChaptersTrackMenuItem = function (_MenuItem) { + _inherits(ChaptersTrackMenuItem, _MenuItem); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function ChaptersTrackMenuItem(player, options) { + _classCallCheck(this, ChaptersTrackMenuItem); + + var track = options.track; + var cue = options.cue; + var currentTime = player.currentTime(); + + // Modify options for parent MenuItem class's init. + options.selectable = true; + options.label = cue.text; + options.selected = cue.startTime <= currentTime && currentTime < cue.endTime; + + var _this = _possibleConstructorReturn(this, _MenuItem.call(this, player, options)); + + _this.track = track; + _this.cue = cue; + track.addEventListener('cuechange', Fn.bind(_this, _this.update)); + return _this; + } + + /** + * This gets called when an `ChaptersTrackMenuItem` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + ChaptersTrackMenuItem.prototype.handleClick = function handleClick(event) { + _MenuItem.prototype.handleClick.call(this); + this.player_.currentTime(this.cue.startTime); + this.update(this.cue.startTime); + }; + + /** + * Update chapter menu item + * + * @param {EventTarget~Event} [event] + * The `cuechange` event that caused this function to run. + * + * @listens TextTrack#cuechange + */ + + + ChaptersTrackMenuItem.prototype.update = function update(event) { + var cue = this.cue; + var currentTime = this.player_.currentTime(); + + // vjs.log(currentTime, cue.startTime); + this.selected(cue.startTime <= currentTime && currentTime < cue.endTime); + }; + + return ChaptersTrackMenuItem; +}(_menuItem2['default']); + +_component2['default'].registerComponent('ChaptersTrackMenuItem', ChaptersTrackMenuItem); +exports['default'] = ChaptersTrackMenuItem; + +},{"48":48,"5":5,"83":83}],27:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _textTrackButton = _dereq_(30); + +var _textTrackButton2 = _interopRequireDefault(_textTrackButton); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file descriptions-button.js + */ + + +/** + * The button component for toggling and selecting descriptions + * + * @extends TextTrackButton + */ +var DescriptionsButton = function (_TextTrackButton) { + _inherits(DescriptionsButton, _TextTrackButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} [ready] + * The function to call when this component is ready. + */ + function DescriptionsButton(player, options, ready) { + _classCallCheck(this, DescriptionsButton); + + var _this = _possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready)); + + _this.el_.setAttribute('aria-label', 'Descriptions Menu'); + + var tracks = player.textTracks(); + + if (tracks) { + var changeHandler = Fn.bind(_this, _this.handleTracksChange); + + tracks.addEventListener('change', changeHandler); + _this.on('dispose', function () { + tracks.removeEventListener('change', changeHandler); + }); + } + return _this; + } + + /** + * Handle text track change + * + * @param {EventTarget~Event} event + * The event that caused this function to run + * + * @listens TextTrackList#change + */ + + + DescriptionsButton.prototype.handleTracksChange = function handleTracksChange(event) { + var tracks = this.player().textTracks(); + var disabled = false; + + // Check whether a track of a different kind is showing + for (var i = 0, l = tracks.length; i < l; i++) { + var track = tracks[i]; + + if (track.kind !== this.kind_ && track.mode === 'showing') { + disabled = true; + break; + } + } + + // If another track is showing, disable this menu button + if (disabled) { + this.disable(); + } else { + this.enable(); + } + }; + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + DescriptionsButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-descriptions-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); + }; + + return DescriptionsButton; +}(_textTrackButton2['default']); + +/** + * `kind` of TextTrack to look for to associate it with this menu. + * + * @type {string} + * @private + */ + + +DescriptionsButton.prototype.kind_ = 'descriptions'; + +/** + * The text that should display over the `DescriptionsButton`s controls. Added for localization. + * + * @type {string} + * @private + */ +DescriptionsButton.prototype.controlText_ = 'Descriptions'; + +_component2['default'].registerComponent('DescriptionsButton', DescriptionsButton); +exports['default'] = DescriptionsButton; + +},{"30":30,"5":5,"83":83}],28:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _textTrackMenuItem = _dereq_(31); + +var _textTrackMenuItem2 = _interopRequireDefault(_textTrackMenuItem); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file off-text-track-menu-item.js + */ + + +/** + * A special menu item for turning of a specific type of text track + * + * @extends TextTrackMenuItem + */ +var OffTextTrackMenuItem = function (_TextTrackMenuItem) { + _inherits(OffTextTrackMenuItem, _TextTrackMenuItem); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function OffTextTrackMenuItem(player, options) { + _classCallCheck(this, OffTextTrackMenuItem); + + // Create pseudo track info + // Requires options['kind'] + options.track = { + player: player, + kind: options.kind, + label: options.kind + ' off', + 'default': false, + mode: 'disabled' + }; + + // MenuItem is selectable + options.selectable = true; + + var _this = _possibleConstructorReturn(this, _TextTrackMenuItem.call(this, player, options)); + + _this.selected(true); + return _this; + } + + /** + * Handle text track change + * + * @param {EventTarget~Event} event + * The event that caused this function to run + */ + + + OffTextTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) { + var tracks = this.player().textTracks(); + var selected = true; + + for (var i = 0, l = tracks.length; i < l; i++) { + var track = tracks[i]; + + if (track.kind === this.track.kind && track.mode === 'showing') { + selected = false; + break; + } + } + + this.selected(selected); + }; + + return OffTextTrackMenuItem; +}(_textTrackMenuItem2['default']); + +_component2['default'].registerComponent('OffTextTrackMenuItem', OffTextTrackMenuItem); +exports['default'] = OffTextTrackMenuItem; + +},{"31":31,"5":5}],29:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _textTrackButton = _dereq_(30); + +var _textTrackButton2 = _interopRequireDefault(_textTrackButton); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file subtitles-button.js + */ + + +/** + * The button component for toggling and selecting subtitles + * + * @extends TextTrackButton + */ +var SubtitlesButton = function (_TextTrackButton) { + _inherits(SubtitlesButton, _TextTrackButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} [ready] + * The function to call when this component is ready. + */ + function SubtitlesButton(player, options, ready) { + _classCallCheck(this, SubtitlesButton); + + var _this = _possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready)); + + _this.el_.setAttribute('aria-label', 'Subtitles Menu'); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + SubtitlesButton.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-subtitles-button ' + _TextTrackButton.prototype.buildCSSClass.call(this); + }; + + return SubtitlesButton; +}(_textTrackButton2['default']); + +/** + * `kind` of TextTrack to look for to associate it with this menu. + * + * @type {string} + * @private + */ + + +SubtitlesButton.prototype.kind_ = 'subtitles'; + +/** + * The text that should display over the `SubtitlesButton`s controls. Added for localization. + * + * @type {string} + * @private + */ +SubtitlesButton.prototype.controlText_ = 'Subtitles'; + +_component2['default'].registerComponent('SubtitlesButton', SubtitlesButton); +exports['default'] = SubtitlesButton; + +},{"30":30,"5":5}],30:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _trackButton = _dereq_(36); + +var _trackButton2 = _interopRequireDefault(_trackButton); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _textTrackMenuItem = _dereq_(31); + +var _textTrackMenuItem2 = _interopRequireDefault(_textTrackMenuItem); + +var _offTextTrackMenuItem = _dereq_(28); + +var _offTextTrackMenuItem2 = _interopRequireDefault(_offTextTrackMenuItem); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file text-track-button.js + */ + + +/** + * The base class for buttons that toggle specific text track types (e.g. subtitles) + * + * @extends MenuButton + */ +var TextTrackButton = function (_TrackButton) { + _inherits(TextTrackButton, _TrackButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options={}] + * The key/value store of player options. + */ + function TextTrackButton(player) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, TextTrackButton); + + options.tracks = player.textTracks(); + + return _possibleConstructorReturn(this, _TrackButton.call(this, player, options)); + } + + /** + * Create a menu item for each text track + * + * @param {TextTrackMenuItem[]} [items=[]] + * Existing array of items to use during creation + * + * @return {TextTrackMenuItem[]} + * Array of menu items that were created + */ + + + TextTrackButton.prototype.createItems = function createItems() { + var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + + // Add an OFF menu item to turn all tracks off + items.push(new _offTextTrackMenuItem2['default'](this.player_, { kind: this.kind_ })); + this.hideThreshold_ += 1; + + var tracks = this.player_.textTracks(); + + if (!tracks) { + return items; + } + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + // only add tracks that are of the appropriate kind and have a label + if (track.kind === this.kind_) { + items.push(new _textTrackMenuItem2['default'](this.player_, { + track: track, + // MenuItem is selectable + selectable: true + })); + } + } + + return items; + }; + + return TextTrackButton; +}(_trackButton2['default']); + +_component2['default'].registerComponent('TextTrackButton', TextTrackButton); +exports['default'] = TextTrackButton; + +},{"28":28,"31":31,"36":36,"5":5}],31:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _menuItem = _dereq_(48); + +var _menuItem2 = _interopRequireDefault(_menuItem); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _window = _dereq_(95); + +var _window2 = _interopRequireDefault(_window); + +var _document = _dereq_(94); + +var _document2 = _interopRequireDefault(_document); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file text-track-menu-item.js + */ + + +/** + * The specific menu item type for selecting a language within a text track kind + * + * @extends MenuItem + */ +var TextTrackMenuItem = function (_MenuItem) { + _inherits(TextTrackMenuItem, _MenuItem); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function TextTrackMenuItem(player, options) { + _classCallCheck(this, TextTrackMenuItem); + + var track = options.track; + var tracks = player.textTracks(); + + // Modify options for parent MenuItem class's init. + options.label = track.label || track.language || 'Unknown'; + options.selected = track['default'] || track.mode === 'showing'; + + var _this = _possibleConstructorReturn(this, _MenuItem.call(this, player, options)); + + _this.track = track; + + if (tracks) { + var changeHandler = Fn.bind(_this, _this.handleTracksChange); + + player.on(['loadstart', 'texttrackchange'], changeHandler); + tracks.addEventListener('change', changeHandler); + _this.on('dispose', function () { + tracks.removeEventListener('change', changeHandler); + }); + } + + // iOS7 doesn't dispatch change events to TextTrackLists when an + // associated track's mode changes. Without something like + // Object.observe() (also not present on iOS7), it's not + // possible to detect changes to the mode attribute and polyfill + // the change event. As a poor substitute, we manually dispatch + // change events whenever the controls modify the mode. + if (tracks && tracks.onchange === undefined) { + var event = void 0; + + _this.on(['tap', 'click'], function () { + if (_typeof(_window2['default'].Event) !== 'object') { + // Android 2.3 throws an Illegal Constructor error for window.Event + try { + event = new _window2['default'].Event('change'); + } catch (err) { + // continue regardless of error + } + } + + if (!event) { + event = _document2['default'].createEvent('Event'); + event.initEvent('change', true, true); + } + + tracks.dispatchEvent(event); + }); + } + return _this; + } + + /** + * This gets called when an `TextTrackMenuItem` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} event + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + TextTrackMenuItem.prototype.handleClick = function handleClick(event) { + var kind = this.track.kind; + var tracks = this.player_.textTracks(); + + _MenuItem.prototype.handleClick.call(this, event); + + if (!tracks) { + return; + } + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + if (track.kind !== kind) { + continue; + } + + if (track === this.track) { + if (track.mode !== 'showing') { + track.mode = 'showing'; + } + } else if (track.mode !== 'disabled') { + track.mode = 'disabled'; + } + } + }; + + /** + * Handle text track list change + * + * @param {EventTarget~Event} event + * The `change` event that caused this function to be called. + * + * @listens TextTrackList#change + */ + + + TextTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) { + this.selected(this.track.mode === 'showing'); + }; + + return TextTrackMenuItem; +}(_menuItem2['default']); + +_component2['default'].registerComponent('TextTrackMenuItem', TextTrackMenuItem); +exports['default'] = TextTrackMenuItem; + +},{"48":48,"5":5,"83":83,"94":94,"95":95}],32:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _formatTime = _dereq_(84); + +var _formatTime2 = _interopRequireDefault(_formatTime); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file current-time-display.js + */ + + +/** + * Displays the current time + * + * @extends Component + */ +var CurrentTimeDisplay = function (_Component) { + _inherits(CurrentTimeDisplay, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function CurrentTimeDisplay(player, options) { + _classCallCheck(this, CurrentTimeDisplay); + + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.on(player, 'timeupdate', _this.updateContent); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + CurrentTimeDisplay.prototype.createEl = function createEl() { + var el = _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-current-time vjs-time-control vjs-control' + }); + + this.contentEl_ = Dom.createEl('div', { + className: 'vjs-current-time-display', + // label the current time for screen reader users + innerHTML: 'Current Time ' + '0:00' + }, { + // tell screen readers not to automatically read the time as it changes + 'aria-live': 'off' + }); + + el.appendChild(this.contentEl_); + return el; + }; + + /** + * Update current time display + * + * @param {EventTarget~Event} [event] + * The `timeupdate` event that caused this function to run. + * + * @listens Player#timeupdate + */ + + + CurrentTimeDisplay.prototype.updateContent = function updateContent(event) { + // Allows for smooth scrubbing, when player can't keep up. + var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime(); + var localizedText = this.localize('Current Time'); + var formattedTime = (0, _formatTime2['default'])(time, this.player_.duration()); + + if (formattedTime !== this.formattedTime_) { + this.formattedTime_ = formattedTime; + this.contentEl_.innerHTML = '' + localizedText + ' ' + formattedTime; + } + }; + + return CurrentTimeDisplay; +}(_component2['default']); + +_component2['default'].registerComponent('CurrentTimeDisplay', CurrentTimeDisplay); +exports['default'] = CurrentTimeDisplay; + +},{"5":5,"81":81,"84":84}],33:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _formatTime = _dereq_(84); + +var _formatTime2 = _interopRequireDefault(_formatTime); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file duration-display.js + */ + + +/** + * Displays the duration + * + * @extends Component + */ +var DurationDisplay = function (_Component) { + _inherits(DurationDisplay, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function DurationDisplay(player, options) { + _classCallCheck(this, DurationDisplay); + + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.on(player, 'durationchange', _this.updateContent); + + // Also listen for timeupdate and loadedmetadata because removing those + // listeners could have broken dependent applications/libraries. These + // can likely be removed for 6.0. + _this.on(player, 'timeupdate', _this.updateContent); + _this.on(player, 'loadedmetadata', _this.updateContent); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + DurationDisplay.prototype.createEl = function createEl() { + var el = _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-duration vjs-time-control vjs-control' + }); + + this.contentEl_ = Dom.createEl('div', { + className: 'vjs-duration-display', + // label the duration time for screen reader users + innerHTML: '' + this.localize('Duration Time') + ' 0:00' + }, { + // tell screen readers not to automatically read the time as it changes + 'aria-live': 'off' + }); + + el.appendChild(this.contentEl_); + return el; + }; + + /** + * Update duration time display. + * + * @param {EventTarget~Event} [event] + * The `durationchange`, `timeupdate`, or `loadedmetadata` event that caused + * this function to be called. + * + * @listens Player#durationchange + * @listens Player#timeupdate + * @listens Player#loadedmetadata + */ + + + DurationDisplay.prototype.updateContent = function updateContent(event) { + var duration = this.player_.duration(); + + if (duration && this.duration_ !== duration) { + this.duration_ = duration; + var localizedText = this.localize('Duration Time'); + var formattedTime = (0, _formatTime2['default'])(duration); + + // label the duration time for screen reader users + this.contentEl_.innerHTML = '' + localizedText + ' ' + formattedTime; + } + }; + + return DurationDisplay; +}(_component2['default']); + +_component2['default'].registerComponent('DurationDisplay', DurationDisplay); +exports['default'] = DurationDisplay; + +},{"5":5,"81":81,"84":84}],34:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _formatTime = _dereq_(84); + +var _formatTime2 = _interopRequireDefault(_formatTime); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file remaining-time-display.js + */ + + +/** + * Displays the time left in the video + * + * @extends Component + */ +var RemainingTimeDisplay = function (_Component) { + _inherits(RemainingTimeDisplay, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function RemainingTimeDisplay(player, options) { + _classCallCheck(this, RemainingTimeDisplay); + + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.on(player, 'timeupdate', _this.updateContent); + _this.on(player, 'durationchange', _this.updateContent); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + RemainingTimeDisplay.prototype.createEl = function createEl() { + var el = _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-remaining-time vjs-time-control vjs-control' + }); + + this.contentEl_ = Dom.createEl('div', { + className: 'vjs-remaining-time-display', + // label the remaining time for screen reader users + innerHTML: '' + this.localize('Remaining Time') + ' -0:00' + }, { + // tell screen readers not to automatically read the time as it changes + 'aria-live': 'off' + }); + + el.appendChild(this.contentEl_); + return el; + }; + + /** + * Update remaining time display. + * + * @param {EventTarget~Event} [event] + * The `timeupdate` or `durationchange` event that caused this to run. + * + * @listens Player#timeupdate + * @listens Player#durationchange + */ + + + RemainingTimeDisplay.prototype.updateContent = function updateContent(event) { + if (this.player_.duration()) { + var localizedText = this.localize('Remaining Time'); + var formattedTime = (0, _formatTime2['default'])(this.player_.remainingTime()); + + if (formattedTime !== this.formattedTime_) { + this.formattedTime_ = formattedTime; + this.contentEl_.innerHTML = '' + localizedText + ' -' + formattedTime; + } + } + + // Allows for smooth scrubbing, when player can't keep up. + // var time = (this.player_.scrubbing()) ? this.player_.getCache().currentTime : this.player_.currentTime(); + // this.contentEl_.innerHTML = vjs.formatTime(time, this.player_.duration()); + }; + + return RemainingTimeDisplay; +}(_component2['default']); + +_component2['default'].registerComponent('RemainingTimeDisplay', RemainingTimeDisplay); +exports['default'] = RemainingTimeDisplay; + +},{"5":5,"81":81,"84":84}],35:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file time-divider.js + */ + + +/** + * The separator between the current time and duration. + * Can be hidden if it's not needed in the design. + * + * @extends Component + */ +var TimeDivider = function (_Component) { + _inherits(TimeDivider, _Component); + + function TimeDivider() { + _classCallCheck(this, TimeDivider); + + return _possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Create the component's DOM element + * + * @return {Element} + * The element that was created. + */ + TimeDivider.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-time-control vjs-time-divider', + innerHTML: '
/
' + }); + }; + + return TimeDivider; +}(_component2['default']); + +_component2['default'].registerComponent('TimeDivider', TimeDivider); +exports['default'] = TimeDivider; + +},{"5":5}],36:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _menuButton = _dereq_(47); + +var _menuButton2 = _interopRequireDefault(_menuButton); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file track-button.js + */ + + +/** + * The base class for buttons that toggle specific track types (e.g. subtitles). + * + * @extends MenuButton + */ +var TrackButton = function (_MenuButton) { + _inherits(TrackButton, _MenuButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function TrackButton(player, options) { + _classCallCheck(this, TrackButton); + + var tracks = options.tracks; + + var _this = _possibleConstructorReturn(this, _MenuButton.call(this, player, options)); + + if (_this.items.length <= 1) { + _this.hide(); + } + + if (!tracks) { + return _possibleConstructorReturn(_this); + } + + var updateHandler = Fn.bind(_this, _this.update); + + tracks.addEventListener('removetrack', updateHandler); + tracks.addEventListener('addtrack', updateHandler); + + _this.player_.on('dispose', function () { + tracks.removeEventListener('removetrack', updateHandler); + tracks.removeEventListener('addtrack', updateHandler); + }); + return _this; + } + + return TrackButton; +}(_menuButton2['default']); + +_component2['default'].registerComponent('TrackButton', TrackButton); +exports['default'] = TrackButton; + +},{"47":47,"5":5,"83":83}],37:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _slider = _dereq_(57); + +var _slider2 = _interopRequireDefault(_slider); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +_dereq_(39); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file volume-bar.js + */ + + +// Required children + + +/** + * The bar that contains the volume level and can be clicked on to adjust the level + * + * @extends Slider + */ +var VolumeBar = function (_Slider) { + _inherits(VolumeBar, _Slider); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function VolumeBar(player, options) { + _classCallCheck(this, VolumeBar); + + var _this = _possibleConstructorReturn(this, _Slider.call(this, player, options)); + + _this.on(player, 'volumechange', _this.updateARIAAttributes); + player.ready(Fn.bind(_this, _this.updateARIAAttributes)); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + VolumeBar.prototype.createEl = function createEl() { + return _Slider.prototype.createEl.call(this, 'div', { + className: 'vjs-volume-bar vjs-slider-bar' + }, { + 'aria-label': 'volume level' + }); + }; + + /** + * Handle movement events on the {@link VolumeMenuButton}. + * + * @param {EventTarget~Event} event + * The event that caused this function to run. + * + * @listens mousemove + */ + + + VolumeBar.prototype.handleMouseMove = function handleMouseMove(event) { + this.checkMuted(); + this.player_.volume(this.calculateDistance(event)); + }; + + /** + * If the player is muted unmute it. + */ + + + VolumeBar.prototype.checkMuted = function checkMuted() { + if (this.player_.muted()) { + this.player_.muted(false); + } + }; + + /** + * Get percent of volume level + * + * @return {number} + * Volume level percent as a decimal number. + */ + + + VolumeBar.prototype.getPercent = function getPercent() { + if (this.player_.muted()) { + return 0; + } + return this.player_.volume(); + }; + + /** + * Increase volume level for keyboard users + */ + + + VolumeBar.prototype.stepForward = function stepForward() { + this.checkMuted(); + this.player_.volume(this.player_.volume() + 0.1); + }; + + /** + * Decrease volume level for keyboard users + */ + + + VolumeBar.prototype.stepBack = function stepBack() { + this.checkMuted(); + this.player_.volume(this.player_.volume() - 0.1); + }; + + /** + * Update ARIA accessibility attributes + * + * @param {EventTarget~Event} [event] + * The `volumechange` event that caused this function to run. + * + * @listens Player#volumechange + */ + + + VolumeBar.prototype.updateARIAAttributes = function updateARIAAttributes(event) { + // Current value of volume bar as a percentage + var volume = (this.player_.volume() * 100).toFixed(2); + + this.el_.setAttribute('aria-valuenow', volume); + this.el_.setAttribute('aria-valuetext', volume + '%'); + }; + + return VolumeBar; +}(_slider2['default']); + +/** + * Default options for the `VolumeBar` + * + * @type {Object} + * @private + */ + + +VolumeBar.prototype.options_ = { + children: ['volumeLevel'], + barName: 'volumeLevel' +}; + +/** + * Call the update event for this Slider when this event happens on the player. + * + * @type {string} + */ +VolumeBar.prototype.playerEvent = 'volumechange'; + +_component2['default'].registerComponent('VolumeBar', VolumeBar); +exports['default'] = VolumeBar; + +},{"39":39,"5":5,"57":57,"83":83}],38:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +_dereq_(37); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file volume-control.js + */ + + +// Required children + + +/** + * The component for controlling the volume level + * + * @extends Component + */ +var VolumeControl = function (_Component) { + _inherits(VolumeControl, _Component); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options={}] + * The key/value store of player options. + */ + function VolumeControl(player, options) { + _classCallCheck(this, VolumeControl); + + // hide volume controls when they're not supported by the current tech + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + if (player.tech_ && player.tech_.featuresVolumeControl === false) { + _this.addClass('vjs-hidden'); + } + _this.on(player, 'loadstart', function () { + if (player.tech_.featuresVolumeControl === false) { + this.addClass('vjs-hidden'); + } else { + this.removeClass('vjs-hidden'); + } + }); + return _this; + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + + + VolumeControl.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-volume-control vjs-control' + }); + }; + + return VolumeControl; +}(_component2['default']); + +/** + * Default options for the `VolumeControl` + * + * @type {Object} + * @private + */ + + +VolumeControl.prototype.options_ = { + children: ['volumeBar'] +}; + +_component2['default'].registerComponent('VolumeControl', VolumeControl); +exports['default'] = VolumeControl; + +},{"37":37,"5":5}],39:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file volume-level.js + */ + + +/** + * Shows volume level + * + * @extends Component + */ +var VolumeLevel = function (_Component) { + _inherits(VolumeLevel, _Component); + + function VolumeLevel() { + _classCallCheck(this, VolumeLevel); + + return _possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Create the `Component`'s DOM element + * + * @return {Element} + * The element that was created. + */ + VolumeLevel.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-volume-level', + innerHTML: '' + }); + }; + + return VolumeLevel; +}(_component2['default']); + +_component2['default'].registerComponent('VolumeLevel', VolumeLevel); +exports['default'] = VolumeLevel; + +},{"5":5}],40:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _popup = _dereq_(54); + +var _popup2 = _interopRequireDefault(_popup); + +var _popupButton = _dereq_(53); + +var _popupButton2 = _interopRequireDefault(_popupButton); + +var _muteToggle = _dereq_(11); + +var _muteToggle2 = _interopRequireDefault(_muteToggle); + +var _volumeBar = _dereq_(37); + +var _volumeBar2 = _interopRequireDefault(_volumeBar); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file volume-menu-button.js + */ + + +/** + * Button for volume popup + * + * @extends PopupButton + */ +var VolumeMenuButton = function (_PopupButton) { + _inherits(VolumeMenuButton, _PopupButton); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options={}] + * The key/value store of player options. + */ + function VolumeMenuButton(player) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, VolumeMenuButton); + + // Default to inline + if (options.inline === undefined) { + options.inline = true; + } + + // If the vertical option isn't passed at all, default to true. + if (options.vertical === undefined) { + // If an inline volumeMenuButton is used, we should default to using + // a horizontal slider for obvious reasons. + if (options.inline) { + options.vertical = false; + } else { + options.vertical = true; + } + } + + // The vertical option needs to be set on the volumeBar as well, + // since that will need to be passed along to the VolumeBar constructor + options.volumeBar = options.volumeBar || {}; + options.volumeBar.vertical = !!options.vertical; + + // Same listeners as MuteToggle + var _this = _possibleConstructorReturn(this, _PopupButton.call(this, player, options)); + + _this.on(player, 'volumechange', _this.volumeUpdate); + _this.on(player, 'loadstart', _this.volumeUpdate); + + // hide mute toggle if the current tech doesn't support volume control + function updateVisibility() { + if (player.tech_ && player.tech_.featuresVolumeControl === false) { + this.addClass('vjs-hidden'); + } else { + this.removeClass('vjs-hidden'); + } + } + + updateVisibility.call(_this); + _this.on(player, 'loadstart', updateVisibility); + + _this.on(_this.volumeBar, ['slideractive', 'focus'], function () { + this.addClass('vjs-slider-active'); + }); + + _this.on(_this.volumeBar, ['sliderinactive', 'blur'], function () { + this.removeClass('vjs-slider-active'); + }); + + _this.on(_this.volumeBar, ['focus'], function () { + this.addClass('vjs-lock-showing'); + }); + + _this.on(_this.volumeBar, ['blur'], function () { + this.removeClass('vjs-lock-showing'); + }); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + VolumeMenuButton.prototype.buildCSSClass = function buildCSSClass() { + var orientationClass = ''; + + if (this.options_.vertical) { + orientationClass = 'vjs-volume-menu-button-vertical'; + } else { + orientationClass = 'vjs-volume-menu-button-horizontal'; + } + + return 'vjs-volume-menu-button ' + _PopupButton.prototype.buildCSSClass.call(this) + ' ' + orientationClass; + }; + + /** + * Create the VolumeMenuButton popup + * + * @return {Popup} + * The popup that was created + */ + + + VolumeMenuButton.prototype.createPopup = function createPopup() { + var popup = new _popup2['default'](this.player_, { + contentElType: 'div' + }); + + var vb = new _volumeBar2['default'](this.player_, this.options_.volumeBar); + + popup.addChild(vb); + + this.menuContent = popup; + this.volumeBar = vb; + + this.attachVolumeBarEvents(); + + return popup; + }; + + /** + * This gets called when an `VolumeMenuButton` is "clicked". See + * {@link ClickableComponent} for more detailed information on what a click can be. + * + * @param {EventTarget~Event} [event] + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + VolumeMenuButton.prototype.handleClick = function handleClick(event) { + _muteToggle2['default'].prototype.handleClick.call(this); + _PopupButton.prototype.handleClick.call(this); + }; + + /** + * Add events listeners to the created `VolumeBar`. + */ + + + VolumeMenuButton.prototype.attachVolumeBarEvents = function attachVolumeBarEvents() { + this.menuContent.on(['mousedown', 'touchdown'], Fn.bind(this, this.handleMouseDown)); + }; + + /** + * Handle the `mousedown` and `touchdown` events on the `VolumeBar` + * + * @param {EventTarget~Event} [event] + * The `mousedown` or `touchdown` event that caused this to run. + * + * @listens mousedown + * @listens touchdown + */ + + + VolumeMenuButton.prototype.handleMouseDown = function handleMouseDown(event) { + this.on(['mousemove', 'touchmove'], Fn.bind(this.volumeBar, this.volumeBar.handleMouseMove)); + this.on(this.el_.ownerDocument, ['mouseup', 'touchend'], this.handleMouseUp); + }; + + /** + * Handle the `mouseup` and `touchend` events on the `VolumeBar` + * + * @param {EventTarget~Event} [event] + * The `mouseup` or `touchend` event that caused this to run. + * + * @listens mouseup + * @listens touchend + */ + + + VolumeMenuButton.prototype.handleMouseUp = function handleMouseUp(event) { + this.off(['mousemove', 'touchmove'], Fn.bind(this.volumeBar, this.volumeBar.handleMouseMove)); + }; + + return VolumeMenuButton; +}(_popupButton2['default']); + +/** + * @borrows MuteToggle#update as VolumeMenuButton#volumeUpdate + */ + + +VolumeMenuButton.prototype.volumeUpdate = _muteToggle2['default'].prototype.update; + +/** + * The text that should display over the `VolumeMenuButton`s controls. Added for localization. + * + * @type {string} + * @private + */ +VolumeMenuButton.prototype.controlText_ = 'Mute'; + +_component2['default'].registerComponent('VolumeMenuButton', VolumeMenuButton); +exports['default'] = VolumeMenuButton; + +},{"11":11,"37":37,"5":5,"53":53,"54":54,"83":83}],41:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _modalDialog = _dereq_(50); + +var _modalDialog2 = _interopRequireDefault(_modalDialog); + +var _mergeOptions = _dereq_(87); + +var _mergeOptions2 = _interopRequireDefault(_mergeOptions); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file error-display.js + */ + + +/** + * A display that indicates an error has occurred. This means that the video + * is unplayable. + * + * @extends ModalDialog + */ +var ErrorDisplay = function (_ModalDialog) { + _inherits(ErrorDisplay, _ModalDialog); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function ErrorDisplay(player, options) { + _classCallCheck(this, ErrorDisplay); + + var _this = _possibleConstructorReturn(this, _ModalDialog.call(this, player, options)); + + _this.on(player, 'error', _this.open); + return _this; + } + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + * + * @deprecated Since version 5. + */ + + + ErrorDisplay.prototype.buildCSSClass = function buildCSSClass() { + return 'vjs-error-display ' + _ModalDialog.prototype.buildCSSClass.call(this); + }; + + /** + * Gets the localized error message based on the `Player`s error. + * + * @return {string} + * The `Player`s error message localized or an empty string. + */ + + + ErrorDisplay.prototype.content = function content() { + var error = this.player().error(); + + return error ? this.localize(error.message) : ''; + }; + + return ErrorDisplay; +}(_modalDialog2['default']); + +/** + * The default options for an `ErrorDisplay`. + * + * @private + */ + + +ErrorDisplay.prototype.options_ = (0, _mergeOptions2['default'])(_modalDialog2['default'].prototype.options_, { + pauseOnOpen: false, + fillAlways: true, + temporary: false, + uncloseable: true +}); + +_component2['default'].registerComponent('ErrorDisplay', ErrorDisplay); +exports['default'] = ErrorDisplay; + +},{"5":5,"50":50,"87":87}],42:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _events = _dereq_(82); + +var Events = _interopRequireWildcard(_events); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +/** + * `EventTarget` is a class that can have the same API as the DOM `EventTarget`. It + * adds shorthand functions that wrap around lengthy functions. For example: + * the `on` function is a wrapper around `addEventListener`. + * + * @see [EventTarget Spec]{@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget} + * @class EventTarget + */ +var EventTarget = function EventTarget() {}; + +/** + * A Custom DOM event. + * + * @typedef {Object} EventTarget~Event + * @see [Properties]{@link https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent} + */ + +/** + * All event listeners should follow the following format. + * + * @callback EventTarget~EventListener + * @this {EventTarget} + * + * @param {EventTarget~Event} event + * the event that triggered this function + * + * @param {Object} [hash] + * hash of data sent during the event + */ + +/** + * An object containing event names as keys and booleans as values. + * + * > NOTE: If an event name is set to a true value here {@link EventTarget#trigger} + * will have extra functionality. See that function for more information. + * + * @property EventTarget.prototype.allowedEvents_ + * @private + */ +/** + * @file src/js/event-target.js + */ +EventTarget.prototype.allowedEvents_ = {}; + +/** + * Adds an `event listener` to an instance of an `EventTarget`. An `event listener` is a + * function that will get called when an event with a certain name gets triggered. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {EventTarget~EventListener} fn + * The function to call with `EventTarget`s + */ +EventTarget.prototype.on = function (type, fn) { + // Remove the addEventListener alias before calling Events.on + // so we don't get into an infinite type loop + var ael = this.addEventListener; + + this.addEventListener = function () {}; + Events.on(this, type, fn); + this.addEventListener = ael; +}; + +/** + * An alias of {@link EventTarget#on}. Allows `EventTarget` to mimic + * the standard DOM API. + * + * @function + * @see {@link EventTarget#on} + */ +EventTarget.prototype.addEventListener = EventTarget.prototype.on; + +/** + * Removes an `event listener` for a specific event from an instance of `EventTarget`. + * This makes it so that the `event listener` will no longer get called when the + * named event happens. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {EventTarget~EventListener} fn + * The function to remove. + */ +EventTarget.prototype.off = function (type, fn) { + Events.off(this, type, fn); +}; + +/** + * An alias of {@link EventTarget#off}. Allows `EventTarget` to mimic + * the standard DOM API. + * + * @function + * @see {@link EventTarget#off} + */ +EventTarget.prototype.removeEventListener = EventTarget.prototype.off; + +/** + * This function will add an `event listener` that gets triggered only once. After the + * first trigger it will get removed. This is like adding an `event listener` + * with {@link EventTarget#on} that calls {@link EventTarget#off} on itself. + * + * @param {string|string[]} type + * An event name or an array of event names. + * + * @param {EventTarget~EventListener} fn + * The function to be called once for each event name. + */ +EventTarget.prototype.one = function (type, fn) { + // Remove the addEventListener alialing Events.on + // so we don't get into an infinite type loop + var ael = this.addEventListener; + + this.addEventListener = function () {}; + Events.one(this, type, fn); + this.addEventListener = ael; +}; + +/** + * This function causes an event to happen. This will then cause any `event listeners` + * that are waiting for that event, to get called. If there are no `event listeners` + * for an event then nothing will happen. + * + * If the name of the `Event` that is being triggered is in `EventTarget.allowedEvents_`. + * Trigger will also call the `on` + `uppercaseEventName` function. + * + * Example: + * 'click' is in `EventTarget.allowedEvents_`, so, trigger will attempt to call + * `onClick` if it exists. + * + * @param {string|EventTarget~Event|Object} event + * The name of the event, an `Event`, or an object with a key of type set to + * an event name. + */ +EventTarget.prototype.trigger = function (event) { + var type = event.type || event; + + if (typeof event === 'string') { + event = { type: type }; + } + event = Events.fixEvent(event); + + if (this.allowedEvents_[type] && this['on' + type]) { + this['on' + type](event); + } + + Events.trigger(this, event); +}; + +/** + * An alias of {@link EventTarget#trigger}. Allows `EventTarget` to mimic + * the standard DOM API. + * + * @function + * @see {@link EventTarget#trigger} + */ +EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger; + +exports['default'] = EventTarget; + +},{"82":82}],43:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _log = _dereq_(86); + +var _log2 = _interopRequireDefault(_log); + +var _obj = _dereq_(88); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +/** + * @file extend.js + * @module extend + */ + +/** + * A combination of node inherits and babel's inherits (after transpile). + * Both work the same but node adds `super_` to the subClass + * and Bable adds the superClass as __proto__. Both seem useful. + * + * @param {Object} subClass + * The class to inherit to + * + * @param {Object} superClass + * The class to inherit from + * + * @private + */ +var _inherits = function _inherits(subClass, superClass) { + if (typeof superClass !== 'function' && superClass !== null) { + throw new TypeError('Super expression must either be null or a function, not ' + (typeof superClass === 'undefined' ? 'undefined' : _typeof(superClass))); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + + if (superClass) { + // node + subClass.super_ = superClass; + } +}; + +/** + * Function for subclassing using the same inheritance that + * videojs uses internally + * + * @param {Object} superClass + * The class to inherit from + * + * @param {Object} [subClassMethods={}] + * The class to inherit to + * + * @return {Object} + * The new object with subClassMethods that inherited superClass. + */ +var extendFn = function extendFn(superClass) { + var subClassMethods = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var subClass = function subClass() { + superClass.apply(this, arguments); + }; + + var methods = {}; + + if ((0, _obj.isObject)(subClassMethods)) { + if (typeof subClassMethods.init === 'function') { + _log2['default'].warn('Constructor logic via init() is deprecated; please use constructor() instead.'); + subClassMethods.constructor = subClassMethods.init; + } + if (subClassMethods.constructor !== Object.prototype.constructor) { + subClass = subClassMethods.constructor; + } + methods = subClassMethods; + } else if (typeof subClassMethods === 'function') { + subClass = subClassMethods; + } + + _inherits(subClass, superClass); + + // Extend subObj's prototype with functions and other properties from props + for (var name in methods) { + if (methods.hasOwnProperty(name)) { + subClass.prototype[name] = methods[name]; + } + } + + return subClass; +}; + +exports['default'] = extendFn; + +},{"86":86,"88":88}],44:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _document = _dereq_(94); + +var _document2 = _interopRequireDefault(_document); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +/** + * Store the browser-specific methods for the fullscreen API. + * + * @type {Object} + * @see [Specification]{@link https://fullscreen.spec.whatwg.org} + * @see [Map Approach From Screenfull.js]{@link https://github.com/sindresorhus/screenfull.js} + */ +var FullscreenApi = {}; + +// browser API methods +/** + * @file fullscreen-api.js + * @module fullscreen-api + * @private + */ +var apiMap = [['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror'], +// WebKit +['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror'], +// Old WebKit (Safari 5.1) +['webkitRequestFullScreen', 'webkitCancelFullScreen', 'webkitCurrentFullScreenElement', 'webkitCancelFullScreen', 'webkitfullscreenchange', 'webkitfullscreenerror'], +// Mozilla +['mozRequestFullScreen', 'mozCancelFullScreen', 'mozFullScreenElement', 'mozFullScreenEnabled', 'mozfullscreenchange', 'mozfullscreenerror'], +// Microsoft +['msRequestFullscreen', 'msExitFullscreen', 'msFullscreenElement', 'msFullscreenEnabled', 'MSFullscreenChange', 'MSFullscreenError']]; + +var specApi = apiMap[0]; +var browserApi = void 0; + +// determine the supported set of functions +for (var i = 0; i < apiMap.length; i++) { + // check for exitFullscreen function + if (apiMap[i][1] in _document2['default']) { + browserApi = apiMap[i]; + break; + } +} + +// map the browser API names to the spec API names +if (browserApi) { + for (var _i = 0; _i < browserApi.length; _i++) { + FullscreenApi[specApi[_i]] = browserApi[_i]; + } +} + +exports['default'] = FullscreenApi; + +},{"94":94}],45:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file loading-spinner.js + */ + + +/** + * A loading spinner for use during waiting/loading events. + * + * @extends Component + */ +var LoadingSpinner = function (_Component) { + _inherits(LoadingSpinner, _Component); + + function LoadingSpinner() { + _classCallCheck(this, LoadingSpinner); + + return _possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Create the `LoadingSpinner`s DOM element. + * + * @return {Element} + * The dom element that gets created. + */ + LoadingSpinner.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: 'vjs-loading-spinner', + dir: 'ltr' + }); + }; + + return LoadingSpinner; +}(_component2['default']); + +_component2['default'].registerComponent('LoadingSpinner', LoadingSpinner); +exports['default'] = LoadingSpinner; + +},{"5":5}],46:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _obj = _dereq_(88); + +/** + * A Custom `MediaError` class which mimics the standard HTML5 `MediaError` class. + * + * @param {number|string|Object|MediaError} value + * This can be of multiple types: + * - number: should be a standard error code + * - string: an error message (the code will be 0) + * - Object: arbitrary properties + * - `MediaError` (native): used to populate a video.js `MediaError` object + * - `MediaError` (video.js): will return itself if it's already a + * video.js `MediaError` object. + * + * @see [MediaError Spec]{@link https://dev.w3.org/html5/spec-author-view/video.html#mediaerror} + * @see [Encrypted MediaError Spec]{@link https://www.w3.org/TR/2013/WD-encrypted-media-20130510/#error-codes} + * + * @class MediaError + */ +function MediaError(value) { + + // Allow redundant calls to this constructor to avoid having `instanceof` + // checks peppered around the code. + if (value instanceof MediaError) { + return value; + } + + if (typeof value === 'number') { + this.code = value; + } else if (typeof value === 'string') { + // default code is zero, so this is a custom error + this.message = value; + } else if ((0, _obj.isObject)(value)) { + + // We assign the `code` property manually because native `MediaError` objects + // do not expose it as an own/enumerable property of the object. + if (typeof value.code === 'number') { + this.code = value.code; + } + + (0, _obj.assign)(this, value); + } + + if (!this.message) { + this.message = MediaError.defaultMessages[this.code] || ''; + } +} + +/** + * The error code that refers two one of the defined `MediaError` types + * + * @type {Number} + */ +/** + * @file media-error.js + */ +MediaError.prototype.code = 0; + +/** + * An optional message that to show with the error. Message is not part of the HTML5 + * video spec but allows for more informative custom errors. + * + * @type {String} + */ +MediaError.prototype.message = ''; + +/** + * An optional status code that can be set by plugins to allow even more detail about + * the error. For example a plugin might provide a specific HTTP status code and an + * error message for that code. Then when the plugin gets that error this class will + * know how to display an error message for it. This allows a custom message to show + * up on the `Player` error overlay. + * + * @type {Array} + */ +MediaError.prototype.status = null; + +/** + * Errors indexed by the W3C standard. The order **CANNOT CHANGE**! See the + * specification listed under {@link MediaError} for more information. + * + * @enum {array} + * @readonly + * @property {string} 0 - MEDIA_ERR_CUSTOM + * @property {string} 1 - MEDIA_ERR_CUSTOM + * @property {string} 2 - MEDIA_ERR_ABORTED + * @property {string} 3 - MEDIA_ERR_NETWORK + * @property {string} 4 - MEDIA_ERR_SRC_NOT_SUPPORTED + * @property {string} 5 - MEDIA_ERR_ENCRYPTED + */ +MediaError.errorTypes = ['MEDIA_ERR_CUSTOM', 'MEDIA_ERR_ABORTED', 'MEDIA_ERR_NETWORK', 'MEDIA_ERR_DECODE', 'MEDIA_ERR_SRC_NOT_SUPPORTED', 'MEDIA_ERR_ENCRYPTED']; + +/** + * The default `MediaError` messages based on the {@link MediaError.errorTypes}. + * + * @type {Array} + * @constant + */ +MediaError.defaultMessages = { + 1: 'You aborted the media playback', + 2: 'A network error caused the media download to fail part-way.', + 3: 'The media playback was aborted due to a corruption problem or because the media used features your browser did not support.', + 4: 'The media could not be loaded, either because the server or network failed or because the format is not supported.', + 5: 'The media is encrypted and we do not have the keys to decrypt it.' +}; + +// Add types as properties on MediaError +// e.g. MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4; +for (var errNum = 0; errNum < MediaError.errorTypes.length; errNum++) { + MediaError[MediaError.errorTypes[errNum]] = errNum; + // values should be accessible on both the class and instance + MediaError.prototype[MediaError.errorTypes[errNum]] = errNum; +} + +// jsdocs for instance/static members added above +// instance methods use `#` and static methods use `.` +/** + * W3C error code for any custom error. + * + * @member MediaError#MEDIA_ERR_CUSTOM + * @constant {number} + * @default 0 + */ +/** + * W3C error code for any custom error. + * + * @member MediaError.MEDIA_ERR_CUSTOM + * @constant {number} + * @default 0 + */ + +/** + * W3C error code for media error aborted. + * + * @member MediaError#MEDIA_ERR_ABORTED + * @constant {number} + * @default 1 + */ +/** + * W3C error code for media error aborted. + * + * @member MediaError.MEDIA_ERR_ABORTED + * @constant {number} + * @default 1 + */ + +/** + * W3C error code for any network error. + * + * @member MediaError#MEDIA_ERR_NETWORK + * @constant {number} + * @default 2 + */ +/** + * W3C error code for any network error. + * + * @member MediaError.MEDIA_ERR_NETWORK + * @constant {number} + * @default 2 + */ + +/** + * W3C error code for any decoding error. + * + * @member MediaError#MEDIA_ERR_DECODE + * @constant {number} + * @default 3 + */ +/** + * W3C error code for any decoding error. + * + * @member MediaError.MEDIA_ERR_DECODE + * @constant {number} + * @default 3 + */ + +/** + * W3C error code for any time that a source is not supported. + * + * @member MediaError#MEDIA_ERR_SRC_NOT_SUPPORTED + * @constant {number} + * @default 4 + */ +/** + * W3C error code for any time that a source is not supported. + * + * @member MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED + * @constant {number} + * @default 4 + */ + +/** + * W3C error code for any time that a source is encrypted. + * + * @member MediaError#MEDIA_ERR_ENCRYPTED + * @constant {number} + * @default 5 + */ +/** + * W3C error code for any time that a source is encrypted. + * + * @member MediaError.MEDIA_ERR_ENCRYPTED + * @constant {number} + * @default 5 + */ + +exports['default'] = MediaError; + +},{"88":88}],47:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _clickableComponent = _dereq_(3); + +var _clickableComponent2 = _interopRequireDefault(_clickableComponent); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _menu = _dereq_(49); + +var _menu2 = _interopRequireDefault(_menu); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _toTitleCase = _dereq_(91); + +var _toTitleCase2 = _interopRequireDefault(_toTitleCase); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file menu-button.js + */ + + +/** + * A `MenuButton` class for any popup {@link Menu}. + * + * @extends ClickableComponent + */ +var MenuButton = function (_ClickableComponent) { + _inherits(MenuButton, _ClickableComponent); + + /** + * Creates an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options={}] + * The key/value store of player options. + */ + function MenuButton(player) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, MenuButton); + + var _this = _possibleConstructorReturn(this, _ClickableComponent.call(this, player, options)); + + _this.update(); + + _this.enabled_ = true; + + _this.el_.setAttribute('aria-haspopup', 'true'); + _this.el_.setAttribute('role', 'menuitem'); + _this.on('keydown', _this.handleSubmenuKeyPress); + return _this; + } + + /** + * Update the menu based on the current state of its items. + */ + + + MenuButton.prototype.update = function update() { + var menu = this.createMenu(); + + if (this.menu) { + this.removeChild(this.menu); + } + + this.menu = menu; + this.addChild(menu); + + /** + * Track the state of the menu button + * + * @type {Boolean} + * @private + */ + this.buttonPressed_ = false; + this.el_.setAttribute('aria-expanded', 'false'); + + if (this.items && this.items.length <= this.hideThreshold_) { + this.hide(); + } else { + this.show(); + } + }; + + /** + * Create the menu and add all items to it. + * + * @return {Menu} + * The constructed menu + */ + + + MenuButton.prototype.createMenu = function createMenu() { + var menu = new _menu2['default'](this.player_); + + /** + * Hide the menu if the number of items is less than or equal to this threshold. This defaults + * to 0 and whenever we add items which can be hidden to the menu we'll increment it. We list + * it here because every time we run `createMenu` we need to reset the value. + * + * @protected + * @type {Number} + */ + this.hideThreshold_ = 0; + + // Add a title list item to the top + if (this.options_.title) { + var title = Dom.createEl('li', { + className: 'vjs-menu-title', + innerHTML: (0, _toTitleCase2['default'])(this.options_.title), + tabIndex: -1 + }); + + this.hideThreshold_ += 1; + + menu.children_.unshift(title); + Dom.insertElFirst(title, menu.contentEl()); + } + + this.items = this.createItems(); + + if (this.items) { + // Add menu items to the menu + for (var i = 0; i < this.items.length; i++) { + menu.addItem(this.items[i]); + } + } + + return menu; + }; + + /** + * Create the list of menu items. Specific to each subclass. + * + * @abstract + */ + + + MenuButton.prototype.createItems = function createItems() {}; + + /** + * Create the `MenuButtons`s DOM element. + * + * @return {Element} + * The element that gets created. + */ + + + MenuButton.prototype.createEl = function createEl() { + return _ClickableComponent.prototype.createEl.call(this, 'div', { + className: this.buildCSSClass() + }); + }; + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + MenuButton.prototype.buildCSSClass = function buildCSSClass() { + var menuButtonClass = 'vjs-menu-button'; + + // If the inline option is passed, we want to use different styles altogether. + if (this.options_.inline === true) { + menuButtonClass += '-inline'; + } else { + menuButtonClass += '-popup'; + } + + return 'vjs-menu-button ' + menuButtonClass + ' ' + _ClickableComponent.prototype.buildCSSClass.call(this); + }; + + /** + * Handle a click on a `MenuButton`. + * See {@link ClickableComponent#handleClick} for instances where this is called. + * + * @param {EventTarget~Event} event + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + MenuButton.prototype.handleClick = function handleClick(event) { + // When you click the button it adds focus, which will show the menu. + // So we'll remove focus when the mouse leaves the button. Focus is needed + // for tab navigation. + + this.one(this.menu.contentEl(), 'mouseleave', Fn.bind(this, function (e) { + this.unpressButton(); + this.el_.blur(); + })); + if (this.buttonPressed_) { + this.unpressButton(); + } else { + this.pressButton(); + } + }; + + /** + * Handle tab, escape, down arrow, and up arrow keys for `MenuButton`. See + * {@link ClickableComponent#handleKeyPress} for instances where this is called. + * + * @param {EventTarget~Event} event + * The `keydown` event that caused this function to be called. + * + * @listens keydown + */ + + + MenuButton.prototype.handleKeyPress = function handleKeyPress(event) { + + // Escape (27) key or Tab (9) key unpress the 'button' + if (event.which === 27 || event.which === 9) { + if (this.buttonPressed_) { + this.unpressButton(); + } + // Don't preventDefault for Tab key - we still want to lose focus + if (event.which !== 9) { + event.preventDefault(); + } + // Up (38) key or Down (40) key press the 'button' + } else if (event.which === 38 || event.which === 40) { + if (!this.buttonPressed_) { + this.pressButton(); + event.preventDefault(); + } + } else { + _ClickableComponent.prototype.handleKeyPress.call(this, event); + } + }; + + /** + * Handle a `keydown` event on a sub-menu. The listener for this is added in + * the constructor. + * + * @param {EventTarget~Event} event + * Key press event + * + * @listens keydown + */ + + + MenuButton.prototype.handleSubmenuKeyPress = function handleSubmenuKeyPress(event) { + + // Escape (27) key or Tab (9) key unpress the 'button' + if (event.which === 27 || event.which === 9) { + if (this.buttonPressed_) { + this.unpressButton(); + } + // Don't preventDefault for Tab key - we still want to lose focus + if (event.which !== 9) { + event.preventDefault(); + } + } + }; + + /** + * Put the current `MenuButton` into a pressed state. + */ + + + MenuButton.prototype.pressButton = function pressButton() { + if (this.enabled_) { + this.buttonPressed_ = true; + this.menu.lockShowing(); + this.el_.setAttribute('aria-expanded', 'true'); + // set the focus into the submenu + this.menu.focus(); + } + }; + + /** + * Take the current `MenuButton` out of a pressed state. + */ + + + MenuButton.prototype.unpressButton = function unpressButton() { + if (this.enabled_) { + this.buttonPressed_ = false; + this.menu.unlockShowing(); + this.el_.setAttribute('aria-expanded', 'false'); + // Set focus back to this menu button + this.el_.focus(); + } + }; + + /** + * Disable the `MenuButton`. Don't allow it to be clicked. + * + * @return {MenuButton} + * Returns itself; method can be chained. + */ + + + MenuButton.prototype.disable = function disable() { + // Unpress, but don't force focus on this button + this.buttonPressed_ = false; + this.menu.unlockShowing(); + this.el_.setAttribute('aria-expanded', 'false'); + + this.enabled_ = false; + + return _ClickableComponent.prototype.disable.call(this); + }; + + /** + * Enable the `MenuButton`. Allow it to be clicked. + * + * @return {MenuButton} + * Returns itself; method can be chained. + */ + + + MenuButton.prototype.enable = function enable() { + this.enabled_ = true; + + return _ClickableComponent.prototype.enable.call(this); + }; + + return MenuButton; +}(_clickableComponent2['default']); + +_component2['default'].registerComponent('MenuButton', MenuButton); +exports['default'] = MenuButton; + +},{"3":3,"49":49,"5":5,"81":81,"83":83,"91":91}],48:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _clickableComponent = _dereq_(3); + +var _clickableComponent2 = _interopRequireDefault(_clickableComponent); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _obj = _dereq_(88); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file menu-item.js + */ + + +/** + * The component for a menu item. `
  • ` + * + * @extends ClickableComponent + */ +var MenuItem = function (_ClickableComponent) { + _inherits(MenuItem, _ClickableComponent); + + /** + * Creates an instance of the this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options={}] + * The key/value store of player options. + * + */ + function MenuItem(player, options) { + _classCallCheck(this, MenuItem); + + var _this = _possibleConstructorReturn(this, _ClickableComponent.call(this, player, options)); + + _this.selectable = options.selectable; + + _this.selected(options.selected); + + if (_this.selectable) { + // TODO: May need to be either menuitemcheckbox or menuitemradio, + // and may need logical grouping of menu items. + _this.el_.setAttribute('role', 'menuitemcheckbox'); + } else { + _this.el_.setAttribute('role', 'menuitem'); + } + return _this; + } + + /** + * Create the `MenuItem's DOM element + * + * @param {string} [type=li] + * Element's node type, not actually used, always set to `li`. + * + * @param {Object} [props={}] + * An object of properties that should be set on the element + * + * @param {Object} [attrs={}] + * An object of attributes that should be set on the element + * + * @return {Element} + * The element that gets created. + */ + + + MenuItem.prototype.createEl = function createEl(type, props, attrs) { + // The control is textual, not just an icon + this.nonIconControl = true; + + return _ClickableComponent.prototype.createEl.call(this, 'li', (0, _obj.assign)({ + className: 'vjs-menu-item', + innerHTML: this.localize(this.options_.label), + tabIndex: -1 + }, props), attrs); + }; + + /** + * Any click on a `MenuItem` puts int into the selected state. + * See {@link ClickableComponent#handleClick} for instances where this is called. + * + * @param {EventTarget~Event} event + * The `keydown`, `tap`, or `click` event that caused this function to be + * called. + * + * @listens tap + * @listens click + */ + + + MenuItem.prototype.handleClick = function handleClick(event) { + this.selected(true); + }; + + /** + * Set the state for this menu item as selected or not. + * + * @param {boolean} selected + * if the menu item is selected or not + */ + + + MenuItem.prototype.selected = function selected(_selected) { + if (this.selectable) { + if (_selected) { + this.addClass('vjs-selected'); + this.el_.setAttribute('aria-checked', 'true'); + // aria-checked isn't fully supported by browsers/screen readers, + // so indicate selected state to screen reader in the control text. + this.controlText(', selected'); + } else { + this.removeClass('vjs-selected'); + this.el_.setAttribute('aria-checked', 'false'); + // Indicate un-selected state to screen reader + // Note that a space clears out the selected state text + this.controlText(' '); + } + } + }; + + return MenuItem; +}(_clickableComponent2['default']); + +_component2['default'].registerComponent('MenuItem', MenuItem); +exports['default'] = MenuItem; + +},{"3":3,"5":5,"88":88}],49:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _events = _dereq_(82); + +var Events = _interopRequireWildcard(_events); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file menu.js + */ + + +/** + * The Menu component is used to build popup menus, including subtitle and + * captions selection menus. + * + * @extends Component + */ +var Menu = function (_Component) { + _inherits(Menu, _Component); + + /** + * Create an instance of this class. + * + * @param {Player} player + * the player that this component should attach to + * + * @param {Object} [options] + * Object of option names and values + * + */ + function Menu(player, options) { + _classCallCheck(this, Menu); + + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.focusedChild_ = -1; + + _this.on('keydown', _this.handleKeyPress); + return _this; + } + + /** + * Add a {@link MenuItem} to the menu. + * + * @param {Object|string} component + * The name or instance of the `MenuItem` to add. + * + */ + + + Menu.prototype.addItem = function addItem(component) { + this.addChild(component); + component.on('click', Fn.bind(this, function (event) { + this.unlockShowing(); + // TODO: Need to set keyboard focus back to the menuButton + })); + }; + + /** + * Create the `Menu`s DOM element. + * + * @return {Element} + * the element that was created + */ + + + Menu.prototype.createEl = function createEl() { + var contentElType = this.options_.contentElType || 'ul'; + + this.contentEl_ = Dom.createEl(contentElType, { + className: 'vjs-menu-content' + }); + + this.contentEl_.setAttribute('role', 'menu'); + + var el = _Component.prototype.createEl.call(this, 'div', { + append: this.contentEl_, + className: 'vjs-menu' + }); + + el.setAttribute('role', 'presentation'); + el.appendChild(this.contentEl_); + + // Prevent clicks from bubbling up. Needed for Menu Buttons, + // where a click on the parent is significant + Events.on(el, 'click', function (event) { + event.preventDefault(); + event.stopImmediatePropagation(); + }); + + return el; + }; + + /** + * Handle a `keydown` event on this menu. This listener is added in the constructor. + * + * @param {EventTarget~Event} event + * A `keydown` event that happened on the menu. + * + * @listens keydown + */ + + + Menu.prototype.handleKeyPress = function handleKeyPress(event) { + // Left and Down Arrows + if (event.which === 37 || event.which === 40) { + event.preventDefault(); + this.stepForward(); + + // Up and Right Arrows + } else if (event.which === 38 || event.which === 39) { + event.preventDefault(); + this.stepBack(); + } + }; + + /** + * Move to next (lower) menu item for keyboard users. + */ + + + Menu.prototype.stepForward = function stepForward() { + var stepChild = 0; + + if (this.focusedChild_ !== undefined) { + stepChild = this.focusedChild_ + 1; + } + this.focus(stepChild); + }; + + /** + * Move to previous (higher) menu item for keyboard users. + */ + + + Menu.prototype.stepBack = function stepBack() { + var stepChild = 0; + + if (this.focusedChild_ !== undefined) { + stepChild = this.focusedChild_ - 1; + } + this.focus(stepChild); + }; + + /** + * Set focus on a {@link MenuItem} in the `Menu`. + * + * @param {Object|string} [item=0] + * Index of child item set focus on. + */ + + + Menu.prototype.focus = function focus() { + var item = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; + + var children = this.children().slice(); + var haveTitle = children.length && children[0].className && /vjs-menu-title/.test(children[0].className); + + if (haveTitle) { + children.shift(); + } + + if (children.length > 0) { + if (item < 0) { + item = 0; + } else if (item >= children.length) { + item = children.length - 1; + } + + this.focusedChild_ = item; + + children[item].el_.focus(); + } + }; + + return Menu; +}(_component2['default']); + +_component2['default'].registerComponent('Menu', Menu); +exports['default'] = Menu; + +},{"5":5,"81":81,"82":82,"83":83}],50:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file modal-dialog.js + */ + + +var MODAL_CLASS_NAME = 'vjs-modal-dialog'; +var ESC = 27; + +/** + * The `ModalDialog` displays over the video and its controls, which blocks + * interaction with the player until it is closed. + * + * Modal dialogs include a "Close" button and will close when that button + * is activated - or when ESC is pressed anywhere. + * + * @extends Component + */ + +var ModalDialog = function (_Component) { + _inherits(ModalDialog, _Component); + + /** + * Create an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Mixed} [options.content=undefined] + * Provide customized content for this modal. + * + * @param {string} [options.description] + * A text description for the modal, primarily for accessibility. + * + * @param {boolean} [options.fillAlways=false] + * Normally, modals are automatically filled only the first time + * they open. This tells the modal to refresh its content + * every time it opens. + * + * @param {string} [options.label] + * A text label for the modal, primarily for accessibility. + * + * @param {boolean} [options.temporary=true] + * If `true`, the modal can only be opened once; it will be + * disposed as soon as it's closed. + * + * @param {boolean} [options.uncloseable=false] + * If `true`, the user will not be able to close the modal + * through the UI in the normal ways. Programmatic closing is + * still possible. + */ + function ModalDialog(player, options) { + _classCallCheck(this, ModalDialog); + + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.opened_ = _this.hasBeenOpened_ = _this.hasBeenFilled_ = false; + + _this.closeable(!_this.options_.uncloseable); + _this.content(_this.options_.content); + + // Make sure the contentEl is defined AFTER any children are initialized + // because we only want the contents of the modal in the contentEl + // (not the UI elements like the close button). + _this.contentEl_ = Dom.createEl('div', { + className: MODAL_CLASS_NAME + '-content' + }, { + role: 'document' + }); + + _this.descEl_ = Dom.createEl('p', { + className: MODAL_CLASS_NAME + '-description vjs-offscreen', + id: _this.el().getAttribute('aria-describedby') + }); + + Dom.textContent(_this.descEl_, _this.description()); + _this.el_.appendChild(_this.descEl_); + _this.el_.appendChild(_this.contentEl_); + return _this; + } + + /** + * Create the `ModalDialog`'s DOM element + * + * @return {Element} + * The DOM element that gets created. + */ + + + ModalDialog.prototype.createEl = function createEl() { + return _Component.prototype.createEl.call(this, 'div', { + className: this.buildCSSClass(), + tabIndex: -1 + }, { + 'aria-describedby': this.id() + '_description', + 'aria-hidden': 'true', + 'aria-label': this.label(), + 'role': 'dialog' + }); + }; + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + ModalDialog.prototype.buildCSSClass = function buildCSSClass() { + return MODAL_CLASS_NAME + ' vjs-hidden ' + _Component.prototype.buildCSSClass.call(this); + }; + + /** + * Handles `keydown` events on the document, looking for ESC, which closes + * the modal. + * + * @param {EventTarget~Event} e + * The keypress that triggered this event. + * + * @listens keydown + */ + + + ModalDialog.prototype.handleKeyPress = function handleKeyPress(e) { + if (e.which === ESC && this.closeable()) { + this.close(); + } + }; + + /** + * Returns the label string for this modal. Primarily used for accessibility. + * + * @return {string} + * the localized or raw label of this modal. + */ + + + ModalDialog.prototype.label = function label() { + return this.options_.label || this.localize('Modal Window'); + }; + + /** + * Returns the description string for this modal. Primarily used for + * accessibility. + * + * @return {string} + * The localized or raw description of this modal. + */ + + + ModalDialog.prototype.description = function description() { + var desc = this.options_.description || this.localize('This is a modal window.'); + + // Append a universal closeability message if the modal is closeable. + if (this.closeable()) { + desc += ' ' + this.localize('This modal can be closed by pressing the Escape key or activating the close button.'); + } + + return desc; + }; + + /** + * Opens the modal. + * + * @fires ModalDialog#beforemodalopen + * @fires ModalDialog#modalopen + * + * @return {ModalDialog} + * Returns itself; method can be chained. + */ + + + ModalDialog.prototype.open = function open() { + if (!this.opened_) { + var player = this.player(); + + /** + * Fired just before a `ModalDialog` is opened. + * + * @event ModalDialog#beforemodalopen + * @type {EventTarget~Event} + */ + this.trigger('beforemodalopen'); + this.opened_ = true; + + // Fill content if the modal has never opened before and + // never been filled. + if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) { + this.fill(); + } + + // If the player was playing, pause it and take note of its previously + // playing state. + this.wasPlaying_ = !player.paused(); + + if (this.options_.pauseOnOpen && this.wasPlaying_) { + player.pause(); + } + + if (this.closeable()) { + this.on(this.el_.ownerDocument, 'keydown', Fn.bind(this, this.handleKeyPress)); + } + + player.controls(false); + this.show(); + this.el().setAttribute('aria-hidden', 'false'); + + /** + * Fired just after a `ModalDialog` is opened. + * + * @event ModalDialog#modalopen + * @type {EventTarget~Event} + */ + this.trigger('modalopen'); + this.hasBeenOpened_ = true; + } + return this; + }; + + /** + * If the `ModalDialog` is currently open or closed. + * + * @param {boolean} [value] + * If given, it will open (`true`) or close (`false`) the modal. + * + * @return {boolean} + * the current open state of the modaldialog + */ + + + ModalDialog.prototype.opened = function opened(value) { + if (typeof value === 'boolean') { + this[value ? 'open' : 'close'](); + } + return this.opened_; + }; + + /** + * Closes the modal, does nothing if the `ModalDialog` is + * not open. + * + * @fires ModalDialog#beforemodalclose + * @fires ModalDialog#modalclose + * + * @return {ModalDialog} + * Returns itself; method can be chained. + */ + + + ModalDialog.prototype.close = function close() { + if (this.opened_) { + var player = this.player(); + + /** + * Fired just before a `ModalDialog` is closed. + * + * @event ModalDialog#beforemodalclose + * @type {EventTarget~Event} + */ + this.trigger('beforemodalclose'); + this.opened_ = false; + + if (this.wasPlaying_ && this.options_.pauseOnOpen) { + player.play(); + } + + if (this.closeable()) { + this.off(this.el_.ownerDocument, 'keydown', Fn.bind(this, this.handleKeyPress)); + } + + player.controls(true); + this.hide(); + this.el().setAttribute('aria-hidden', 'true'); + + /** + * Fired just after a `ModalDialog` is closed. + * + * @event ModalDialog#modalclose + * @type {EventTarget~Event} + */ + this.trigger('modalclose'); + + if (this.options_.temporary) { + this.dispose(); + } + } + return this; + }; + + /** + * Check to see if the `ModalDialog` is closeable via the UI. + * + * @param {boolean} [value] + * If given as a boolean, it will set the `closeable` option. + * + * @return {boolean} + * Returns the final value of the closable option. + */ + + + ModalDialog.prototype.closeable = function closeable(value) { + if (typeof value === 'boolean') { + var closeable = this.closeable_ = !!value; + var close = this.getChild('closeButton'); + + // If this is being made closeable and has no close button, add one. + if (closeable && !close) { + + // The close button should be a child of the modal - not its + // content element, so temporarily change the content element. + var temp = this.contentEl_; + + this.contentEl_ = this.el_; + close = this.addChild('closeButton', { controlText: 'Close Modal Dialog' }); + this.contentEl_ = temp; + this.on(close, 'close', this.close); + } + + // If this is being made uncloseable and has a close button, remove it. + if (!closeable && close) { + this.off(close, 'close', this.close); + this.removeChild(close); + close.dispose(); + } + } + return this.closeable_; + }; + + /** + * Fill the modal's content element with the modal's "content" option. + * The content element will be emptied before this change takes place. + * + * @return {ModalDialog} + * Returns itself; method can be chained. + */ + + + ModalDialog.prototype.fill = function fill() { + return this.fillWith(this.content()); + }; + + /** + * Fill the modal's content element with arbitrary content. + * The content element will be emptied before this change takes place. + * + * @fires ModalDialog#beforemodalfill + * @fires ModalDialog#modalfill + * + * @param {Mixed} [content] + * The same rules apply to this as apply to the `content` option. + * + * @return {ModalDialog} + * Returns itself; method can be chained. + */ + + + ModalDialog.prototype.fillWith = function fillWith(content) { + var contentEl = this.contentEl(); + var parentEl = contentEl.parentNode; + var nextSiblingEl = contentEl.nextSibling; + + /** + * Fired just before a `ModalDialog` is filled with content. + * + * @event ModalDialog#beforemodalfill + * @type {EventTarget~Event} + */ + this.trigger('beforemodalfill'); + this.hasBeenFilled_ = true; + + // Detach the content element from the DOM before performing + // manipulation to avoid modifying the live DOM multiple times. + parentEl.removeChild(contentEl); + this.empty(); + Dom.insertContent(contentEl, content); + /** + * Fired just after a `ModalDialog` is filled with content. + * + * @event ModalDialog#modalfill + * @type {EventTarget~Event} + */ + this.trigger('modalfill'); + + // Re-inject the re-filled content element. + if (nextSiblingEl) { + parentEl.insertBefore(contentEl, nextSiblingEl); + } else { + parentEl.appendChild(contentEl); + } + + return this; + }; + + /** + * Empties the content element. This happens anytime the modal is filled. + * + * @fires ModalDialog#beforemodalempty + * @fires ModalDialog#modalempty + * + * @return {ModalDialog} + * Returns itself; method can be chained. + */ + + + ModalDialog.prototype.empty = function empty() { + /** + * Fired just before a `ModalDialog` is emptied. + * + * @event ModalDialog#beforemodalempty + * @type {EventTarget~Event} + */ + this.trigger('beforemodalempty'); + Dom.emptyEl(this.contentEl()); + + /** + * Fired just after a `ModalDialog` is emptied. + * + * @event ModalDialog#modalempty + * @type {EventTarget~Event} + */ + this.trigger('modalempty'); + return this; + }; + + /** + * Gets or sets the modal content, which gets normalized before being + * rendered into the DOM. + * + * This does not update the DOM or fill the modal, but it is called during + * that process. + * + * @param {Mixed} [value] + * If defined, sets the internal content value to be used on the + * next call(s) to `fill`. This value is normalized before being + * inserted. To "clear" the internal content value, pass `null`. + * + * @return {Mixed} + * The current content of the modal dialog + */ + + + ModalDialog.prototype.content = function content(value) { + if (typeof value !== 'undefined') { + this.content_ = value; + } + return this.content_; + }; + + return ModalDialog; +}(_component2['default']); + +/** + * Default options for `ModalDialog` default options. + * + * @type {Object} + * @private + */ + + +ModalDialog.prototype.options_ = { + pauseOnOpen: true, + temporary: true +}; + +_component2['default'].registerComponent('ModalDialog', ModalDialog); +exports['default'] = ModalDialog; + +},{"5":5,"81":81,"83":83}],51:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _document = _dereq_(94); + +var _document2 = _interopRequireDefault(_document); + +var _window = _dereq_(95); + +var _window2 = _interopRequireDefault(_window); + +var _events = _dereq_(82); + +var Events = _interopRequireWildcard(_events); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _guid = _dereq_(85); + +var Guid = _interopRequireWildcard(_guid); + +var _browser = _dereq_(78); + +var browser = _interopRequireWildcard(_browser); + +var _log = _dereq_(86); + +var _log2 = _interopRequireDefault(_log); + +var _toTitleCase = _dereq_(91); + +var _toTitleCase2 = _interopRequireDefault(_toTitleCase); + +var _timeRanges = _dereq_(90); + +var _buffer = _dereq_(79); + +var _stylesheet = _dereq_(89); + +var stylesheet = _interopRequireWildcard(_stylesheet); + +var _fullscreenApi = _dereq_(44); + +var _fullscreenApi2 = _interopRequireDefault(_fullscreenApi); + +var _mediaError = _dereq_(46); + +var _mediaError2 = _interopRequireDefault(_mediaError); + +var _tuple = _dereq_(97); + +var _tuple2 = _interopRequireDefault(_tuple); + +var _obj = _dereq_(88); + +var _mergeOptions = _dereq_(87); + +var _mergeOptions2 = _interopRequireDefault(_mergeOptions); + +var _textTrackListConverter = _dereq_(69); + +var _textTrackListConverter2 = _interopRequireDefault(_textTrackListConverter); + +var _modalDialog = _dereq_(50); + +var _modalDialog2 = _interopRequireDefault(_modalDialog); + +var _tech = _dereq_(62); + +var _tech2 = _interopRequireDefault(_tech); + +var _audioTrackList = _dereq_(63); + +var _audioTrackList2 = _interopRequireDefault(_audioTrackList); + +var _videoTrackList = _dereq_(76); + +var _videoTrackList2 = _interopRequireDefault(_videoTrackList); + +_dereq_(61); + +_dereq_(59); + +_dereq_(55); + +_dereq_(68); + +_dereq_(45); + +_dereq_(1); + +_dereq_(4); + +_dereq_(8); + +_dereq_(41); + +_dereq_(71); + +_dereq_(60); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file player.js + */ +// Subclasses Component + + +// The following imports are used only to ensure that the corresponding modules +// are always included in the video.js package. Importing the modules will +// execute them and they will register themselves with video.js. + + +// Import Html5 tech, at least for disposing the original video tag. + + +// The following tech events are simply re-triggered +// on the player when they happen +var TECH_EVENTS_RETRIGGER = [ +/** + * Fired while the user agent is downloading media data. + * + * @event Player#progress + * @type {EventTarget~Event} + */ +/** + * Retrigger the `progress` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechProgress_ + * @fires Player#progress + * @listens Tech#progress + */ +'progress', + +/** + * Fires when the loading of an audio/video is aborted. + * + * @event Player#abort + * @type {EventTarget~Event} + */ +/** + * Retrigger the `abort` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechAbort_ + * @fires Player#abort + * @listens Tech#abort + */ +'abort', + +/** + * Fires when the browser is intentionally not getting media data. + * + * @event Player#suspend + * @type {EventTarget~Event} + */ +/** + * Retrigger the `suspend` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechSuspend_ + * @fires Player#suspend + * @listens Tech#suspend + */ +'suspend', + +/** + * Fires when the current playlist is empty. + * + * @event Player#emptied + * @type {EventTarget~Event} + */ +/** + * Retrigger the `emptied` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechEmptied_ + * @fires Player#emptied + * @listens Tech#emptied + */ +'emptied', +/** + * Fires when the browser is trying to get media data, but data is not available. + * + * @event Player#stalled + * @type {EventTarget~Event} + */ +/** + * Retrigger the `stalled` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechStalled_ + * @fires Player#stalled + * @listens Tech#stalled + */ +'stalled', + +/** + * Fires when the browser has loaded meta data for the audio/video. + * + * @event Player#loadedmetadata + * @type {EventTarget~Event} + */ +/** + * Retrigger the `stalled` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechLoadedmetadata_ + * @fires Player#loadedmetadata + * @listens Tech#loadedmetadata + */ +'loadedmetadata', + +/** + * Fires when the browser has loaded the current frame of the audio/video. + * + * @event player#loadeddata + * @type {event} + */ +/** + * Retrigger the `loadeddata` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechLoaddeddata_ + * @fires Player#loadeddata + * @listens Tech#loadeddata + */ +'loadeddata', + +/** + * Fires when the current playback position has changed. + * + * @event player#timeupdate + * @type {event} + */ +/** + * Retrigger the `timeupdate` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechTimeUpdate_ + * @fires Player#timeupdate + * @listens Tech#timeupdate + */ +'timeupdate', + +/** + * Fires when the playing speed of the audio/video is changed + * + * @event player#ratechange + * @type {event} + */ +/** + * Retrigger the `ratechange` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechRatechange_ + * @fires Player#ratechange + * @listens Tech#ratechange + */ +'ratechange', + +/** + * Fires when the volume has been changed + * + * @event player#volumechange + * @type {event} + */ +/** + * Retrigger the `volumechange` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechVolumechange_ + * @fires Player#volumechange + * @listens Tech#volumechange + */ +'volumechange', + +/** + * Fires when the text track has been changed + * + * @event player#texttrackchange + * @type {event} + */ +/** + * Retrigger the `texttrackchange` event that was triggered by the {@link Tech}. + * + * @private + * @method Player#handleTechTexttrackchange_ + * @fires Player#texttrackchange + * @listens Tech#texttrackchange + */ +'texttrackchange']; + +/** + * An instance of the `Player` class is created when any of the Video.js setup methods + * are used to initialize a video. + * + * After an instance has been created it can be accessed globally in two ways: + * 1. By calling `videojs('example_video_1');` + * 2. By using it directly via `videojs.players.example_video_1;` + * + * @extends Component + */ + +var Player = function (_Component) { + _inherits(Player, _Component); + + /** + * Create an instance of this class. + * + * @param {Element} tag + * The original video DOM element used for configuring options. + * + * @param {Object} [options] + * Object of option names and values. + * + * @param {Component~ReadyCallback} [ready] + * Ready callback function. + */ + function Player(tag, options, ready) { + _classCallCheck(this, Player); + + // Make sure tag ID exists + tag.id = tag.id || 'vjs_video_' + Guid.newGUID(); + + // Set Options + // The options argument overrides options set in the video tag + // which overrides globally set options. + // This latter part coincides with the load order + // (tag must exist before Player) + options = (0, _obj.assign)(Player.getTagSettings(tag), options); + + // Delay the initialization of children because we need to set up + // player properties first, and can't use `this` before `super()` + options.initChildren = false; + + // Same with creating the element + options.createEl = false; + + // we don't want the player to report touch activity on itself + // see enableTouchActivity in Component + options.reportTouchActivity = false; + + // If language is not set, get the closest lang attribute + if (!options.language) { + if (typeof tag.closest === 'function') { + var closest = tag.closest('[lang]'); + + if (closest) { + options.language = closest.getAttribute('lang'); + } + } else { + var element = tag; + + while (element && element.nodeType === 1) { + if (Dom.getElAttributes(element).hasOwnProperty('lang')) { + options.language = element.getAttribute('lang'); + break; + } + element = element.parentNode; + } + } + } + + // Run base component initializing with new options + + // if the global option object was accidentally blown away by + // someone, bail early with an informative error + var _this = _possibleConstructorReturn(this, _Component.call(this, null, options, ready)); + + if (!_this.options_ || !_this.options_.techOrder || !_this.options_.techOrder.length) { + throw new Error('No techOrder specified. Did you overwrite ' + 'videojs.options instead of just changing the ' + 'properties you want to override?'); + } + + // Store the original tag used to set options + _this.tag = tag; + + // Store the tag attributes used to restore html5 element + _this.tagAttributes = tag && Dom.getElAttributes(tag); + + // Update current language + _this.language(_this.options_.language); + + // Update Supported Languages + if (options.languages) { + // Normalise player option languages to lowercase + var languagesToLower = {}; + + Object.getOwnPropertyNames(options.languages).forEach(function (name) { + languagesToLower[name.toLowerCase()] = options.languages[name]; + }); + _this.languages_ = languagesToLower; + } else { + _this.languages_ = Player.prototype.options_.languages; + } + + // Cache for video property values. + _this.cache_ = {}; + + // Set poster + _this.poster_ = options.poster || ''; + + // Set controls + _this.controls_ = !!options.controls; + + // Original tag settings stored in options + // now remove immediately so native controls don't flash. + // May be turned back on by HTML5 tech if nativeControlsForTouch is true + tag.controls = false; + + /* + * Store the internal state of scrubbing + * + * @private + * @return {Boolean} True if the user is scrubbing + */ + _this.scrubbing_ = false; + + _this.el_ = _this.createEl(); + + // We also want to pass the original player options to each component and plugin + // as well so they don't need to reach back into the player for options later. + // We also need to do another copy of this.options_ so we don't end up with + // an infinite loop. + var playerOptionsCopy = (0, _mergeOptions2['default'])(_this.options_); + + // Load plugins + if (options.plugins) { + var plugins = options.plugins; + + Object.getOwnPropertyNames(plugins).forEach(function (name) { + if (typeof this[name] === 'function') { + this[name](plugins[name]); + } else { + _log2['default'].error('Unable to find plugin:', name); + } + }, _this); + } + + _this.options_.playerOptions = playerOptionsCopy; + + _this.initChildren(); + + // Set isAudio based on whether or not an audio tag was used + _this.isAudio(tag.nodeName.toLowerCase() === 'audio'); + + // Update controls className. Can't do this when the controls are initially + // set because the element doesn't exist yet. + if (_this.controls()) { + _this.addClass('vjs-controls-enabled'); + } else { + _this.addClass('vjs-controls-disabled'); + } + + // Set ARIA label and region role depending on player type + _this.el_.setAttribute('role', 'region'); + if (_this.isAudio()) { + _this.el_.setAttribute('aria-label', 'audio player'); + } else { + _this.el_.setAttribute('aria-label', 'video player'); + } + + if (_this.isAudio()) { + _this.addClass('vjs-audio'); + } + + if (_this.flexNotSupported_()) { + _this.addClass('vjs-no-flex'); + } + + // TODO: Make this smarter. Toggle user state between touching/mousing + // using events, since devices can have both touch and mouse events. + // if (browser.TOUCH_ENABLED) { + // this.addClass('vjs-touch-enabled'); + // } + + // iOS Safari has broken hover handling + if (!browser.IS_IOS) { + _this.addClass('vjs-workinghover'); + } + + // Make player easily findable by ID + Player.players[_this.id_] = _this; + + // Add a major version class to aid css in plugins + var majorVersion = '5.20.2'.split('.')[0]; + + _this.addClass('vjs-v' + majorVersion); + + // When the player is first initialized, trigger activity so components + // like the control bar show themselves if needed + _this.userActive(true); + _this.reportUserActivity(); + _this.listenForUserActivity_(); + + _this.on('fullscreenchange', _this.handleFullscreenChange_); + _this.on('stageclick', _this.handleStageClick_); + return _this; + } + + /** + * Destroys the video player and does any necessary cleanup. + * + * This is especially helpful if you are dynamically adding and removing videos + * to/from the DOM. + * + * @fires Player#dispose + */ + + + Player.prototype.dispose = function dispose() { + /** + * Called when the player is being disposed of. + * + * @event Player#dispose + * @type {EventTarget~Event} + */ + this.trigger('dispose'); + // prevent dispose from being called twice + this.off('dispose'); + + if (this.styleEl_ && this.styleEl_.parentNode) { + this.styleEl_.parentNode.removeChild(this.styleEl_); + } + + // Kill reference to this player + Player.players[this.id_] = null; + + if (this.tag && this.tag.player) { + this.tag.player = null; + } + + if (this.el_ && this.el_.player) { + this.el_.player = null; + } + + if (this.tech_) { + this.tech_.dispose(); + } + + _Component.prototype.dispose.call(this); + }; + + /** + * Create the `Player`'s DOM element. + * + * @return {Element} + * The DOM element that gets created. + */ + + + Player.prototype.createEl = function createEl() { + var tag = this.tag; + var el = void 0; + var playerElIngest = this.playerElIngest_ = tag.parentNode && tag.parentNode.hasAttribute && tag.parentNode.hasAttribute('data-vjs-player'); + + if (playerElIngest) { + el = this.el_ = tag.parentNode; + } else { + el = this.el_ = _Component.prototype.createEl.call(this, 'div'); + } + + // set tabindex to -1 so we could focus on the player element + tag.setAttribute('tabindex', '-1'); + + // Remove width/height attrs from tag so CSS can make it 100% width/height + tag.removeAttribute('width'); + tag.removeAttribute('height'); + + // Copy over all the attributes from the tag, including ID and class + // ID will now reference player box, not the video tag + var attrs = Dom.getElAttributes(tag); + + Object.getOwnPropertyNames(attrs).forEach(function (attr) { + // workaround so we don't totally break IE7 + // http://stackoverflow.com/questions/3653444/css-styles-not-applied-on-dynamic-elements-in-internet-explorer-7 + if (attr === 'class') { + el.className += ' ' + attrs[attr]; + } else { + el.setAttribute(attr, attrs[attr]); + } + }); + + // Update tag id/class for use as HTML5 playback tech + // Might think we should do this after embedding in container so .vjs-tech class + // doesn't flash 100% width/height, but class only applies with .video-js parent + tag.playerId = tag.id; + tag.id += '_html5_api'; + tag.className = 'vjs-tech'; + + // Make player findable on elements + tag.player = el.player = this; + // Default state of video is paused + this.addClass('vjs-paused'); + + // Add a style element in the player that we'll use to set the width/height + // of the player in a way that's still overrideable by CSS, just like the + // video element + if (_window2['default'].VIDEOJS_NO_DYNAMIC_STYLE !== true) { + this.styleEl_ = stylesheet.createStyleElement('vjs-styles-dimensions'); + var defaultsStyleEl = Dom.$('.vjs-styles-defaults'); + var head = Dom.$('head'); + + head.insertBefore(this.styleEl_, defaultsStyleEl ? defaultsStyleEl.nextSibling : head.firstChild); + } + + // Pass in the width/height/aspectRatio options which will update the style el + this.width(this.options_.width); + this.height(this.options_.height); + this.fluid(this.options_.fluid); + this.aspectRatio(this.options_.aspectRatio); + + // Hide any links within the video/audio tag, because IE doesn't hide them completely. + var links = tag.getElementsByTagName('a'); + + for (var i = 0; i < links.length; i++) { + var linkEl = links.item(i); + + Dom.addElClass(linkEl, 'vjs-hidden'); + linkEl.setAttribute('hidden', 'hidden'); + } + + // insertElFirst seems to cause the networkState to flicker from 3 to 2, so + // keep track of the original for later so we can know if the source originally failed + tag.initNetworkState_ = tag.networkState; + + // Wrap video tag in div (el/box) container + if (tag.parentNode && !playerElIngest) { + tag.parentNode.insertBefore(el, tag); + } + + // insert the tag as the first child of the player element + // then manually add it to the children array so that this.addChild + // will work properly for other components + // + // Breaks iPhone, fixed in HTML5 setup. + Dom.insertElFirst(tag, el); + this.children_.unshift(tag); + + this.el_ = el; + + return el; + }; + + /** + * A getter/setter for the `Player`'s width. + * + * @param {number} [value] + * The value to set the `Player's width to. + * + * @return {number} + * The current width of the `Player`. + */ + + + Player.prototype.width = function width(value) { + return this.dimension('width', value); + }; + + /** + * A getter/setter for the `Player`'s height. + * + * @param {number} [value] + * The value to set the `Player's heigth to. + * + * @return {number} + * The current heigth of the `Player`. + */ + + + Player.prototype.height = function height(value) { + return this.dimension('height', value); + }; + + /** + * A getter/setter for the `Player`'s width & height. + * + * @param {string} dimension + * This string can be: + * - 'width' + * - 'height' + * + * @param {number} [value] + * Value for dimension specified in the first argument. + * + * @return {Player|number} + * - Returns itself when setting; method can be chained. + * - The dimension arguments value when getting (width/height). + */ + + + Player.prototype.dimension = function dimension(_dimension, value) { + var privDimension = _dimension + '_'; + + if (value === undefined) { + return this[privDimension] || 0; + } + + if (value === '') { + // If an empty string is given, reset the dimension to be automatic + this[privDimension] = undefined; + } else { + var parsedVal = parseFloat(value); + + if (isNaN(parsedVal)) { + _log2['default'].error('Improper value "' + value + '" supplied for for ' + _dimension); + return this; + } + + this[privDimension] = parsedVal; + } + + this.updateStyleEl_(); + return this; + }; + + /** + * A getter/setter/toggler for the vjs-fluid `className` on the `Player`. + * + * @param {boolean} [bool] + * - A value of true adds the class. + * - A value of false removes the class. + * - No value will toggle the fluid class. + * + * @return {boolean|undefined} + * - The value of fluid when getting. + * - `undefined` when setting. + */ + + + Player.prototype.fluid = function fluid(bool) { + if (bool === undefined) { + return !!this.fluid_; + } + + this.fluid_ = !!bool; + + if (bool) { + this.addClass('vjs-fluid'); + } else { + this.removeClass('vjs-fluid'); + } + + this.updateStyleEl_(); + }; + + /** + * Get/Set the aspect ratio + * + * @param {string} [ratio] + * Aspect ratio for player + * + * @return {string|undefined} + * returns the current aspect ratio when getting + */ + + /** + * A getter/setter for the `Player`'s aspect ratio. + * + * @param {string} [ratio] + * The value to set the `Player's aspect ratio to. + * + * @return {string|undefined} + * - The current aspect ratio of the `Player` when getting. + * - undefined when setting + */ + + + Player.prototype.aspectRatio = function aspectRatio(ratio) { + if (ratio === undefined) { + return this.aspectRatio_; + } + + // Check for width:height format + if (!/^\d+\:\d+$/.test(ratio)) { + throw new Error('Improper value supplied for aspect ratio. The format should be width:height, for example 16:9.'); + } + this.aspectRatio_ = ratio; + + // We're assuming if you set an aspect ratio you want fluid mode, + // because in fixed mode you could calculate width and height yourself. + this.fluid(true); + + this.updateStyleEl_(); + }; + + /** + * Update styles of the `Player` element (height, width and aspect ratio). + * + * @private + * @listens Tech#loadedmetadata + */ + + + Player.prototype.updateStyleEl_ = function updateStyleEl_() { + if (_window2['default'].VIDEOJS_NO_DYNAMIC_STYLE === true) { + var _width = typeof this.width_ === 'number' ? this.width_ : this.options_.width; + var _height = typeof this.height_ === 'number' ? this.height_ : this.options_.height; + var techEl = this.tech_ && this.tech_.el(); + + if (techEl) { + if (_width >= 0) { + techEl.width = _width; + } + if (_height >= 0) { + techEl.height = _height; + } + } + + return; + } + + var width = void 0; + var height = void 0; + var aspectRatio = void 0; + var idClass = void 0; + + // The aspect ratio is either used directly or to calculate width and height. + if (this.aspectRatio_ !== undefined && this.aspectRatio_ !== 'auto') { + // Use any aspectRatio that's been specifically set + aspectRatio = this.aspectRatio_; + } else if (this.videoWidth() > 0) { + // Otherwise try to get the aspect ratio from the video metadata + aspectRatio = this.videoWidth() + ':' + this.videoHeight(); + } else { + // Or use a default. The video element's is 2:1, but 16:9 is more common. + aspectRatio = '16:9'; + } + + // Get the ratio as a decimal we can use to calculate dimensions + var ratioParts = aspectRatio.split(':'); + var ratioMultiplier = ratioParts[1] / ratioParts[0]; + + if (this.width_ !== undefined) { + // Use any width that's been specifically set + width = this.width_; + } else if (this.height_ !== undefined) { + // Or calulate the width from the aspect ratio if a height has been set + width = this.height_ / ratioMultiplier; + } else { + // Or use the video's metadata, or use the video el's default of 300 + width = this.videoWidth() || 300; + } + + if (this.height_ !== undefined) { + // Use any height that's been specifically set + height = this.height_; + } else { + // Otherwise calculate the height from the ratio and the width + height = width * ratioMultiplier; + } + + // Ensure the CSS class is valid by starting with an alpha character + if (/^[^a-zA-Z]/.test(this.id())) { + idClass = 'dimensions-' + this.id(); + } else { + idClass = this.id() + '-dimensions'; + } + + // Ensure the right class is still on the player for the style element + this.addClass(idClass); + + stylesheet.setTextContent(this.styleEl_, '\n .' + idClass + ' {\n width: ' + width + 'px;\n height: ' + height + 'px;\n }\n\n .' + idClass + '.vjs-fluid {\n padding-top: ' + ratioMultiplier * 100 + '%;\n }\n '); + }; + + /** + * Load/Create an instance of playback {@link Tech} including element + * and API methods. Then append the `Tech` element in `Player` as a child. + * + * @param {string} techName + * name of the playback technology + * + * @param {string} source + * video source + * + * @private + */ + + + Player.prototype.loadTech_ = function loadTech_(techName, source) { + var _this2 = this; + + // Pause and remove current playback technology + if (this.tech_) { + this.unloadTech_(); + } + + // get rid of the HTML5 video tag as soon as we are using another tech + if (techName !== 'Html5' && this.tag) { + _tech2['default'].getTech('Html5').disposeMediaElement(this.tag); + this.tag.player = null; + this.tag = null; + } + + this.techName_ = techName; + + // Turn off API access because we're loading a new tech that might load asynchronously + this.isReady_ = false; + + // Grab tech-specific options from player options and add source and parent element to use. + var techOptions = (0, _obj.assign)({ + source: source, + 'nativeControlsForTouch': this.options_.nativeControlsForTouch, + 'playerId': this.id(), + 'techId': this.id() + '_' + techName + '_api', + 'videoTracks': this.videoTracks_, + 'textTracks': this.textTracks_, + 'audioTracks': this.audioTracks_, + 'autoplay': this.options_.autoplay, + 'playsinline': this.options_.playsinline, + 'preload': this.options_.preload, + 'loop': this.options_.loop, + 'muted': this.options_.muted, + 'poster': this.poster(), + 'language': this.language(), + 'playerElIngest': this.playerElIngest_ || false, + 'vtt.js': this.options_['vtt.js'] + }, this.options_[techName.toLowerCase()]); + + if (this.tag) { + techOptions.tag = this.tag; + } + + if (source) { + this.currentType_ = source.type; + + if (source.src === this.cache_.src && this.cache_.currentTime > 0) { + techOptions.startTime = this.cache_.currentTime; + } + + this.cache_.sources = null; + this.cache_.source = source; + this.cache_.src = source.src; + } + + // Initialize tech instance + var TechComponent = _tech2['default'].getTech(techName); + + // Support old behavior of techs being registered as components. + // Remove once that deprecated behavior is removed. + if (!TechComponent) { + TechComponent = _component2['default'].getComponent(techName); + } + this.tech_ = new TechComponent(techOptions); + + // player.triggerReady is always async, so don't need this to be async + this.tech_.ready(Fn.bind(this, this.handleTechReady_), true); + + _textTrackListConverter2['default'].jsonToTextTracks(this.textTracksJson_ || [], this.tech_); + + // Listen to all HTML5-defined events and trigger them on the player + TECH_EVENTS_RETRIGGER.forEach(function (event) { + _this2.on(_this2.tech_, event, _this2['handleTech' + (0, _toTitleCase2['default'])(event) + '_']); + }); + this.on(this.tech_, 'loadstart', this.handleTechLoadStart_); + this.on(this.tech_, 'waiting', this.handleTechWaiting_); + this.on(this.tech_, 'canplay', this.handleTechCanPlay_); + this.on(this.tech_, 'canplaythrough', this.handleTechCanPlayThrough_); + this.on(this.tech_, 'playing', this.handleTechPlaying_); + this.on(this.tech_, 'ended', this.handleTechEnded_); + this.on(this.tech_, 'seeking', this.handleTechSeeking_); + this.on(this.tech_, 'seeked', this.handleTechSeeked_); + this.on(this.tech_, 'play', this.handleTechPlay_); + this.on(this.tech_, 'firstplay', this.handleTechFirstPlay_); + this.on(this.tech_, 'pause', this.handleTechPause_); + this.on(this.tech_, 'durationchange', this.handleTechDurationChange_); + this.on(this.tech_, 'fullscreenchange', this.handleTechFullscreenChange_); + this.on(this.tech_, 'error', this.handleTechError_); + this.on(this.tech_, 'loadedmetadata', this.updateStyleEl_); + this.on(this.tech_, 'posterchange', this.handleTechPosterChange_); + this.on(this.tech_, 'textdata', this.handleTechTextData_); + + this.usingNativeControls(this.techGet_('controls')); + + if (this.controls() && !this.usingNativeControls()) { + this.addTechControlsListeners_(); + } + + // Add the tech element in the DOM if it was not already there + // Make sure to not insert the original video element if using Html5 + if (this.tech_.el().parentNode !== this.el() && (techName !== 'Html5' || !this.tag)) { + Dom.insertElFirst(this.tech_.el(), this.el()); + } + + // Get rid of the original video tag reference after the first tech is loaded + if (this.tag) { + this.tag.player = null; + this.tag = null; + } + }; + + /** + * Unload and dispose of the current playback {@link Tech}. + * + * @private + */ + + + Player.prototype.unloadTech_ = function unloadTech_() { + // Save the current text tracks so that we can reuse the same text tracks with the next tech + this.videoTracks_ = this.videoTracks(); + this.textTracks_ = this.textTracks(); + this.audioTracks_ = this.audioTracks(); + this.textTracksJson_ = _textTrackListConverter2['default'].textTracksToJson(this.tech_); + + this.isReady_ = false; + + this.tech_.dispose(); + + this.tech_ = false; + }; + + /** + * Return a reference to the current {@link Tech}, but only if given an object with the + * `IWillNotUseThisInPlugins` property having a true value. This is try and prevent misuse + * of techs by plugins. + * + * @param {Object} safety + * An object that must contain `{IWillNotUseThisInPlugins: true}` + * + * @param {boolean} safety.IWillNotUseThisInPlugins + * Must be set to true or else this function will throw an error. + * + * @return {Tech} + * The Tech + */ + + + Player.prototype.tech = function tech(safety) { + if (safety && safety.IWillNotUseThisInPlugins) { + return this.tech_; + } + var errorText = '\n Please make sure that you are not using this inside of a plugin.\n To disable this alert and error, please pass in an object with\n `IWillNotUseThisInPlugins` to the `tech` method. See\n https://github.com/videojs/video.js/issues/2617 for more info.\n '; + + _window2['default'].alert(errorText); + throw new Error(errorText); + }; + + /** + * Set up click and touch listeners for the playback element + * + * - On desktops: a click on the video itself will toggle playback + * - On mobile devices: a click on the video toggles controls + * which is done by toggling the user state between active and + * inactive + * - A tap can signal that a user has become active or has become inactive + * e.g. a quick tap on an iPhone movie should reveal the controls. Another + * quick tap should hide them again (signaling the user is in an inactive + * viewing state) + * - In addition to this, we still want the user to be considered inactive after + * a few seconds of inactivity. + * + * > Note: the only part of iOS interaction we can't mimic with this setup + * is a touch and hold on the video element counting as activity in order to + * keep the controls showing, but that shouldn't be an issue. A touch and hold + * on any controls will still keep the user active + * + * @private + */ + + + Player.prototype.addTechControlsListeners_ = function addTechControlsListeners_() { + // Make sure to remove all the previous listeners in case we are called multiple times. + this.removeTechControlsListeners_(); + + // Some browsers (Chrome & IE) don't trigger a click on a flash swf, but do + // trigger mousedown/up. + // http://stackoverflow.com/questions/1444562/javascript-onclick-event-over-flash-object + // Any touch events are set to block the mousedown event from happening + this.on(this.tech_, 'mousedown', this.handleTechClick_); + + // If the controls were hidden we don't want that to change without a tap event + // so we'll check if the controls were already showing before reporting user + // activity + this.on(this.tech_, 'touchstart', this.handleTechTouchStart_); + this.on(this.tech_, 'touchmove', this.handleTechTouchMove_); + this.on(this.tech_, 'touchend', this.handleTechTouchEnd_); + + // The tap listener needs to come after the touchend listener because the tap + // listener cancels out any reportedUserActivity when setting userActive(false) + this.on(this.tech_, 'tap', this.handleTechTap_); + }; + + /** + * Remove the listeners used for click and tap controls. This is needed for + * toggling to controls disabled, where a tap/touch should do nothing. + * + * @private + */ + + + Player.prototype.removeTechControlsListeners_ = function removeTechControlsListeners_() { + // We don't want to just use `this.off()` because there might be other needed + // listeners added by techs that extend this. + this.off(this.tech_, 'tap', this.handleTechTap_); + this.off(this.tech_, 'touchstart', this.handleTechTouchStart_); + this.off(this.tech_, 'touchmove', this.handleTechTouchMove_); + this.off(this.tech_, 'touchend', this.handleTechTouchEnd_); + this.off(this.tech_, 'mousedown', this.handleTechClick_); + }; + + /** + * Player waits for the tech to be ready + * + * @private + */ + + + Player.prototype.handleTechReady_ = function handleTechReady_() { + this.triggerReady(); + + // Keep the same volume as before + if (this.cache_.volume) { + this.techCall_('setVolume', this.cache_.volume); + } + + // Look if the tech found a higher resolution poster while loading + this.handleTechPosterChange_(); + + // Update the duration if available + this.handleTechDurationChange_(); + + // Chrome and Safari both have issues with autoplay. + // In Safari (5.1.1), when we move the video element into the container div, autoplay doesn't work. + // In Chrome (15), if you have autoplay + a poster + no controls, the video gets hidden (but audio plays) + // This fixes both issues. Need to wait for API, so it updates displays correctly + if ((this.src() || this.currentSrc()) && this.tag && this.options_.autoplay && this.paused()) { + try { + // Chrome Fix. Fixed in Chrome v16. + delete this.tag.poster; + } catch (e) { + (0, _log2['default'])('deleting tag.poster throws in some browsers', e); + } + this.play(); + } + }; + + /** + * Retrigger the `loadstart` event that was triggered by the {@link Tech}. This + * function will also trigger {@link Player#firstplay} if it is the first loadstart + * for a video. + * + * @fires Player#loadstart + * @fires Player#firstplay + * @listens Tech#loadstart + * @private + */ + + + Player.prototype.handleTechLoadStart_ = function handleTechLoadStart_() { + // TODO: Update to use `emptied` event instead. See #1277. + + this.removeClass('vjs-ended'); + this.removeClass('vjs-seeking'); + + // reset the error state + this.error(null); + + // If it's already playing we want to trigger a firstplay event now. + // The firstplay event relies on both the play and loadstart events + // which can happen in any order for a new source + if (!this.paused()) { + /** + * Fired when the user agent begins looking for media data + * + * @event Player#loadstart + * @type {EventTarget~Event} + */ + this.trigger('loadstart'); + this.trigger('firstplay'); + } else { + // reset the hasStarted state + this.hasStarted(false); + this.trigger('loadstart'); + } + }; + + /** + * Add/remove the vjs-has-started class + * + * @fires Player#firstplay + * + * @param {boolean} hasStarted + * - true: adds the class + * - false: remove the class + * + * @return {boolean} + * the boolean value of hasStarted + */ + + + Player.prototype.hasStarted = function hasStarted(_hasStarted) { + if (_hasStarted !== undefined) { + // only update if this is a new value + if (this.hasStarted_ !== _hasStarted) { + this.hasStarted_ = _hasStarted; + if (_hasStarted) { + this.addClass('vjs-has-started'); + // trigger the firstplay event if this newly has played + this.trigger('firstplay'); + } else { + this.removeClass('vjs-has-started'); + } + } + return this; + } + return !!this.hasStarted_; + }; + + /** + * Fired whenever the media begins or resumes playback + * + * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-play} + * @fires Player#play + * @listens Tech#play + * @private + */ + + + Player.prototype.handleTechPlay_ = function handleTechPlay_() { + this.removeClass('vjs-ended'); + this.removeClass('vjs-paused'); + this.addClass('vjs-playing'); + + // hide the poster when the user hits play + this.hasStarted(true); + /** + * Triggered whenever an {@link Tech#play} event happens. Indicates that + * playback has started or resumed. + * + * @event Player#play + * @type {EventTarget~Event} + */ + this.trigger('play'); + }; + + /** + * Retrigger the `waiting` event that was triggered by the {@link Tech}. + * + * @fires Player#waiting + * @listens Tech#waiting + * @private + */ + + + Player.prototype.handleTechWaiting_ = function handleTechWaiting_() { + var _this3 = this; + + this.addClass('vjs-waiting'); + /** + * A readyState change on the DOM element has caused playback to stop. + * + * @event Player#waiting + * @type {EventTarget~Event} + */ + this.trigger('waiting'); + this.one('timeupdate', function () { + return _this3.removeClass('vjs-waiting'); + }); + }; + + /** + * Retrigger the `canplay` event that was triggered by the {@link Tech}. + * > Note: This is not consistent between browsers. See #1351 + * + * @fires Player#canplay + * @listens Tech#canplay + * @private + */ + + + Player.prototype.handleTechCanPlay_ = function handleTechCanPlay_() { + this.removeClass('vjs-waiting'); + /** + * The media has a readyState of HAVE_FUTURE_DATA or greater. + * + * @event Player#canplay + * @type {EventTarget~Event} + */ + this.trigger('canplay'); + }; + + /** + * Retrigger the `canplaythrough` event that was triggered by the {@link Tech}. + * + * @fires Player#canplaythrough + * @listens Tech#canplaythrough + * @private + */ + + + Player.prototype.handleTechCanPlayThrough_ = function handleTechCanPlayThrough_() { + this.removeClass('vjs-waiting'); + /** + * The media has a readyState of HAVE_ENOUGH_DATA or greater. This means that the + * entire media file can be played without buffering. + * + * @event Player#canplaythrough + * @type {EventTarget~Event} + */ + this.trigger('canplaythrough'); + }; + + /** + * Retrigger the `playing` event that was triggered by the {@link Tech}. + * + * @fires Player#playing + * @listens Tech#playing + * @private + */ + + + Player.prototype.handleTechPlaying_ = function handleTechPlaying_() { + this.removeClass('vjs-waiting'); + /** + * The media is no longer blocked from playback, and has started playing. + * + * @event Player#playing + * @type {EventTarget~Event} + */ + this.trigger('playing'); + }; + + /** + * Retrigger the `seeking` event that was triggered by the {@link Tech}. + * + * @fires Player#seeking + * @listens Tech#seeking + * @private + */ + + + Player.prototype.handleTechSeeking_ = function handleTechSeeking_() { + this.addClass('vjs-seeking'); + /** + * Fired whenever the player is jumping to a new time + * + * @event Player#seeking + * @type {EventTarget~Event} + */ + this.trigger('seeking'); + }; + + /** + * Retrigger the `seeked` event that was triggered by the {@link Tech}. + * + * @fires Player#seeked + * @listens Tech#seeked + * @private + */ + + + Player.prototype.handleTechSeeked_ = function handleTechSeeked_() { + this.removeClass('vjs-seeking'); + /** + * Fired when the player has finished jumping to a new time + * + * @event Player#seeked + * @type {EventTarget~Event} + */ + this.trigger('seeked'); + }; + + /** + * Retrigger the `firstplay` event that was triggered by the {@link Tech}. + * + * @fires Player#firstplay + * @listens Tech#firstplay + * @deprecated As of 6.0 passing the `starttime` option to the player will be deprecated + * @private + */ + + + Player.prototype.handleTechFirstPlay_ = function handleTechFirstPlay_() { + // If the first starttime attribute is specified + // then we will start at the given offset in seconds + if (this.options_.starttime) { + _log2['default'].warn('Passing the `starttime` option to the player will be deprecated in 6.0'); + this.currentTime(this.options_.starttime); + } + + this.addClass('vjs-has-started'); + /** + * Fired the first time a video is played. Not part of the HLS spec, and this is + * probably not the best implementation yet, so use sparingly. If you don't have a + * reason to prevent playback, use `myPlayer.one('play');` instead. + * + * @event Player#firstplay + * @type {EventTarget~Event} + */ + this.trigger('firstplay'); + }; + + /** + * Retrigger the `pause` event that was triggered by the {@link Tech}. + * + * @fires Player#pause + * @listens Tech#pause + * @private + */ + + + Player.prototype.handleTechPause_ = function handleTechPause_() { + this.removeClass('vjs-playing'); + this.addClass('vjs-paused'); + /** + * Fired whenever the media has been paused + * + * @event Player#pause + * @type {EventTarget~Event} + */ + this.trigger('pause'); + }; + + /** + * Retrigger the `ended` event that was triggered by the {@link Tech}. + * + * @fires Player#ended + * @listens Tech#ended + * @private + */ + + + Player.prototype.handleTechEnded_ = function handleTechEnded_() { + this.addClass('vjs-ended'); + if (this.options_.loop) { + this.currentTime(0); + this.play(); + } else if (!this.paused()) { + this.pause(); + } + + /** + * Fired when the end of the media resource is reached (currentTime == duration) + * + * @event Player#ended + * @type {EventTarget~Event} + */ + this.trigger('ended'); + }; + + /** + * Fired when the duration of the media resource is first known or changed + * + * @listens Tech#durationchange + * @private + */ + + + Player.prototype.handleTechDurationChange_ = function handleTechDurationChange_() { + this.duration(this.techGet_('duration')); + }; + + /** + * Handle a click on the media element to play/pause + * + * @param {EventTarget~Event} event + * the event that caused this function to trigger + * + * @listens Tech#mousedown + * @private + */ + + + Player.prototype.handleTechClick_ = function handleTechClick_(event) { + // We're using mousedown to detect clicks thanks to Flash, but mousedown + // will also be triggered with right-clicks, so we need to prevent that + if (event.button !== 0) { + return; + } + + // When controls are disabled a click should not toggle playback because + // the click is considered a control + if (this.controls()) { + if (this.paused()) { + this.play(); + } else { + this.pause(); + } + } + }; + + /** + * Handle a tap on the media element. It will toggle the user + * activity state, which hides and shows the controls. + * + * @listens Tech#tap + * @private + */ + + + Player.prototype.handleTechTap_ = function handleTechTap_() { + this.userActive(!this.userActive()); + }; + + /** + * Handle touch to start + * + * @listens Tech#touchstart + * @private + */ + + + Player.prototype.handleTechTouchStart_ = function handleTechTouchStart_() { + this.userWasActive = this.userActive(); + }; + + /** + * Handle touch to move + * + * @listens Tech#touchmove + * @private + */ + + + Player.prototype.handleTechTouchMove_ = function handleTechTouchMove_() { + if (this.userWasActive) { + this.reportUserActivity(); + } + }; + + /** + * Handle touch to end + * + * @param {EventTarget~Event} event + * the touchend event that triggered + * this function + * + * @listens Tech#touchend + * @private + */ + + + Player.prototype.handleTechTouchEnd_ = function handleTechTouchEnd_(event) { + // Stop the mouse events from also happening + event.preventDefault(); + }; + + /** + * Fired when the player switches in or out of fullscreen mode + * + * @private + * @listens Player#fullscreenchange + */ + + + Player.prototype.handleFullscreenChange_ = function handleFullscreenChange_() { + if (this.isFullscreen()) { + this.addClass('vjs-fullscreen'); + } else { + this.removeClass('vjs-fullscreen'); + } + }; + + /** + * native click events on the SWF aren't triggered on IE11, Win8.1RT + * use stageclick events triggered from inside the SWF instead + * + * @private + * @listens stageclick + */ + + + Player.prototype.handleStageClick_ = function handleStageClick_() { + this.reportUserActivity(); + }; + + /** + * Handle Tech Fullscreen Change + * + * @param {EventTarget~Event} event + * the fullscreenchange event that triggered this function + * + * @param {Object} data + * the data that was sent with the event + * + * @private + * @listens Tech#fullscreenchange + * @fires Player#fullscreenchange + */ + + + Player.prototype.handleTechFullscreenChange_ = function handleTechFullscreenChange_(event, data) { + if (data) { + this.isFullscreen(data.isFullscreen); + } + /** + * Fired when going in and out of fullscreen. + * + * @event Player#fullscreenchange + * @type {EventTarget~Event} + */ + this.trigger('fullscreenchange'); + }; + + /** + * Fires when an error occurred during the loading of an audio/video. + * + * @private + * @listens Tech#error + */ + + + Player.prototype.handleTechError_ = function handleTechError_() { + var error = this.tech_.error(); + + this.error(error); + }; + + /** + * Retrigger the `textdata` event that was triggered by the {@link Tech}. + * + * @fires Player#textdata + * @listens Tech#textdata + * @private + */ + + + Player.prototype.handleTechTextData_ = function handleTechTextData_() { + var data = null; + + if (arguments.length > 1) { + data = arguments[1]; + } + + /** + * Fires when we get a textdata event from tech + * + * @event Player#textdata + * @type {EventTarget~Event} + */ + this.trigger('textdata', data); + }; + + /** + * Get object for cached values. + * + * @return {Object} + * get the current object cache + */ + + + Player.prototype.getCache = function getCache() { + return this.cache_; + }; + + /** + * Pass values to the playback tech + * + * @param {string} [method] + * the method to call + * + * @param {Object} arg + * the argument to pass + * + * @private + */ + + + Player.prototype.techCall_ = function techCall_(method, arg) { + // If it's not ready yet, call method when it is + if (this.tech_ && !this.tech_.isReady_) { + this.tech_.ready(function () { + this[method](arg); + }, true); + + // Otherwise call method now + } else { + try { + if (this.tech_) { + this.tech_[method](arg); + } + } catch (e) { + (0, _log2['default'])(e); + throw e; + } + } + }; + + /** + * Get calls can't wait for the tech, and sometimes don't need to. + * + * @param {string} method + * Tech method + * + * @return {Function|undefined} + * the method or undefined + * + * @private + */ + + + Player.prototype.techGet_ = function techGet_(method) { + if (this.tech_ && this.tech_.isReady_) { + + // Flash likes to die and reload when you hide or reposition it. + // In these cases the object methods go away and we get errors. + // When that happens we'll catch the errors and inform tech that it's not ready any more. + try { + return this.tech_[method](); + } catch (e) { + // When building additional tech libs, an expected method may not be defined yet + if (this.tech_[method] === undefined) { + (0, _log2['default'])('Video.js: ' + method + ' method not defined for ' + this.techName_ + ' playback technology.', e); + + // When a method isn't available on the object it throws a TypeError + } else if (e.name === 'TypeError') { + (0, _log2['default'])('Video.js: ' + method + ' unavailable on ' + this.techName_ + ' playback technology element.', e); + this.tech_.isReady_ = false; + } else { + (0, _log2['default'])(e); + } + throw e; + } + } + + return; + }; + + /** + * start media playback + * + * @return {Player} + * A reference to the player object this function was called on + */ + + + Player.prototype.play = function play() { + // Only calls the tech's play if we already have a src loaded + if (this.src() || this.currentSrc()) { + this.techCall_('play'); + } else { + this.tech_.one('loadstart', function () { + this.play(); + }); + } + + return this; + }; + + /** + * Pause the video playback + * + * @return {Player} + * A reference to the player object this function was called on + */ + + + Player.prototype.pause = function pause() { + this.techCall_('pause'); + return this; + }; + + /** + * Check if the player is paused or has yet to play + * + * @return {boolean} + * - false: if the media is currently playing + * - true: if media is not currently playing + */ + + + Player.prototype.paused = function paused() { + // The initial state of paused should be true (in Safari it's actually false) + return this.techGet_('paused') === false ? false : true; + }; + + /** + * Returns whether or not the user is "scrubbing". Scrubbing is + * when the user has clicked the progress bar handle and is + * dragging it along the progress bar. + * + * @param {boolean} [isScrubbing] + * wether the user is or is not scrubbing + * + * @return {boolean|Player} + * A instance of the player that called this function when setting, + * and the value of scrubbing when getting + */ + + + Player.prototype.scrubbing = function scrubbing(isScrubbing) { + if (isScrubbing !== undefined) { + this.scrubbing_ = !!isScrubbing; + + if (isScrubbing) { + this.addClass('vjs-scrubbing'); + } else { + this.removeClass('vjs-scrubbing'); + } + + return this; + } + + return this.scrubbing_; + }; + + /** + * Get or set the current time (in seconds) + * + * @param {number|string} [seconds] + * The time to seek to in seconds + * + * @return {Player|number} + * - the current time in seconds when getting + * - a reference to the current player object when setting + */ + + + Player.prototype.currentTime = function currentTime(seconds) { + if (seconds !== undefined) { + + this.techCall_('setCurrentTime', seconds); + + return this; + } + + // cache last currentTime and return. default to 0 seconds + // + // Caching the currentTime is meant to prevent a massive amount of reads on the tech's + // currentTime when scrubbing, but may not provide much performance benefit afterall. + // Should be tested. Also something has to read the actual current time or the cache will + // never get updated. + this.cache_.currentTime = this.techGet_('currentTime') || 0; + return this.cache_.currentTime; + }; + + /** + * Normally gets the length in time of the video in seconds; + * in all but the rarest use cases an argument will NOT be passed to the method + * + * > **NOTE**: The video must have started loading before the duration can be + * known, and in the case of Flash, may not be known until the video starts + * playing. + * + * @fires Player#durationchange + * + * @param {number} [seconds] + * The duration of the video to set in seconds + * + * @return {number|Player} + * - The duration of the video in seconds when getting + * - A reference to the player that called this function + * when setting + */ + + + Player.prototype.duration = function duration(seconds) { + if (seconds === undefined) { + // return NaN if the duration is not known + return this.cache_.duration !== undefined ? this.cache_.duration : NaN; + } + + seconds = parseFloat(seconds); + + // Standardize on Inifity for signaling video is live + if (seconds < 0) { + seconds = Infinity; + } + + if (seconds !== this.cache_.duration) { + // Cache the last set value for optimized scrubbing (esp. Flash) + this.cache_.duration = seconds; + + if (seconds === Infinity) { + this.addClass('vjs-live'); + } else { + this.removeClass('vjs-live'); + } + /** + * @event Player#durationchange + * @type {EventTarget~Event} + */ + this.trigger('durationchange'); + } + + return this; + }; + + /** + * Calculates how much time is left in the video. Not part + * of the native video API. + * + * @return {number} + * The time remaining in seconds + */ + + + Player.prototype.remainingTime = function remainingTime() { + return this.duration() - this.currentTime(); + }; + + // + // Kind of like an array of portions of the video that have been downloaded. + + /** + * Get a TimeRange object with an array of the times of the video + * that have been downloaded. If you just want the percent of the + * video that's been downloaded, use bufferedPercent. + * + * @see [Buffered Spec]{@link http://dev.w3.org/html5/spec/video.html#dom-media-buffered} + * + * @return {TimeRange} + * A mock TimeRange object (following HTML spec) + */ + + + Player.prototype.buffered = function buffered() { + var buffered = this.techGet_('buffered'); + + if (!buffered || !buffered.length) { + buffered = (0, _timeRanges.createTimeRange)(0, 0); + } + + return buffered; + }; + + /** + * Get the percent (as a decimal) of the video that's been downloaded. + * This method is not a part of the native HTML video API. + * + * @return {number} + * A decimal between 0 and 1 representing the percent + * that is bufferred 0 being 0% and 1 being 100% + */ + + + Player.prototype.bufferedPercent = function bufferedPercent() { + return (0, _buffer.bufferedPercent)(this.buffered(), this.duration()); + }; + + /** + * Get the ending time of the last buffered time range + * This is used in the progress bar to encapsulate all time ranges. + * + * @return {number} + * The end of the last buffered time range + */ + + + Player.prototype.bufferedEnd = function bufferedEnd() { + var buffered = this.buffered(); + var duration = this.duration(); + var end = buffered.end(buffered.length - 1); + + if (end > duration) { + end = duration; + } + + return end; + }; + + /** + * Get or set the current volume of the media + * + * @param {number} [percentAsDecimal] + * The new volume as a decimal percent: + * - 0 is muted/0%/off + * - 1.0 is 100%/full + * - 0.5 is half volume or 50% + * + * @return {Player|number} + * a reference to the calling player when setting and the + * current volume as a percent when getting + */ + + + Player.prototype.volume = function volume(percentAsDecimal) { + var vol = void 0; + + if (percentAsDecimal !== undefined) { + // Force value to between 0 and 1 + vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); + this.cache_.volume = vol; + this.techCall_('setVolume', vol); + + return this; + } + + // Default to 1 when returning current volume. + vol = parseFloat(this.techGet_('volume')); + return isNaN(vol) ? 1 : vol; + }; + + /** + * Get the current muted state, or turn mute on or off + * + * @param {boolean} [muted] + * - true to mute + * - false to unmute + * + * @return {boolean|Player} + * - true if mute is on and getting + * - false if mute is off and getting + * - A reference to the current player when setting + */ + + + Player.prototype.muted = function muted(_muted) { + if (_muted !== undefined) { + this.techCall_('setMuted', _muted); + return this; + } + return this.techGet_('muted') || false; + }; + + /** + * Check if current tech can support native fullscreen + * (e.g. with built in controls like iOS, so not our flash swf) + * + * @return {boolean} + * if native fullscreen is supported + */ + + + Player.prototype.supportsFullScreen = function supportsFullScreen() { + return this.techGet_('supportsFullScreen') || false; + }; + + /** + * Check if the player is in fullscreen mode or tell the player that it + * is or is not in fullscreen mode. + * + * > NOTE: As of the latest HTML5 spec, isFullscreen is no longer an official + * property and instead document.fullscreenElement is used. But isFullscreen is + * still a valuable property for internal player workings. + * + * @param {boolean} [isFS] + * Set the players current fullscreen state + * + * @return {boolean|Player} + * - true if fullscreen is on and getting + * - false if fullscreen is off and getting + * - A reference to the current player when setting + */ + + + Player.prototype.isFullscreen = function isFullscreen(isFS) { + if (isFS !== undefined) { + this.isFullscreen_ = !!isFS; + return this; + } + return !!this.isFullscreen_; + }; + + /** + * Increase the size of the video to full screen + * In some browsers, full screen is not supported natively, so it enters + * "full window mode", where the video fills the browser window. + * In browsers and devices that support native full screen, sometimes the + * browser's default controls will be shown, and not the Video.js custom skin. + * This includes most mobile devices (iOS, Android) and older versions of + * Safari. + * + * @fires Player#fullscreenchange + * @return {Player} + * A reference to the current player + */ + + + Player.prototype.requestFullscreen = function requestFullscreen() { + var fsApi = _fullscreenApi2['default']; + + this.isFullscreen(true); + + if (fsApi.requestFullscreen) { + // the browser supports going fullscreen at the element level so we can + // take the controls fullscreen as well as the video + + // Trigger fullscreenchange event after change + // We have to specifically add this each time, and remove + // when canceling fullscreen. Otherwise if there's multiple + // players on a page, they would all be reacting to the same fullscreen + // events + Events.on(_document2['default'], fsApi.fullscreenchange, Fn.bind(this, function documentFullscreenChange(e) { + this.isFullscreen(_document2['default'][fsApi.fullscreenElement]); + + // If cancelling fullscreen, remove event listener. + if (this.isFullscreen() === false) { + Events.off(_document2['default'], fsApi.fullscreenchange, documentFullscreenChange); + } + /** + * @event Player#fullscreenchange + * @type {EventTarget~Event} + */ + this.trigger('fullscreenchange'); + })); + + this.el_[fsApi.requestFullscreen](); + } else if (this.tech_.supportsFullScreen()) { + // we can't take the video.js controls fullscreen but we can go fullscreen + // with native controls + this.techCall_('enterFullScreen'); + } else { + // fullscreen isn't supported so we'll just stretch the video element to + // fill the viewport + this.enterFullWindow(); + /** + * @event Player#fullscreenchange + * @type {EventTarget~Event} + */ + this.trigger('fullscreenchange'); + } + + return this; + }; + + /** + * Return the video to its normal size after having been in full screen mode + * + * @fires Player#fullscreenchange + * + * @return {Player} + * A reference to the current player + */ + + + Player.prototype.exitFullscreen = function exitFullscreen() { + var fsApi = _fullscreenApi2['default']; + + this.isFullscreen(false); + + // Check for browser element fullscreen support + if (fsApi.requestFullscreen) { + _document2['default'][fsApi.exitFullscreen](); + } else if (this.tech_.supportsFullScreen()) { + this.techCall_('exitFullScreen'); + } else { + this.exitFullWindow(); + /** + * @event Player#fullscreenchange + * @type {EventTarget~Event} + */ + this.trigger('fullscreenchange'); + } + + return this; + }; + + /** + * When fullscreen isn't supported we can stretch the + * video container to as wide as the browser will let us. + * + * @fires Player#enterFullWindow + */ + + + Player.prototype.enterFullWindow = function enterFullWindow() { + this.isFullWindow = true; + + // Storing original doc overflow value to return to when fullscreen is off + this.docOrigOverflow = _document2['default'].documentElement.style.overflow; + + // Add listener for esc key to exit fullscreen + Events.on(_document2['default'], 'keydown', Fn.bind(this, this.fullWindowOnEscKey)); + + // Hide any scroll bars + _document2['default'].documentElement.style.overflow = 'hidden'; + + // Apply fullscreen styles + Dom.addElClass(_document2['default'].body, 'vjs-full-window'); + + /** + * @event Player#enterFullWindow + * @type {EventTarget~Event} + */ + this.trigger('enterFullWindow'); + }; + + /** + * Check for call to either exit full window or + * full screen on ESC key + * + * @param {string} event + * Event to check for key press + */ + + + Player.prototype.fullWindowOnEscKey = function fullWindowOnEscKey(event) { + if (event.keyCode === 27) { + if (this.isFullscreen() === true) { + this.exitFullscreen(); + } else { + this.exitFullWindow(); + } + } + }; + + /** + * Exit full window + * + * @fires Player#exitFullWindow + */ + + + Player.prototype.exitFullWindow = function exitFullWindow() { + this.isFullWindow = false; + Events.off(_document2['default'], 'keydown', this.fullWindowOnEscKey); + + // Unhide scroll bars. + _document2['default'].documentElement.style.overflow = this.docOrigOverflow; + + // Remove fullscreen styles + Dom.removeElClass(_document2['default'].body, 'vjs-full-window'); + + // Resize the box, controller, and poster to original sizes + // this.positionAll(); + /** + * @event Player#exitFullWindow + * @type {EventTarget~Event} + */ + this.trigger('exitFullWindow'); + }; + + /** + * Check whether the player can play a given mimetype + * + * @see https://www.w3.org/TR/2011/WD-html5-20110113/video.html#dom-navigator-canplaytype + * + * @param {string} type + * The mimetype to check + * + * @return {string} + * 'probably', 'maybe', or '' (empty string) + */ + + + Player.prototype.canPlayType = function canPlayType(type) { + var can = void 0; + + // Loop through each playback technology in the options order + for (var i = 0, j = this.options_.techOrder; i < j.length; i++) { + var techName = (0, _toTitleCase2['default'])(j[i]); + var tech = _tech2['default'].getTech(techName); + + // Support old behavior of techs being registered as components. + // Remove once that deprecated behavior is removed. + if (!tech) { + tech = _component2['default'].getComponent(techName); + } + + // Check if the current tech is defined before continuing + if (!tech) { + _log2['default'].error('The "' + techName + '" tech is undefined. Skipped browser support check for that tech.'); + continue; + } + + // Check if the browser supports this technology + if (tech.isSupported()) { + can = tech.canPlayType(type); + + if (can) { + return can; + } + } + } + + return ''; + }; + + /** + * Select source based on tech-order or source-order + * Uses source-order selection if `options.sourceOrder` is truthy. Otherwise, + * defaults to tech-order selection + * + * @param {Array} sources + * The sources for a media asset + * + * @return {Object|boolean} + * Object of source and tech order or false + */ + + + Player.prototype.selectSource = function selectSource(sources) { + var _this4 = this; + + // Get only the techs specified in `techOrder` that exist and are supported by the + // current platform + var techs = this.options_.techOrder.map(_toTitleCase2['default']).map(function (techName) { + // `Component.getComponent(...)` is for support of old behavior of techs + // being registered as components. + // Remove once that deprecated behavior is removed. + return [techName, _tech2['default'].getTech(techName) || _component2['default'].getComponent(techName)]; + }).filter(function (_ref) { + var techName = _ref[0], + tech = _ref[1]; + + // Check if the current tech is defined before continuing + if (tech) { + // Check if the browser supports this technology + return tech.isSupported(); + } + + _log2['default'].error('The "' + techName + '" tech is undefined. Skipped browser support check for that tech.'); + return false; + }); + + // Iterate over each `innerArray` element once per `outerArray` element and execute + // `tester` with both. If `tester` returns a non-falsy value, exit early and return + // that value. + var findFirstPassingTechSourcePair = function findFirstPassingTechSourcePair(outerArray, innerArray, tester) { + var found = void 0; + + outerArray.some(function (outerChoice) { + return innerArray.some(function (innerChoice) { + found = tester(outerChoice, innerChoice); + + if (found) { + return true; + } + }); + }); + + return found; + }; + + var foundSourceAndTech = void 0; + var flip = function flip(fn) { + return function (a, b) { + return fn(b, a); + }; + }; + var finder = function finder(_ref2, source) { + var techName = _ref2[0], + tech = _ref2[1]; + + if (tech.canPlaySource(source, _this4.options_[techName.toLowerCase()])) { + return { source: source, tech: techName }; + } + }; + + // Depending on the truthiness of `options.sourceOrder`, we swap the order of techs and sources + // to select from them based on their priority. + if (this.options_.sourceOrder) { + // Source-first ordering + foundSourceAndTech = findFirstPassingTechSourcePair(sources, techs, flip(finder)); + } else { + // Tech-first ordering + foundSourceAndTech = findFirstPassingTechSourcePair(techs, sources, finder); + } + + return foundSourceAndTech || false; + }; + + /** + * The source function updates the video source + * There are three types of variables you can pass as the argument. + * **URL string**: A URL to the the video file. Use this method if you are sure + * the current playback technology (HTML5/Flash) can support the source you + * provide. Currently only MP4 files can be used in both HTML5 and Flash. + * + * @param {Tech~SourceObject|Tech~SourceObject[]} [source] + * One SourceObject or an array of SourceObjects + * + * @return {string|Player} + * - The current video source when getting + * - The player when setting + */ + + + Player.prototype.src = function src(source) { + if (source === undefined) { + return this.techGet_('src'); + } + + var currentTech = _tech2['default'].getTech(this.techName_); + + // Support old behavior of techs being registered as components. + // Remove once that deprecated behavior is removed. + if (!currentTech) { + currentTech = _component2['default'].getComponent(this.techName_); + } + + // case: Array of source objects to choose from and pick the best to play + if (Array.isArray(source)) { + this.sourceList_(source); + + // case: URL String (http://myvideo...) + } else if (typeof source === 'string') { + // create a source object from the string + this.src({ src: source }); + + // case: Source object { src: '', type: '' ... } + } else if (source instanceof Object) { + // check if the source has a type and the loaded tech cannot play the source + // if there's no type we'll just try the current tech + if (source.type && !currentTech.canPlaySource(source, this.options_[this.techName_.toLowerCase()])) { + // create a source list with the current source and send through + // the tech loop to check for a compatible technology + this.sourceList_([source]); + } else { + this.cache_.sources = null; + this.cache_.source = source; + this.cache_.src = source.src; + + this.currentType_ = source.type || ''; + + // wait until the tech is ready to set the source + this.ready(function () { + + // The setSource tech method was added with source handlers + // so older techs won't support it + // We need to check the direct prototype for the case where subclasses + // of the tech do not support source handlers + if (currentTech.prototype.hasOwnProperty('setSource')) { + this.techCall_('setSource', source); + } else { + this.techCall_('src', source.src); + } + + if (this.options_.preload === 'auto') { + this.load(); + } + + if (this.options_.autoplay) { + this.play(); + } + + // Set the source synchronously if possible (#2326) + }, true); + } + } + + return this; + }; + + /** + * Handle an array of source objects + * + * @param {Tech~SourceObject[]} sources + * Array of source objects + * + * @private + */ + + + Player.prototype.sourceList_ = function sourceList_(sources) { + var sourceTech = this.selectSource(sources); + + if (sourceTech) { + if (sourceTech.tech === this.techName_) { + // if this technology is already loaded, set the source + this.src(sourceTech.source); + } else { + // load this technology with the chosen source + this.loadTech_(sourceTech.tech, sourceTech.source); + } + + this.cache_.sources = sources; + } else { + // We need to wrap this in a timeout to give folks a chance to add error event handlers + this.setTimeout(function () { + this.error({ code: 4, message: this.localize(this.options_.notSupportedMessage) }); + }, 0); + + // we could not find an appropriate tech, but let's still notify the delegate that this is it + // this needs a better comment about why this is needed + this.triggerReady(); + } + }; + + /** + * Begin loading the src data. + * + * @return {Player} + * A reference to the player + */ + + + Player.prototype.load = function load() { + this.techCall_('load'); + return this; + }; + + /** + * Reset the player. Loads the first tech in the techOrder, + * and calls `reset` on the tech`. + * + * @return {Player} + * A reference to the player + */ + + + Player.prototype.reset = function reset() { + this.loadTech_((0, _toTitleCase2['default'])(this.options_.techOrder[0]), null); + this.techCall_('reset'); + return this; + }; + + /** + * Returns all of the current source objects. + * + * @return {Tech~SourceObject[]} + * The current source objects + */ + + + Player.prototype.currentSources = function currentSources() { + var source = this.currentSource(); + var sources = []; + + // assume `{}` or `{ src }` + if (Object.keys(source).length !== 0) { + sources.push(source); + } + + return this.cache_.sources || sources; + }; + + /** + * Returns the current source object. + * + * @return {Tech~SourceObject} + * The current source object + */ + + + Player.prototype.currentSource = function currentSource() { + var source = {}; + var src = this.currentSrc(); + + if (src) { + source.src = src; + } + + return this.cache_.source || source; + }; + + /** + * Returns the fully qualified URL of the current source value e.g. http://mysite.com/video.mp4 + * Can be used in conjuction with `currentType` to assist in rebuilding the current source object. + * + * @return {string} + * The current source + */ + + + Player.prototype.currentSrc = function currentSrc() { + return this.techGet_('currentSrc') || this.cache_.src || ''; + }; + + /** + * Get the current source type e.g. video/mp4 + * This can allow you rebuild the current source object so that you could load the same + * source and tech later + * + * @return {string} + * The source MIME type + */ + + + Player.prototype.currentType = function currentType() { + return this.currentType_ || ''; + }; + + /** + * Get or set the preload attribute + * + * @param {boolean} [value] + * - true means that we should preload + * - false maens that we should not preload + * + * @return {string|Player} + * - the preload attribute value when getting + * - the player when setting + */ + + + Player.prototype.preload = function preload(value) { + if (value !== undefined) { + this.techCall_('setPreload', value); + this.options_.preload = value; + return this; + } + return this.techGet_('preload'); + }; + + /** + * Get or set the autoplay attribute. + * + * @param {boolean} [value] + * - true means that we should autoplay + * - false maens that we should not autoplay + * + * @return {string|Player} + * - the current value of autoplay + * - the player when setting + */ + + + Player.prototype.autoplay = function autoplay(value) { + if (value !== undefined) { + this.techCall_('setAutoplay', value); + this.options_.autoplay = value; + return this; + } + return this.techGet_('autoplay', value); + }; + + /** + * Set or unset the playsinline attribute. + * Playsinline tells the browser that non-fullscreen playback is preferred. + * + * @param {boolean} [value] + * - true means that we should try to play inline by default + * - false means that we should use the browser's default playback mode, + * which in most cases is inline. iOS Safari is a notable exception + * and plays fullscreen by default. + * + * @return {string|Player} + * - the current value of playsinline + * - the player when setting + * + * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline} + */ + + + Player.prototype.playsinline = function playsinline(value) { + if (value !== undefined) { + this.techCall_('setPlaysinline', value); + this.options_.playsinline = value; + return this; + } + return this.techGet_('playsinline'); + }; + + /** + * Get or set the loop attribute on the video element. + * + * @param {boolean} [value] + * - true means that we should loop the video + * - false means that we should not loop the video + * + * @return {string|Player} + * - the current value of loop when getting + * - the player when setting + */ + + + Player.prototype.loop = function loop(value) { + if (value !== undefined) { + this.techCall_('setLoop', value); + this.options_.loop = value; + return this; + } + return this.techGet_('loop'); + }; + + /** + * Get or set the poster image source url + * + * @fires Player#posterchange + * + * @param {string} [src] + * Poster image source URL + * + * @return {string|Player} + * - the current value of poster when getting + * - the player when setting + */ + + + Player.prototype.poster = function poster(src) { + if (src === undefined) { + return this.poster_; + } + + // The correct way to remove a poster is to set as an empty string + // other falsey values will throw errors + if (!src) { + src = ''; + } + + // update the internal poster variable + this.poster_ = src; + + // update the tech's poster + this.techCall_('setPoster', src); + + // alert components that the poster has been set + /** + * This event fires when the poster image is changed on the player. + * + * @event Player#posterchange + * @type {EventTarget~Event} + */ + this.trigger('posterchange'); + + return this; + }; + + /** + * Some techs (e.g. YouTube) can provide a poster source in an + * asynchronous way. We want the poster component to use this + * poster source so that it covers up the tech's controls. + * (YouTube's play button). However we only want to use this + * soruce if the player user hasn't set a poster through + * the normal APIs. + * + * @fires Player#posterchange + * @listens Tech#posterchange + * @private + */ + + + Player.prototype.handleTechPosterChange_ = function handleTechPosterChange_() { + if (!this.poster_ && this.tech_ && this.tech_.poster) { + this.poster_ = this.tech_.poster() || ''; + + // Let components know the poster has changed + this.trigger('posterchange'); + } + }; + + /** + * Get or set whether or not the controls are showing. + * + * @fires Player#controlsenabled + * + * @param {boolean} [bool] + * - true to turn controls on + * - false to turn controls off + * + * @return {boolean|Player} + * - the current value of controls when getting + * - the player when setting + */ + + + Player.prototype.controls = function controls(bool) { + if (bool !== undefined) { + bool = !!bool; + + // Don't trigger a change event unless it actually changed + if (this.controls_ !== bool) { + this.controls_ = bool; + + if (this.usingNativeControls()) { + this.techCall_('setControls', bool); + } + + if (bool) { + this.removeClass('vjs-controls-disabled'); + this.addClass('vjs-controls-enabled'); + /** + * @event Player#controlsenabled + * @type {EventTarget~Event} + */ + this.trigger('controlsenabled'); + + if (!this.usingNativeControls()) { + this.addTechControlsListeners_(); + } + } else { + this.removeClass('vjs-controls-enabled'); + this.addClass('vjs-controls-disabled'); + /** + * @event Player#controlsdisabled + * @type {EventTarget~Event} + */ + this.trigger('controlsdisabled'); + + if (!this.usingNativeControls()) { + this.removeTechControlsListeners_(); + } + } + } + return this; + } + return !!this.controls_; + }; + + /** + * Toggle native controls on/off. Native controls are the controls built into + * devices (e.g. default iPhone controls), Flash, or other techs + * (e.g. Vimeo Controls) + * **This should only be set by the current tech, because only the tech knows + * if it can support native controls** + * + * @fires Player#usingnativecontrols + * @fires Player#usingcustomcontrols + * + * @param {boolean} [bool] + * - true to turn native controls on + * - false to turn native controls off + * + * @return {boolean|Player} + * - the current value of native controls when getting + * - the player when setting + */ + + + Player.prototype.usingNativeControls = function usingNativeControls(bool) { + if (bool !== undefined) { + bool = !!bool; + + // Don't trigger a change event unless it actually changed + if (this.usingNativeControls_ !== bool) { + this.usingNativeControls_ = bool; + if (bool) { + this.addClass('vjs-using-native-controls'); + + /** + * player is using the native device controls + * + * @event Player#usingnativecontrols + * @type {EventTarget~Event} + */ + this.trigger('usingnativecontrols'); + } else { + this.removeClass('vjs-using-native-controls'); + + /** + * player is using the custom HTML controls + * + * @event Player#usingcustomcontrols + * @type {EventTarget~Event} + */ + this.trigger('usingcustomcontrols'); + } + } + return this; + } + return !!this.usingNativeControls_; + }; + + /** + * Set or get the current MediaError + * + * @fires Player#error + * + * @param {MediaError|string|number} [err] + * A MediaError or a string/number to be turned + * into a MediaError + * + * @return {MediaError|null|Player} + * - The current MediaError when getting (or null) + * - The player when setting + */ + + + Player.prototype.error = function error(err) { + if (err === undefined) { + return this.error_ || null; + } + + // restoring to default + if (err === null) { + this.error_ = err; + this.removeClass('vjs-error'); + if (this.errorDisplay) { + this.errorDisplay.close(); + } + return this; + } + + this.error_ = new _mediaError2['default'](err); + + // add the vjs-error classname to the player + this.addClass('vjs-error'); + + // log the name of the error type and any message + // ie8 just logs "[object object]" if you just log the error object + _log2['default'].error('(CODE:' + this.error_.code + ' ' + _mediaError2['default'].errorTypes[this.error_.code] + ')', this.error_.message, this.error_); + + /** + * @event Player#error + * @type {EventTarget~Event} + */ + this.trigger('error'); + + return this; + }; + + /** + * Report user activity + * + * @param {Object} event + * Event object + */ + + + Player.prototype.reportUserActivity = function reportUserActivity(event) { + this.userActivity_ = true; + }; + + /** + * Get/set if user is active + * + * @fires Player#useractive + * @fires Player#userinactive + * + * @param {boolean} [bool] + * - true if the user is active + * - false if the user is inactive + * @return {boolean|Player} + * - the current value of userActive when getting + * - the player when setting + */ + + + Player.prototype.userActive = function userActive(bool) { + if (bool !== undefined) { + bool = !!bool; + if (bool !== this.userActive_) { + this.userActive_ = bool; + if (bool) { + // If the user was inactive and is now active we want to reset the + // inactivity timer + this.userActivity_ = true; + this.removeClass('vjs-user-inactive'); + this.addClass('vjs-user-active'); + /** + * @event Player#useractive + * @type {EventTarget~Event} + */ + this.trigger('useractive'); + } else { + // We're switching the state to inactive manually, so erase any other + // activity + this.userActivity_ = false; + + // Chrome/Safari/IE have bugs where when you change the cursor it can + // trigger a mousemove event. This causes an issue when you're hiding + // the cursor when the user is inactive, and a mousemove signals user + // activity. Making it impossible to go into inactive mode. Specifically + // this happens in fullscreen when we really need to hide the cursor. + // + // When this gets resolved in ALL browsers it can be removed + // https://code.google.com/p/chromium/issues/detail?id=103041 + if (this.tech_) { + this.tech_.one('mousemove', function (e) { + e.stopPropagation(); + e.preventDefault(); + }); + } + + this.removeClass('vjs-user-active'); + this.addClass('vjs-user-inactive'); + /** + * @event Player#userinactive + * @type {EventTarget~Event} + */ + this.trigger('userinactive'); + } + } + return this; + } + return this.userActive_; + }; + + /** + * Listen for user activity based on timeout value + * + * @private + */ + + + Player.prototype.listenForUserActivity_ = function listenForUserActivity_() { + var mouseInProgress = void 0; + var lastMoveX = void 0; + var lastMoveY = void 0; + var handleActivity = Fn.bind(this, this.reportUserActivity); + + var handleMouseMove = function handleMouseMove(e) { + // #1068 - Prevent mousemove spamming + // Chrome Bug: https://code.google.com/p/chromium/issues/detail?id=366970 + if (e.screenX !== lastMoveX || e.screenY !== lastMoveY) { + lastMoveX = e.screenX; + lastMoveY = e.screenY; + handleActivity(); + } + }; + + var handleMouseDown = function handleMouseDown() { + handleActivity(); + // For as long as the they are touching the device or have their mouse down, + // we consider them active even if they're not moving their finger or mouse. + // So we want to continue to update that they are active + this.clearInterval(mouseInProgress); + // Setting userActivity=true now and setting the interval to the same time + // as the activityCheck interval (250) should ensure we never miss the + // next activityCheck + mouseInProgress = this.setInterval(handleActivity, 250); + }; + + var handleMouseUp = function handleMouseUp(event) { + handleActivity(); + // Stop the interval that maintains activity if the mouse/touch is down + this.clearInterval(mouseInProgress); + }; + + // Any mouse movement will be considered user activity + this.on('mousedown', handleMouseDown); + this.on('mousemove', handleMouseMove); + this.on('mouseup', handleMouseUp); + + // Listen for keyboard navigation + // Shouldn't need to use inProgress interval because of key repeat + this.on('keydown', handleActivity); + this.on('keyup', handleActivity); + + // Run an interval every 250 milliseconds instead of stuffing everything into + // the mousemove/touchmove function itself, to prevent performance degradation. + // `this.reportUserActivity` simply sets this.userActivity_ to true, which + // then gets picked up by this loop + // http://ejohn.org/blog/learning-from-twitter/ + var inactivityTimeout = void 0; + + this.setInterval(function () { + // Check to see if mouse/touch activity has happened + if (this.userActivity_) { + // Reset the activity tracker + this.userActivity_ = false; + + // If the user state was inactive, set the state to active + this.userActive(true); + + // Clear any existing inactivity timeout to start the timer over + this.clearTimeout(inactivityTimeout); + + var timeout = this.options_.inactivityTimeout; + + if (timeout > 0) { + // In milliseconds, if no more activity has occurred the + // user will be considered inactive + inactivityTimeout = this.setTimeout(function () { + // Protect against the case where the inactivityTimeout can trigger just + // before the next user activity is picked up by the activity check loop + // causing a flicker + if (!this.userActivity_) { + this.userActive(false); + } + }, timeout); + } + } + }, 250); + }; + + /** + * Gets or sets the current playback rate. A playback rate of + * 1.0 represents normal speed and 0.5 would indicate half-speed + * playback, for instance. + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-playbackrate + * + * @param {number} [rate] + * New playback rate to set. + * + * @return {number|Player} + * - The current playback rate when getting or 1.0 + * - the player when setting + */ + + + Player.prototype.playbackRate = function playbackRate(rate) { + if (rate !== undefined) { + this.techCall_('setPlaybackRate', rate); + return this; + } + + if (this.tech_ && this.tech_.featuresPlaybackRate) { + return this.techGet_('playbackRate'); + } + return 1.0; + }; + + /** + * Gets or sets the audio flag + * + * @param {boolean} bool + * - true signals that this is an audio player + * - false signals that this is not an audio player + * + * @return {Player|boolean} + * - the current value of isAudio when getting + * - the player if setting + */ + + + Player.prototype.isAudio = function isAudio(bool) { + if (bool !== undefined) { + this.isAudio_ = !!bool; + return this; + } + + return !!this.isAudio_; + }; + + /** + * Get the {@link VideoTrackList} + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist + * + * @return {VideoTrackList} + * the current video track list + */ + + + Player.prototype.videoTracks = function videoTracks() { + // if we have not yet loadTech_, we create videoTracks_ + // these will be passed to the tech during loading + if (!this.tech_) { + this.videoTracks_ = this.videoTracks_ || new _videoTrackList2['default'](); + return this.videoTracks_; + } + + return this.tech_.videoTracks(); + }; + + /** + * Get the {@link AudioTrackList} + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist + * + * @return {AudioTrackList} + * the current audio track list + */ + + + Player.prototype.audioTracks = function audioTracks() { + // if we have not yet loadTech_, we create videoTracks_ + // these will be passed to the tech during loading + if (!this.tech_) { + this.audioTracks_ = this.audioTracks_ || new _audioTrackList2['default'](); + return this.audioTracks_; + } + + return this.tech_.audioTracks(); + }; + + /** + * Get the {@link TextTrackList} + * + * Text tracks are tracks of timed text events. + * - Captions: text displayed over the video + * for the hearing impaired + * - Subtitles: text displayed over the video for + * those who don't understand language in the video + * - Chapters: text displayed in a menu allowing the user to jump + * to particular points (chapters) in the video + * - Descriptions: (not yet implemented) audio descriptions that are read back to + * the user by a screen reading device + * + * @see http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-texttracks + * + * @return {TextTrackList|undefined} + * The current TextTrackList or undefined if + * or undefined if we don't have a tech + */ + + + Player.prototype.textTracks = function textTracks() { + // cannot use techGet_ directly because it checks to see whether the tech is ready. + // Flash is unlikely to be ready in time but textTracks should still work. + if (this.tech_) { + return this.tech_.textTracks(); + } + }; + + /** + * Get the "remote" {@link TextTrackList}. Remote Text Tracks + * are tracks that were added to the HTML video element and can + * be removed, whereas normal texttracks cannot be removed. + * + * + * @return {TextTrackList|undefined} + * The current remote text track list or undefined + * if we don't have a tech + */ + + + Player.prototype.remoteTextTracks = function remoteTextTracks() { + if (this.tech_) { + return this.tech_.remoteTextTracks(); + } + }; + + /** + * Get the "remote" {@link HTMLTrackElementList}. + * This gives the user all of the DOM elements that match up + * with the remote {@link TextTrackList}. + * + * @return {HTMLTrackElementList} + * The current remote text track list elements + * or undefined if we don't have a tech + */ + + + Player.prototype.remoteTextTrackEls = function remoteTextTrackEls() { + if (this.tech_) { + return this.tech_.remoteTextTrackEls(); + } + }; + + /** + * A helper method for adding a {@link TextTrack} to our + * {@link TextTrackList}. + * + * In addition to the W3C settings we allow adding additional info through options. + * + * @see http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-addtexttrack + * + * @param {string} [kind] + * the kind of TextTrack you are adding + * + * @param {string} [label] + * the label to give the TextTrack label + * + * @param {string} [language] + * the language to set on the TextTrack + * + * @return {TextTrack|undefined} + * the TextTrack that was added or undefined + * if there is no tech + */ + + + Player.prototype.addTextTrack = function addTextTrack(kind, label, language) { + if (this.tech_) { + return this.tech_.addTextTrack(kind, label, language); + } + }; + + /** + * Create a remote {@link TextTrack} and an {@link HTMLTrackElement}. It will + * automatically removed from the video element whenever the source changes, unless + * manualCleanup is set to false. + * + * @param {Object} options + * Options to pass to {@link HTMLTrackElement} during creation. See + * {@link HTMLTrackElement} for object properties that you should use. + * + * @param {boolean} [manualCleanup=true] if set to false, the TextTrack will be + * + * @return {HTMLTrackElement} + * the HTMLTrackElement that was created and added + * to the HTMLTrackElementList and the remote + * TextTrackList + * + * @deprecated The default value of the "manualCleanup" parameter will default + * to "false" in upcoming versions of Video.js + */ + + + Player.prototype.addRemoteTextTrack = function addRemoteTextTrack(options, manualCleanup) { + if (this.tech_) { + return this.tech_.addRemoteTextTrack(options, manualCleanup); + } + }; + + /** + * Remove a remote {@link TextTrack} from the respective + * {@link TextTrackList} and {@link HTMLTrackElementList}. + * + * @param {Object} track + * Remote {@link TextTrack} to remove + * + * @return {undefined} + * does not return anything + */ + + + Player.prototype.removeRemoteTextTrack = function removeRemoteTextTrack() { + var _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + _ref3$track = _ref3.track, + track = _ref3$track === undefined ? arguments[0] : _ref3$track; + + // destructure the input into an object with a track argument, defaulting to arguments[0] + // default the whole argument to an empty object if nothing was passed in + + if (this.tech_) { + return this.tech_.removeRemoteTextTrack(track); + } + }; + + /** + * Gets available media playback quality metrics as specified by the W3C's Media + * Playback Quality API. + * + * @see [Spec]{@link https://wicg.github.io/media-playback-quality} + * + * @return {Object|undefined} + * An object with supported media playback quality metrics or undefined if there + * is no tech or the tech does not support it. + */ + + + Player.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() { + return this.techGet_('getVideoPlaybackQuality'); + }; + + /** + * Get video width + * + * @return {number} + * current video width + */ + + + Player.prototype.videoWidth = function videoWidth() { + return this.tech_ && this.tech_.videoWidth && this.tech_.videoWidth() || 0; + }; + + /** + * Get video height + * + * @return {number} + * current video height + */ + + + Player.prototype.videoHeight = function videoHeight() { + return this.tech_ && this.tech_.videoHeight && this.tech_.videoHeight() || 0; + }; + + // Methods to add support for + // initialTime: function() { return this.techCall_('initialTime'); }, + // startOffsetTime: function() { return this.techCall_('startOffsetTime'); }, + // played: function() { return this.techCall_('played'); }, + // defaultPlaybackRate: function() { return this.techCall_('defaultPlaybackRate'); }, + // defaultMuted: function() { return this.techCall_('defaultMuted'); } + + /** + * The player's language code + * NOTE: The language should be set in the player options if you want the + * the controls to be built with a specific language. Changing the lanugage + * later will not update controls text. + * + * @param {string} [code] + * the language code to set the player to + * + * @return {string|Player} + * - The current language code when getting + * - A reference to the player when setting + */ + + + Player.prototype.language = function language(code) { + if (code === undefined) { + return this.language_; + } + + this.language_ = String(code).toLowerCase(); + return this; + }; + + /** + * Get the player's language dictionary + * Merge every time, because a newly added plugin might call videojs.addLanguage() at any time + * Languages specified directly in the player options have precedence + * + * @return {Array} + * An array of of supported languages + */ + + + Player.prototype.languages = function languages() { + return (0, _mergeOptions2['default'])(Player.prototype.options_.languages, this.languages_); + }; + + /** + * returns a JavaScript object reperesenting the current track + * information. **DOES not return it as JSON** + * + * @return {Object} + * Object representing the current of track info + */ + + + Player.prototype.toJSON = function toJSON() { + var options = (0, _mergeOptions2['default'])(this.options_); + var tracks = options.tracks; + + options.tracks = []; + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + // deep merge tracks and null out player so no circular references + track = (0, _mergeOptions2['default'])(track); + track.player = undefined; + options.tracks[i] = track; + } + + return options; + }; + + /** + * Creates a simple modal dialog (an instance of the {@link ModalDialog} + * component) that immediately overlays the player with arbitrary + * content and removes itself when closed. + * + * @param {string|Function|Element|Array|null} content + * Same as {@link ModalDialog#content}'s param of the same name. + * The most straight-forward usage is to provide a string or DOM + * element. + * + * @param {Object} [options] + * Extra options which will be passed on to the {@link ModalDialog}. + * + * @return {ModalDialog} + * the {@link ModalDialog} that was created + */ + + + Player.prototype.createModal = function createModal(content, options) { + var _this5 = this; + + options = options || {}; + options.content = content || ''; + + var modal = new _modalDialog2['default'](this, options); + + this.addChild(modal); + modal.on('dispose', function () { + _this5.removeChild(modal); + }); + + return modal.open(); + }; + + /** + * Gets tag settings + * + * @param {Element} tag + * The player tag + * + * @return {Object} + * An object containing all of the settings + * for a player tag + */ + + + Player.getTagSettings = function getTagSettings(tag) { + var baseOptions = { + sources: [], + tracks: [] + }; + + var tagOptions = Dom.getElAttributes(tag); + var dataSetup = tagOptions['data-setup']; + + if (Dom.hasElClass(tag, 'vjs-fluid')) { + tagOptions.fluid = true; + } + + // Check if data-setup attr exists. + if (dataSetup !== null) { + // Parse options JSON + // If empty string, make it a parsable json object. + var _safeParseTuple = (0, _tuple2['default'])(dataSetup || '{}'), + err = _safeParseTuple[0], + data = _safeParseTuple[1]; + + if (err) { + _log2['default'].error(err); + } + (0, _obj.assign)(tagOptions, data); + } + + (0, _obj.assign)(baseOptions, tagOptions); + + // Get tag children settings + if (tag.hasChildNodes()) { + var children = tag.childNodes; + + for (var i = 0, j = children.length; i < j; i++) { + var child = children[i]; + // Change case needed: http://ejohn.org/blog/nodename-case-sensitivity/ + var childName = child.nodeName.toLowerCase(); + + if (childName === 'source') { + baseOptions.sources.push(Dom.getElAttributes(child)); + } else if (childName === 'track') { + baseOptions.tracks.push(Dom.getElAttributes(child)); + } + } + } + + return baseOptions; + }; + + /** + * Determine wether or not flexbox is supported + * + * @return {boolean} + * - true if flexbox is supported + * - false if flexbox is not supported + */ + + + Player.prototype.flexNotSupported_ = function flexNotSupported_() { + var elem = _document2['default'].createElement('i'); + + // Note: We don't actually use flexBasis (or flexOrder), but it's one of the more + // common flex features that we can rely on when checking for flex support. + return !('flexBasis' in elem.style || 'webkitFlexBasis' in elem.style || 'mozFlexBasis' in elem.style || 'msFlexBasis' in elem.style || + // IE10-specific (2012 flex spec) + 'msFlexOrder' in elem.style); + }; + + return Player; +}(_component2['default']); + +/** + * Global player list + * + * @type {Object} + */ + + +Player.players = {}; + +var navigator = _window2['default'].navigator; + +/* + * Player instance options, surfaced using options + * options = Player.prototype.options_ + * Make changes in options, not here. + * + * @type {Object} + * @private + */ +Player.prototype.options_ = { + // Default order of fallback technology + techOrder: ['html5', 'flash'], + // techOrder: ['flash','html5'], + + html5: {}, + flash: {}, + + // defaultVolume: 0.85, + defaultVolume: 0.00, + + // default inactivity timeout + inactivityTimeout: 2000, + + // default playback rates + playbackRates: [], + // Add playback rate selection by adding rates + // 'playbackRates': [0.5, 1, 1.5, 2], + + // Included control sets + children: ['mediaLoader', 'posterImage', 'textTrackDisplay', 'loadingSpinner', 'bigPlayButton', 'controlBar', 'errorDisplay', 'textTrackSettings'], + + language: navigator && (navigator.languages && navigator.languages[0] || navigator.userLanguage || navigator.language) || 'en', + + // locales and their language translations + languages: {}, + + // Default message to show when a video cannot be played. + notSupportedMessage: 'No compatible source was found for this media.' +}; + +[ +/** + * Returns whether or not the player is in the "ended" state. + * + * @return {Boolean} True if the player is in the ended state, false if not. + * @method Player#ended + */ +'ended', +/** + * Returns whether or not the player is in the "seeking" state. + * + * @return {Boolean} True if the player is in the seeking state, false if not. + * @method Player#seeking + */ +'seeking', +/** + * Returns the TimeRanges of the media that are currently available + * for seeking to. + * + * @return {TimeRanges} the seekable intervals of the media timeline + * @method Player#seekable + */ +'seekable', +/** + * Returns the current state of network activity for the element, from + * the codes in the list below. + * - NETWORK_EMPTY (numeric value 0) + * The element has not yet been initialised. All attributes are in + * their initial states. + * - NETWORK_IDLE (numeric value 1) + * The element's resource selection algorithm is active and has + * selected a resource, but it is not actually using the network at + * this time. + * - NETWORK_LOADING (numeric value 2) + * The user agent is actively trying to download data. + * - NETWORK_NO_SOURCE (numeric value 3) + * The element's resource selection algorithm is active, but it has + * not yet found a resource to use. + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#network-states + * @return {number} the current network activity state + * @method Player#networkState + */ +'networkState', +/** + * Returns a value that expresses the current state of the element + * with respect to rendering the current playback position, from the + * codes in the list below. + * - HAVE_NOTHING (numeric value 0) + * No information regarding the media resource is available. + * - HAVE_METADATA (numeric value 1) + * Enough of the resource has been obtained that the duration of the + * resource is available. + * - HAVE_CURRENT_DATA (numeric value 2) + * Data for the immediate current playback position is available. + * - HAVE_FUTURE_DATA (numeric value 3) + * Data for the immediate current playback position is available, as + * well as enough data for the user agent to advance the current + * playback position in the direction of playback. + * - HAVE_ENOUGH_DATA (numeric value 4) + * The user agent estimates that enough data is available for + * playback to proceed uninterrupted. + * + * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-readystate + * @return {number} the current playback rendering state + * @method Player#readyState + */ +'readyState'].forEach(function (fn) { + Player.prototype[fn] = function () { + return this.techGet_(fn); + }; +}); + +TECH_EVENTS_RETRIGGER.forEach(function (event) { + Player.prototype['handleTech' + (0, _toTitleCase2['default'])(event) + '_'] = function () { + return this.trigger(event); + }; +}); + +/** + * Fired when the player has initial duration and dimension information + * + * @event Player#loadedmetadata + * @type {EventTarget~Event} + */ + +/** + * Fired when the player has downloaded data at the current playback position + * + * @event Player#loadeddata + * @type {EventTarget~Event} + */ + +/** + * Fired when the current playback position has changed * + * During playback this is fired every 15-250 milliseconds, depending on the + * playback technology in use. + * + * @event Player#timeupdate + * @type {EventTarget~Event} + */ + +/** + * Fired when the volume changes + * + * @event Player#volumechange + * @type {EventTarget~Event} + */ + +_component2['default'].registerComponent('Player', Player); +exports['default'] = Player; + +},{"1":1,"4":4,"41":41,"44":44,"45":45,"46":46,"5":5,"50":50,"55":55,"59":59,"60":60,"61":61,"62":62,"63":63,"68":68,"69":69,"71":71,"76":76,"78":78,"79":79,"8":8,"81":81,"82":82,"83":83,"85":85,"86":86,"87":87,"88":88,"89":89,"90":90,"91":91,"94":94,"95":95,"97":97}],52:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _player = _dereq_(51); + +var _player2 = _interopRequireDefault(_player); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +/** + * The method for registering a video.js plugin. {@link videojs:videojs.registerPlugin]. + * + * @param {string} name + * The name of the plugin that is being registered + * + * @param {plugins:PluginFn} init + * The function that gets run when a `Player` initializes. + */ +var plugin = function plugin(name, init) { + _player2['default'].prototype[name] = init; +}; /** + * @file plugins.js + * @module plugins + */ +exports['default'] = plugin; + +},{"51":51}],53:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _clickableComponent = _dereq_(3); + +var _clickableComponent2 = _interopRequireDefault(_clickableComponent); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file popup-button.js + */ + + +/** + * A button class for use with {@link Popup} controls + * + * @extends ClickableComponent + */ +var PopupButton = function (_ClickableComponent) { + _inherits(PopupButton, _ClickableComponent); + + /** + * Create an instance of this class. + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function PopupButton(player) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, PopupButton); + + var _this = _possibleConstructorReturn(this, _ClickableComponent.call(this, player, options)); + + _this.update(); + return _this; + } + + /** + * Update the `Popup` that this button is attached to. + */ + + + PopupButton.prototype.update = function update() { + var popup = this.createPopup(); + + if (this.popup) { + this.removeChild(this.popup); + } + + this.popup = popup; + this.addChild(popup); + + if (this.items && this.items.length === 0) { + this.hide(); + } else if (this.items && this.items.length > 1) { + this.show(); + } + }; + + /** + * Create a `Popup`. - Override with specific functionality for component + * + * @abstract + */ + + + PopupButton.prototype.createPopup = function createPopup() {}; + + /** + * Create the `PopupButton`s DOM element. + * + * @return {Element} + * The element that gets created. + */ + + + PopupButton.prototype.createEl = function createEl() { + return _ClickableComponent.prototype.createEl.call(this, 'div', { + className: this.buildCSSClass() + }); + }; + + /** + * Builds the default DOM `className`. + * + * @return {string} + * The DOM `className` for this object. + */ + + + PopupButton.prototype.buildCSSClass = function buildCSSClass() { + var menuButtonClass = 'vjs-menu-button'; + + // If the inline option is passed, we want to use different styles altogether. + if (this.options_.inline === true) { + menuButtonClass += '-inline'; + } else { + menuButtonClass += '-popup'; + } + + return 'vjs-menu-button ' + menuButtonClass + ' ' + _ClickableComponent.prototype.buildCSSClass.call(this); + }; + + return PopupButton; +}(_clickableComponent2['default']); + +_component2['default'].registerComponent('PopupButton', PopupButton); +exports['default'] = PopupButton; + +},{"3":3,"5":5}],54:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _events = _dereq_(82); + +var Events = _interopRequireWildcard(_events); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file popup.js + */ + + +/** + * The Popup component is used to build pop up controls. + * + * @extends Component + */ +var Popup = function (_Component) { + _inherits(Popup, _Component); + + function Popup() { + _classCallCheck(this, Popup); + + return _possibleConstructorReturn(this, _Component.apply(this, arguments)); + } + + /** + * Add a popup item to the popup + * + * @param {Object|string} component + * Component or component type to add + * + */ + Popup.prototype.addItem = function addItem(component) { + this.addChild(component); + component.on('click', Fn.bind(this, function () { + this.unlockShowing(); + })); + }; + + /** + * Create the `PopupButton`s DOM element. + * + * @return {Element} + * The element that gets created. + */ + + + Popup.prototype.createEl = function createEl() { + var contentElType = this.options_.contentElType || 'ul'; + + this.contentEl_ = Dom.createEl(contentElType, { + className: 'vjs-menu-content' + }); + + var el = _Component.prototype.createEl.call(this, 'div', { + append: this.contentEl_, + className: 'vjs-menu' + }); + + el.appendChild(this.contentEl_); + + // Prevent clicks from bubbling up. Needed for Popup Buttons, + // where a click on the parent is significant + Events.on(el, 'click', function (event) { + event.preventDefault(); + event.stopImmediatePropagation(); + }); + + return el; + }; + + return Popup; +}(_component2['default']); + +_component2['default'].registerComponent('Popup', Popup); +exports['default'] = Popup; + +},{"5":5,"81":81,"82":82,"83":83}],55:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _clickableComponent = _dereq_(3); + +var _clickableComponent2 = _interopRequireDefault(_clickableComponent); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _browser = _dereq_(78); + +var browser = _interopRequireWildcard(_browser); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file poster-image.js + */ + + +/** + * A `ClickableComponent` that handles showing the poster image for the player. + * + * @extends ClickableComponent + */ +var PosterImage = function (_ClickableComponent) { + _inherits(PosterImage, _ClickableComponent); + + /** + * Create an instance of this class. + * + * @param {Player} player + * The `Player` that this class should attach to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function PosterImage(player, options) { + _classCallCheck(this, PosterImage); + + var _this = _possibleConstructorReturn(this, _ClickableComponent.call(this, player, options)); + + _this.update(); + player.on('posterchange', Fn.bind(_this, _this.update)); + return _this; + } + + /** + * Clean up and dispose of the `PosterImage`. + */ + + + PosterImage.prototype.dispose = function dispose() { + this.player().off('posterchange', this.update); + _ClickableComponent.prototype.dispose.call(this); + }; + + /** + * Create the `PosterImage`s DOM element. + * + * @return {Element} + * The element that gets created. + */ + + + PosterImage.prototype.createEl = function createEl() { + var el = Dom.createEl('div', { + className: 'vjs-poster', + + // Don't want poster to be tabbable. + tabIndex: -1 + }); + + // To ensure the poster image resizes while maintaining its original aspect + // ratio, use a div with `background-size` when available. For browsers that + // do not support `background-size` (e.g. IE8), fall back on using a regular + // img element. + if (!browser.BACKGROUND_SIZE_SUPPORTED) { + this.fallbackImg_ = Dom.createEl('img'); + el.appendChild(this.fallbackImg_); + } + + return el; + }; + + /** + * An {@link EventTarget~EventListener} for {@link Player#posterchange} events. + * + * @listens Player#posterchange + * + * @param {EventTarget~Event} [event] + * The `Player#posterchange` event that triggered this function. + */ + + + PosterImage.prototype.update = function update(event) { + var url = this.player().poster(); + + this.setSrc(url); + + // If there's no poster source we should display:none on this component + // so it's not still clickable or right-clickable + if (url) { + this.show(); + } else { + this.hide(); + } + }; + + /** + * Set the source of the `PosterImage` depending on the display method. + * + * @param {string} url + * The URL to the source for the `PosterImage`. + */ + + + PosterImage.prototype.setSrc = function setSrc(url) { + if (this.fallbackImg_) { + this.fallbackImg_.src = url; + } else { + var backgroundImage = ''; + + // Any falsey values should stay as an empty string, otherwise + // this will throw an extra error + if (url) { + backgroundImage = 'url("' + url + '")'; + } + + this.el_.style.backgroundImage = backgroundImage; + } + }; + + /** + * An {@link EventTarget~EventListener} for clicks on the `PosterImage`. See + * {@link ClickableComponent#handleClick} for instances where this will be triggered. + * + * @listens tap + * @listens click + * @listens keydown + * + * @param {EventTarget~Event} event + + The `click`, `tap` or `keydown` event that caused this function to be called. + */ + + + PosterImage.prototype.handleClick = function handleClick(event) { + // We don't want a click to trigger playback when controls are disabled + if (!this.player_.controls()) { + return; + } + + if (this.player_.paused()) { + this.player_.play(); + } else { + this.player_.pause(); + } + }; + + return PosterImage; +}(_clickableComponent2['default']); + +_component2['default'].registerComponent('PosterImage', PosterImage); +exports['default'] = PosterImage; + +},{"3":3,"5":5,"78":78,"81":81,"83":83}],56:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; +exports.hasLoaded = exports.autoSetupTimeout = exports.autoSetup = undefined; + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _events = _dereq_(82); + +var Events = _interopRequireWildcard(_events); + +var _document = _dereq_(94); + +var _document2 = _interopRequireDefault(_document); + +var _window = _dereq_(95); + +var _window2 = _interopRequireDefault(_window); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +/** + * @file setup.js - Functions for setting up a player without + * user interaction based on the data-setup `attribute` of the video tag. + * + * @module setup + */ +var _windowLoaded = false; +var videojs = void 0; + +/** + * Set up any tags that have a data-setup `attribute` when the player is started. + */ +var autoSetup = function autoSetup() { + + // Protect against breakage in non-browser environments. + if (!Dom.isReal()) { + return; + } + + // One day, when we stop supporting IE8, go back to this, but in the meantime...*hack hack hack* + // var vids = Array.prototype.slice.call(document.getElementsByTagName('video')); + // var audios = Array.prototype.slice.call(document.getElementsByTagName('audio')); + // var mediaEls = vids.concat(audios); + + // Because IE8 doesn't support calling slice on a node list, we need to loop + // through each list of elements to build up a new, combined list of elements. + var vids = _document2['default'].getElementsByTagName('video'); + var audios = _document2['default'].getElementsByTagName('audio'); + var mediaEls = []; + + if (vids && vids.length > 0) { + for (var i = 0, e = vids.length; i < e; i++) { + mediaEls.push(vids[i]); + } + } + + if (audios && audios.length > 0) { + for (var _i = 0, _e = audios.length; _i < _e; _i++) { + mediaEls.push(audios[_i]); + } + } + + // Check if any media elements exist + if (mediaEls && mediaEls.length > 0) { + + for (var _i2 = 0, _e2 = mediaEls.length; _i2 < _e2; _i2++) { + var mediaEl = mediaEls[_i2]; + + // Check if element exists, has getAttribute func. + // IE seems to consider typeof el.getAttribute == 'object' instead of + // 'function' like expected, at least when loading the player immediately. + if (mediaEl && mediaEl.getAttribute) { + + // Make sure this player hasn't already been set up. + if (mediaEl.player === undefined) { + var options = mediaEl.getAttribute('data-setup'); + + // Check if data-setup attr exists. + // We only auto-setup if they've added the data-setup attr. + if (options !== null) { + // Create new video.js instance. + videojs(mediaEl); + } + } + + // If getAttribute isn't defined, we need to wait for the DOM. + } else { + autoSetupTimeout(1); + break; + } + } + + // No videos were found, so keep looping unless page is finished loading. + } else if (!_windowLoaded) { + autoSetupTimeout(1); + } +}; + +/** + * Wait until the page is loaded before running autoSetup. This will be called in + * autoSetup if `hasLoaded` returns false. + * + * @param {number} wait + * How long to wait in ms + * + * @param {videojs} [vjs] + * The videojs library function + */ +function autoSetupTimeout(wait, vjs) { + if (vjs) { + videojs = vjs; + } + + _window2['default'].setTimeout(autoSetup, wait); +} + +if (Dom.isReal() && _document2['default'].readyState === 'complete') { + _windowLoaded = true; +} else { + /** + * Listen for the load event on window, and set _windowLoaded to true. + * + * @listens load + */ + Events.one(_window2['default'], 'load', function () { + _windowLoaded = true; + }); +} + +/** + * check if the document has been loaded + */ +var hasLoaded = function hasLoaded() { + return _windowLoaded; +}; + +exports.autoSetup = autoSetup; +exports.autoSetupTimeout = autoSetupTimeout; +exports.hasLoaded = hasLoaded; + +},{"81":81,"82":82,"94":94,"95":95}],57:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _obj = _dereq_(88); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file slider.js + */ + + +/** + * The base functionality for a slider. Can be vertical or horizontal. + * For instance the volume bar or the seek bar on a video is a slider. + * + * @extends Component + */ +var Slider = function (_Component) { + _inherits(Slider, _Component); + + /** + * Create an instance of this class + * + * @param {Player} player + * The `Player` that this class should be attached to. + * + * @param {Object} [options] + * The key/value store of player options. + */ + function Slider(player, options) { + _classCallCheck(this, Slider); + + // Set property names to bar to match with the child Slider class is looking for + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options)); + + _this.bar = _this.getChild(_this.options_.barName); + + // Set a horizontal or vertical class on the slider depending on the slider type + _this.vertical(!!_this.options_.vertical); + + _this.on('mousedown', _this.handleMouseDown); + _this.on('touchstart', _this.handleMouseDown); + _this.on('focus', _this.handleFocus); + _this.on('blur', _this.handleBlur); + _this.on('click', _this.handleClick); + + _this.on(player, 'controlsvisible', _this.update); + _this.on(player, _this.playerEvent, _this.update); + return _this; + } + + /** + * Create the `Button`s DOM element. + * + * @param {string} type + * Type of element to create. + * + * @param {Object} [props={}] + * List of properties in Object form. + * + * @param {Object} [attributes={}] + * list of attributes in Object form. + * + * @return {Element} + * The element that gets created. + */ + + + Slider.prototype.createEl = function createEl(type) { + var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + // Add the slider element class to all sub classes + props.className = props.className + ' vjs-slider'; + props = (0, _obj.assign)({ + tabIndex: 0 + }, props); + + attributes = (0, _obj.assign)({ + 'role': 'slider', + 'aria-valuenow': 0, + 'aria-valuemin': 0, + 'aria-valuemax': 100, + 'tabIndex': 0 + }, attributes); + + return _Component.prototype.createEl.call(this, type, props, attributes); + }; + + /** + * Handle `mousedown` or `touchstart` events on the `Slider`. + * + * @param {EventTarget~Event} event + * `mousedown` or `touchstart` event that triggered this function + * + * @listens mousedown + * @listens touchstart + * @fires Slider#slideractive + */ + + + Slider.prototype.handleMouseDown = function handleMouseDown(event) { + var doc = this.bar.el_.ownerDocument; + + event.preventDefault(); + Dom.blockTextSelection(); + + this.addClass('vjs-sliding'); + /** + * Triggered when the slider is in an active state + * + * @event Slider#slideractive + * @type {EventTarget~Event} + */ + this.trigger('slideractive'); + + this.on(doc, 'mousemove', this.handleMouseMove); + this.on(doc, 'mouseup', this.handleMouseUp); + this.on(doc, 'touchmove', this.handleMouseMove); + this.on(doc, 'touchend', this.handleMouseUp); + + this.handleMouseMove(event); + }; + + /** + * Handle the `mousemove`, `touchmove`, and `mousedown` events on this `Slider`. + * The `mousemove` and `touchmove` events will only only trigger this function during + * `mousedown` and `touchstart`. This is due to {@link Slider#handleMouseDown} and + * {@link Slider#handleMouseUp}. + * + * @param {EventTarget~Event} event + * `mousedown`, `mousemove`, `touchstart`, or `touchmove` event that triggered + * this function + * + * @listens mousemove + * @listens touchmove + */ + + + Slider.prototype.handleMouseMove = function handleMouseMove(event) {}; + + /** + * Handle `mouseup` or `touchend` events on the `Slider`. + * + * @param {EventTarget~Event} event + * `mouseup` or `touchend` event that triggered this function. + * + * @listens touchend + * @listens mouseup + * @fires Slider#sliderinactive + */ + + + Slider.prototype.handleMouseUp = function handleMouseUp() { + var doc = this.bar.el_.ownerDocument; + + Dom.unblockTextSelection(); + + this.removeClass('vjs-sliding'); + /** + * Triggered when the slider is no longer in an active state. + * + * @event Slider#sliderinactive + * @type {EventTarget~Event} + */ + this.trigger('sliderinactive'); + + this.off(doc, 'mousemove', this.handleMouseMove); + this.off(doc, 'mouseup', this.handleMouseUp); + this.off(doc, 'touchmove', this.handleMouseMove); + this.off(doc, 'touchend', this.handleMouseUp); + + this.update(); + }; + + /** + * Update the progress bar of the `Slider`. + */ + + + Slider.prototype.update = function update() { + // In VolumeBar init we have a setTimeout for update that pops and update to the end of the + // execution stack. The player is destroyed before then update will cause an error + if (!this.el_) { + return; + } + + // If scrubbing, we could use a cached value to make the handle keep up with the user's mouse. + // On HTML5 browsers scrubbing is really smooth, but some flash players are slow, so we might want to utilize this later. + // var progress = (this.player_.scrubbing()) ? this.player_.getCache().currentTime / this.player_.duration() : this.player_.currentTime() / this.player_.duration(); + var progress = this.getPercent(); + var bar = this.bar; + + // If there's no bar... + if (!bar) { + return; + } + + // Protect against no duration and other division issues + if (typeof progress !== 'number' || progress !== progress || progress < 0 || progress === Infinity) { + progress = 0; + } + + // Convert to a percentage for setting + var percentage = (progress * 100).toFixed(2) + '%'; + + // Set the new bar width or height + if (this.vertical()) { + bar.el().style.height = percentage; + } else { + bar.el().style.width = percentage; + } + }; + + /** + * Calculate distance for slider + * + * @param {EventTarget~Event} event + * The event that caused this function to run. + * + * @return {number} + * The current position of the Slider. + * - postition.x for vertical `Slider`s + * - postition.y for horizontal `Slider`s + */ + + + Slider.prototype.calculateDistance = function calculateDistance(event) { + var position = Dom.getPointerPosition(this.el_, event); + + if (this.vertical()) { + return position.y; + } + return position.x; + }; + + /** + * Handle a `focus` event on this `Slider`. + * + * @param {EventTarget~Event} event + * The `focus` event that caused this function to run. + * + * @listens focus + */ + + + Slider.prototype.handleFocus = function handleFocus() { + this.on(this.bar.el_.ownerDocument, 'keydown', this.handleKeyPress); + }; + + /** + * Handle a `keydown` event on the `Slider`. Watches for left, rigth, up, and down + * arrow keys. This function will only be called when the slider has focus. See + * {@link Slider#handleFocus} and {@link Slider#handleBlur}. + * + * @param {EventTarget~Event} event + * the `keydown` event that caused this function to run. + * + * @listens keydown + */ + + + Slider.prototype.handleKeyPress = function handleKeyPress(event) { + // Left and Down Arrows + if (event.which === 37 || event.which === 40) { + event.preventDefault(); + this.stepBack(); + + // Up and Right Arrows + } else if (event.which === 38 || event.which === 39) { + event.preventDefault(); + this.stepForward(); + } + }; + + /** + * Handle a `blur` event on this `Slider`. + * + * @param {EventTarget~Event} event + * The `blur` event that caused this function to run. + * + * @listens blur + */ + + Slider.prototype.handleBlur = function handleBlur() { + this.off(this.bar.el_.ownerDocument, 'keydown', this.handleKeyPress); + }; + + /** + * Listener for click events on slider, used to prevent clicks + * from bubbling up to parent elements like button menus. + * + * @param {Object} event + * Event that caused this object to run + */ + + + Slider.prototype.handleClick = function handleClick(event) { + event.stopImmediatePropagation(); + event.preventDefault(); + }; + + /** + * Get/set if slider is horizontal for vertical + * + * @param {boolean} [bool] + * - true if slider is vertical, + * - false is horizontal + * + * @return {boolean|Slider} + * - true if slider is vertical, and getting + * - false is horizontal, and getting + * - a reference to this object when setting + */ + + + Slider.prototype.vertical = function vertical(bool) { + if (bool === undefined) { + return this.vertical_ || false; + } + + this.vertical_ = !!bool; + + if (this.vertical_) { + this.addClass('vjs-slider-vertical'); + } else { + this.addClass('vjs-slider-horizontal'); + } + + return this; + }; + + return Slider; +}(_component2['default']); + +_component2['default'].registerComponent('Slider', Slider); +exports['default'] = Slider; + +},{"5":5,"81":81,"88":88}],58:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; +/** + * @file flash-rtmp.js + * @module flash-rtmp + */ + +/** + * Add RTMP properties to the {@link Flash} Tech. + * + * @param {Flash} Flash + * The flash tech class. + * + * @mixin FlashRtmpDecorator + */ +function FlashRtmpDecorator(Flash) { + Flash.streamingFormats = { + 'rtmp/mp4': 'MP4', + 'rtmp/flv': 'FLV' + }; + + /** + * Join connection and stream with an ampersand. + * + * @param {string} connection + * The connection string. + * + * @param {string} stream + * The stream string. + */ + Flash.streamFromParts = function (connection, stream) { + return connection + '&' + stream; + }; + + /** + * The flash parts object that contains connection and stream info. + * + * @typedef {Object} Flash~PartsObject + * + * @property {string} connection + * The connection string of a source, defaults to an empty string. + * + * @property {string} stream + * The stream string of the source, defaults to an empty string. + */ + + /** + * Convert a source url into a stream and connection parts. + * + * @param {string} src + * the source url + * + * @return {Flash~PartsObject} + * The parts object that contains a connection and a stream + */ + Flash.streamToParts = function (src) { + var parts = { + connection: '', + stream: '' + }; + + if (!src) { + return parts; + } + + // Look for the normal URL separator we expect, '&'. + // If found, we split the URL into two pieces around the + // first '&'. + var connEnd = src.search(/&(?!\w+=)/); + var streamBegin = void 0; + + if (connEnd !== -1) { + streamBegin = connEnd + 1; + } else { + // If there's not a '&', we use the last '/' as the delimiter. + connEnd = streamBegin = src.lastIndexOf('/') + 1; + if (connEnd === 0) { + // really, there's not a '/'? + connEnd = streamBegin = src.length; + } + } + + parts.connection = src.substring(0, connEnd); + parts.stream = src.substring(streamBegin, src.length); + + return parts; + }; + + /** + * Check if the source type is a streaming type. + * + * @param {string} srcType + * The mime type to check. + * + * @return {boolean} + * - True if the source type is a streaming type. + * - False if the source type is not a streaming type. + */ + Flash.isStreamingType = function (srcType) { + return srcType in Flash.streamingFormats; + }; + + // RTMP has four variations, any string starting + // with one of these protocols should be valid + + /** + * Regular expression used to check if the source is an rtmp source. + * + * @property {RegExp} Flash.RTMP_RE + */ + Flash.RTMP_RE = /^rtmp[set]?:\/\//i; + + /** + * Check if the source itself is a streaming type. + * + * @param {string} src + * The url to the source. + * + * @return {boolean} + * - True if the source url indicates that the source is streaming. + * - False if the shource url indicates that the source url is not streaming. + */ + Flash.isStreamingSrc = function (src) { + return Flash.RTMP_RE.test(src); + }; + + /** + * A source handler for RTMP urls + * @type {Object} + */ + Flash.rtmpSourceHandler = {}; + + /** + * Check if Flash can play the given mime type. + * + * @param {string} type + * The mime type to check + * + * @return {string} + * 'maybe', or '' (empty string) + */ + Flash.rtmpSourceHandler.canPlayType = function (type) { + if (Flash.isStreamingType(type)) { + return 'maybe'; + } + + return ''; + }; + + /** + * Check if Flash can handle the source natively + * + * @param {Object} source + * The source object + * + * @param {Object} [options] + * The options passed to the tech + * + * @return {string} + * 'maybe', or '' (empty string) + */ + Flash.rtmpSourceHandler.canHandleSource = function (source, options) { + var can = Flash.rtmpSourceHandler.canPlayType(source.type); + + if (can) { + return can; + } + + if (Flash.isStreamingSrc(source.src)) { + return 'maybe'; + } + + return ''; + }; + + /** + * Pass the source to the flash object. + * + * @param {Object} source + * The source object + * + * @param {Flash} tech + * The instance of the Flash tech + * + * @param {Object} [options] + * The options to pass to the source + */ + Flash.rtmpSourceHandler.handleSource = function (source, tech, options) { + var srcParts = Flash.streamToParts(source.src); + + tech.setRtmpConnection(srcParts.connection); + tech.setRtmpStream(srcParts.stream); + }; + + // Register the native source handler + Flash.registerSourceHandler(Flash.rtmpSourceHandler); + + return Flash; +} + +exports['default'] = FlashRtmpDecorator; + +},{}],59:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _tech = _dereq_(62); + +var _tech2 = _interopRequireDefault(_tech); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _url = _dereq_(92); + +var Url = _interopRequireWildcard(_url); + +var _timeRanges = _dereq_(90); + +var _flashRtmp = _dereq_(58); + +var _flashRtmp2 = _interopRequireDefault(_flashRtmp); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _window = _dereq_(95); + +var _window2 = _interopRequireDefault(_window); + +var _obj = _dereq_(88); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file flash.js + * VideoJS-SWF - Custom Flash Player with HTML5-ish API + * https://github.com/zencoder/video-js-swf + * Not using setupTriggers. Using global onEvent func to distribute events + */ + +var navigator = _window2['default'].navigator; + +/** + * Flash Media Controller - Wrapper for Flash Media API + * + * @mixes FlashRtmpDecorator + * @mixes Tech~SouceHandlerAdditions + * @extends Tech + */ + +var Flash = function (_Tech) { + _inherits(Flash, _Tech); + + /** + * Create an instance of this Tech. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} ready + * Callback function to call when the `Flash` Tech is ready. + */ + function Flash(options, ready) { + _classCallCheck(this, Flash); + + // Set the source when ready + var _this = _possibleConstructorReturn(this, _Tech.call(this, options, ready)); + + if (options.source) { + _this.ready(function () { + this.setSource(options.source); + }, true); + } + + // Having issues with Flash reloading on certain page actions (hide/resize/fullscreen) in certain browsers + // This allows resetting the playhead when we catch the reload + if (options.startTime) { + _this.ready(function () { + this.load(); + this.play(); + this.currentTime(options.startTime); + }, true); + } + + // Add global window functions that the swf expects + // A 4.x workflow we weren't able to solve for in 5.0 + // because of the need to hard code these functions + // into the swf for security reasons + _window2['default'].videojs = _window2['default'].videojs || {}; + _window2['default'].videojs.Flash = _window2['default'].videojs.Flash || {}; + _window2['default'].videojs.Flash.onReady = Flash.onReady; + _window2['default'].videojs.Flash.onEvent = Flash.onEvent; + _window2['default'].videojs.Flash.onError = Flash.onError; + + _this.on('seeked', function () { + this.lastSeekTarget_ = undefined; + }); + + return _this; + } + + /** + * Create the `Flash` Tech's DOM element. + * + * @return {Element} + * The element that gets created. + */ + + + Flash.prototype.createEl = function createEl() { + var options = this.options_; + + // If video.js is hosted locally you should also set the location + // for the hosted swf, which should be relative to the page (not video.js) + // Otherwise this adds a CDN url. + // The CDN also auto-adds a swf URL for that specific version. + if (!options.swf) { + var ver = '5.4.1'; + + options.swf = '//vjs.zencdn.net/swf/' + ver + '/video-js.swf'; + } + + // Generate ID for swf object + var objId = options.techId; + + // Merge default flashvars with ones passed in to init + var flashVars = (0, _obj.assign)({ + + // SWF Callback Functions + readyFunction: 'videojs.Flash.onReady', + eventProxyFunction: 'videojs.Flash.onEvent', + errorEventProxyFunction: 'videojs.Flash.onError', + + // Player Settings + autoplay: options.autoplay, + preload: options.preload, + loop: options.loop, + muted: options.muted + + }, options.flashVars); + + // Merge default parames with ones passed in + var params = (0, _obj.assign)({ + // Opaque is needed to overlay controls, but can affect playback performance + wmode: 'opaque', + // Using bgcolor prevents a white flash when the object is loading + bgcolor: '#000000' + }, options.params); + + // Merge default attributes with ones passed in + var attributes = (0, _obj.assign)({ + // Both ID and Name needed or swf to identify itself + id: objId, + name: objId, + 'class': 'vjs-tech' + }, options.attributes); + + this.el_ = Flash.embed(options.swf, flashVars, params, attributes); + this.el_.tech = this; + + return this.el_; + }; + + /** + * Called by {@link Player#play} to play using the `Flash` `Tech`. + */ + + + Flash.prototype.play = function play() { + if (this.ended()) { + this.setCurrentTime(0); + } + this.el_.vjs_play(); + }; + + /** + * Called by {@link Player#pause} to pause using the `Flash` `Tech`. + */ + + + Flash.prototype.pause = function pause() { + this.el_.vjs_pause(); + }; + + /** + * A getter/setter for the `Flash` Tech's source object. + * > Note: Please use {@link Flash#setSource} + * + * @param {Tech~SourceObject} [src] + * The source object you want to set on the `Flash` techs. + * + * @return {Tech~SourceObject|undefined} + * - The current source object when a source is not passed in. + * - undefined when setting + * + * @deprecated Since version 5. + */ + + + Flash.prototype.src = function src(_src) { + if (_src === undefined) { + return this.currentSrc(); + } + + // Setting src through `src` not `setSrc` will be deprecated + return this.setSrc(_src); + }; + + /** + * A getter/setter for the `Flash` Tech's source object. + * + * @param {Tech~SourceObject} [src] + * The source object you want to set on the `Flash` techs. + * + * @return {Tech~SourceObject|undefined} + * - The current source object when a source is not passed in. + * - undefined when setting + */ + + + Flash.prototype.setSrc = function setSrc(src) { + var _this2 = this; + + // Make sure source URL is absolute. + src = Url.getAbsoluteURL(src); + this.el_.vjs_src(src); + + // Currently the SWF doesn't autoplay if you load a source later. + // e.g. Load player w/ no source, wait 2s, set src. + if (this.autoplay()) { + this.setTimeout(function () { + return _this2.play(); + }, 0); + } + }; + + /** + * Indicates whether the media is currently seeking to a new position or not. + * + * @return {boolean} + * - True if seeking to a new position + * - False otherwise + */ + + + Flash.prototype.seeking = function seeking() { + return this.lastSeekTarget_ !== undefined; + }; + + /** + * Returns the current time in seconds that the media is at in playback. + * + * @param {number} time + * Current playtime of the media in seconds. + */ + + + Flash.prototype.setCurrentTime = function setCurrentTime(time) { + var seekable = this.seekable(); + + if (seekable.length) { + // clamp to the current seekable range + time = time > seekable.start(0) ? time : seekable.start(0); + time = time < seekable.end(seekable.length - 1) ? time : seekable.end(seekable.length - 1); + + this.lastSeekTarget_ = time; + this.trigger('seeking'); + this.el_.vjs_setProperty('currentTime', time); + _Tech.prototype.setCurrentTime.call(this); + } + }; + + /** + * Get the current playback time in seconds + * + * @return {number} + * The current time of playback in seconds. + */ + + + Flash.prototype.currentTime = function currentTime() { + // when seeking make the reported time keep up with the requested time + // by reading the time we're seeking to + if (this.seeking()) { + return this.lastSeekTarget_ || 0; + } + return this.el_.vjs_getProperty('currentTime'); + }; + + /** + * Get the current source + * + * @method currentSrc + * @return {Tech~SourceObject} + * The current source + */ + + + Flash.prototype.currentSrc = function currentSrc() { + if (this.currentSource_) { + return this.currentSource_.src; + } + return this.el_.vjs_getProperty('currentSrc'); + }; + + /** + * Get the total duration of the current media. + * + * @return {number} + 8 The total duration of the current media. + */ + + + Flash.prototype.duration = function duration() { + if (this.readyState() === 0) { + return NaN; + } + var duration = this.el_.vjs_getProperty('duration'); + + return duration >= 0 ? duration : Infinity; + }; + + /** + * Load media into Tech. + */ + + + Flash.prototype.load = function load() { + this.el_.vjs_load(); + }; + + /** + * Get the poster image that was set on the tech. + */ + + + Flash.prototype.poster = function poster() { + this.el_.vjs_getProperty('poster'); + }; + + /** + * Poster images are not handled by the Flash tech so make this is a no-op. + */ + + + Flash.prototype.setPoster = function setPoster() {}; + + /** + * Determine the time ranges that can be seeked to in the media. + * + * @return {TimeRange} + * Returns the time ranges that can be seeked to. + */ + + + Flash.prototype.seekable = function seekable() { + var duration = this.duration(); + + if (duration === 0) { + return (0, _timeRanges.createTimeRange)(); + } + return (0, _timeRanges.createTimeRange)(0, duration); + }; + + /** + * Get and create a `TimeRange` object for buffering. + * + * @return {TimeRange} + * The time range object that was created. + */ + + + Flash.prototype.buffered = function buffered() { + var ranges = this.el_.vjs_getProperty('buffered'); + + if (ranges.length === 0) { + return (0, _timeRanges.createTimeRange)(); + } + return (0, _timeRanges.createTimeRange)(ranges[0][0], ranges[0][1]); + }; + + /** + * Get fullscreen support - + * + * Flash does not allow fullscreen through javascript + * so this always returns false. + * + * @return {boolean} + * The Flash tech does not support fullscreen, so it will always return false. + */ + + + Flash.prototype.supportsFullScreen = function supportsFullScreen() { + // Flash does not allow fullscreen through javascript + return false; + }; + + /** + * Flash does not allow fullscreen through javascript + * so this always returns false. + * + * @return {boolean} + * The Flash tech does not support fullscreen, so it will always return false. + */ + + + Flash.prototype.enterFullScreen = function enterFullScreen() { + return false; + }; + + /** + * Gets available media playback quality metrics as specified by the W3C's Media + * Playback Quality API. + * + * @see [Spec]{@link https://wicg.github.io/media-playback-quality} + * + * @return {Object} + * An object with supported media playback quality metrics + */ + + + Flash.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() { + var videoPlaybackQuality = this.el_.vjs_getProperty('getVideoPlaybackQuality'); + + if (_window2['default'].performance && typeof _window2['default'].performance.now === 'function') { + videoPlaybackQuality.creationTime = _window2['default'].performance.now(); + } else if (_window2['default'].performance && _window2['default'].performance.timing && typeof _window2['default'].performance.timing.navigationStart === 'number') { + videoPlaybackQuality.creationTime = _window2['default'].Date.now() - _window2['default'].performance.timing.navigationStart; + } + + return videoPlaybackQuality; + }; + + return Flash; +}(_tech2['default']); + +// Create setters and getters for attributes + + +var _api = Flash.prototype; +var _readWrite = 'rtmpConnection,rtmpStream,preload,defaultPlaybackRate,playbackRate,autoplay,loop,mediaGroup,controller,controls,volume,muted,defaultMuted'.split(','); +var _readOnly = 'networkState,readyState,initialTime,startOffsetTime,paused,ended,videoWidth,videoHeight'.split(','); + +function _createSetter(attr) { + var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1); + + _api['set' + attrUpper] = function (val) { + return this.el_.vjs_setProperty(attr, val); + }; +} + +function _createGetter(attr) { + _api[attr] = function () { + return this.el_.vjs_getProperty(attr); + }; +} + +// Create getter and setters for all read/write attributes +for (var i = 0; i < _readWrite.length; i++) { + _createGetter(_readWrite[i]); + _createSetter(_readWrite[i]); +} + +// Create getters for read-only attributes +for (var _i = 0; _i < _readOnly.length; _i++) { + _createGetter(_readOnly[_i]); +} + +/** ------------------------------ Getters ------------------------------ **/ +/** + * Get the value of `rtmpConnection` from the swf. + * + * @method Flash#rtmpConnection + * @return {string} + * The current value of `rtmpConnection` on the swf. + */ + +/** + * Get the value of `rtmpStream` from the swf. + * + * @method Flash#rtmpStream + * @return {string} + * The current value of `rtmpStream` on the swf. + */ + +/** + * Get the value of `preload` from the swf. `preload` indicates + * what should download before the media is interacted with. It can have the following + * values: + * - none: nothing should be downloaded + * - metadata: poster and the first few frames of the media may be downloaded to get + * media dimensions and other metadata + * - auto: allow the media and metadata for the media to be downloaded before + * interaction + * + * @method Flash#preload + * @return {string} + * The value of `preload` from the swf. Will be 'none', 'metadata', + * or 'auto'. + */ + +/** + * Get the value of `defaultPlaybackRate` from the swf. + * + * @method Flash#defaultPlaybackRate + * @return {number} + * The current value of `defaultPlaybackRate` on the swf. + */ + +/** + * Get the value of `playbackRate` from the swf. `playbackRate` indicates + * the rate at which the media is currently playing back. Examples: + * - if playbackRate is set to 2, media will play twice as fast. + * - if playbackRate is set to 0.5, media will play half as fast. + * + * @method Flash#playbackRate + * @return {number} + * The value of `playbackRate` from the swf. A number indicating + * the current playback speed of the media, where 1 is normal speed. + */ + +/** + * Get the value of `autoplay` from the swf. `autoplay` indicates + * that the media should start to play as soon as the page is ready. + * + * @method Flash#autoplay + * @return {boolean} + * - The value of `autoplay` from the swf. + * - True indicates that the media ashould start as soon as the page loads. + * - False indicates that the media should not start as soon as the page loads. + */ + +/** + * Get the value of `loop` from the swf. `loop` indicates + * that the media should return to the start of the media and continue playing once + * it reaches the end. + * + * @method Flash#loop + * @return {boolean} + * - The value of `loop` from the swf. + * - True indicates that playback should seek back to start once + * the end of a media is reached. + * - False indicates that playback should not loop back to the start when the + * end of the media is reached. + */ + +/** + * Get the value of `mediaGroup` from the swf. + * + * @method Flash#mediaGroup + * @return {string} + * The current value of `mediaGroup` on the swf. + */ + +/** + * Get the value of `controller` from the swf. + * + * @method Flash#controller + * @return {string} + * The current value of `controller` on the swf. + */ + +/** + * Get the value of `controls` from the swf. `controls` indicates + * whether the native flash controls should be shown or hidden. + * + * @method Flash#controls + * @return {boolean} + * - The value of `controls` from the swf. + * - True indicates that native controls should be showing. + * - False indicates that native controls should be hidden. + */ + +/** + * Get the value of the `volume` from the swf. `volume` indicates the current + * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and + * so on. + * + * @method Flash#volume + * @return {number} + * The volume percent as a decimal. Value will be between 0-1. + */ + +/** + * Get the value of the `muted` from the swf. `muted` indicates the current + * audio level should be silent. + * + * @method Flash#muted + * @return {boolean} + * - True if the audio should be set to silent + * - False otherwise + */ + +/** + * Get the value of `defaultMuted` from the swf. `defaultMuted` indicates + * whether the media should start muted or not. Only changes the default state of the + * media. `muted` and `defaultMuted` can have different values. `muted` indicates the + * current state. + * + * @method Flash#defaultMuted + * @return {boolean} + * - The value of `defaultMuted` from the swf. + * - True indicates that the media should start muted. + * - False indicates that the media should not start muted. + */ + +/** + * Get the value of `networkState` from the swf. `networkState` indicates + * the current network state. It returns an enumeration from the following list: + * - 0: NETWORK_EMPTY + * - 1: NEWORK_IDLE + * - 2: NETWORK_LOADING + * - 3: NETWORK_NO_SOURCE + * + * @method Flash#networkState + * @return {number} + * The value of `networkState` from the swf. This will be a number + * from the list in the description. + */ + +/** + * Get the value of `readyState` from the swf. `readyState` indicates + * the current state of the media element. It returns an enumeration from the + * following list: + * - 0: HAVE_NOTHING + * - 1: HAVE_METADATA + * - 2: HAVE_CURRENT_DATA + * - 3: HAVE_FUTURE_DATA + * - 4: HAVE_ENOUGH_DATA + * + * @method Flash#readyState + * @return {number} + * The value of `readyState` from the swf. This will be a number + * from the list in the description. + */ + +/** + * Get the value of `readyState` from the swf. `readyState` indicates + * the current state of the media element. It returns an enumeration from the + * following list: + * - 0: HAVE_NOTHING + * - 1: HAVE_METADATA + * - 2: HAVE_CURRENT_DATA + * - 3: HAVE_FUTURE_DATA + * - 4: HAVE_ENOUGH_DATA + * + * @method Flash#readyState + * @return {number} + * The value of `readyState` from the swf. This will be a number + * from the list in the description. + */ + +/** + * Get the value of `initialTime` from the swf. + * + * @method Flash#initialTime + * @return {number} + * The `initialTime` proprety on the swf. + */ + +/** + * Get the value of `startOffsetTime` from the swf. + * + * @method Flash#startOffsetTime + * @return {number} + * The `startOffsetTime` proprety on the swf. + */ + +/** + * Get the value of `paused` from the swf. `paused` indicates whether the swf + * is current paused or not. + * + * @method Flash#paused + * @return {boolean} + * The value of `paused` from the swf. + */ + +/** + * Get the value of `ended` from the swf. `ended` indicates whether + * the media has reached the end or not. + * + * @method Flash#ended + * @return {boolean} + * - True indicates that the media has ended. + * - False indicates that the media has not ended. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended} + */ + +/** + * Get the value of `videoWidth` from the swf. `videoWidth` indicates + * the current width of the media in css pixels. + * + * @method Flash#videoWidth + * @return {number} + * The value of `videoWidth` from the swf. This will be a number + * in css pixels. + */ + +/** + * Get the value of `videoHeight` from the swf. `videoHeigth` indicates + * the current height of the media in css pixels. + * + * @method Flassh.prototype.videoHeight + * @return {number} + * The value of `videoHeight` from the swf. This will be a number + * in css pixels. + */ +/** ------------------------------ Setters ------------------------------ **/ + +/** + * Set the value of `rtmpConnection` on the swf. + * + * @method Flash#setRtmpConnection + * @param {string} rtmpConnection + * New value to set the `rtmpConnection` property to. + */ + +/** + * Set the value of `rtmpStream` on the swf. + * + * @method Flash#setRtmpStream + * @param {string} rtmpStream + * New value to set the `rtmpStream` property to. + */ + +/** + * Set the value of `preload` on the swf. `preload` indicates + * what should download before the media is interacted with. It can have the following + * values: + * - none: nothing should be downloaded + * - metadata: poster and the first few frames of the media may be downloaded to get + * media dimensions and other metadata + * - auto: allow the media and metadata for the media to be downloaded before + * interaction + * + * @method Flash#setPreload + * @param {string} preload + * The value of `preload` to set on the swf. Should be 'none', 'metadata', + * or 'auto'. + */ + +/** + * Set the value of `defaultPlaybackRate` on the swf. + * + * @method Flash#setDefaultPlaybackRate + * @param {number} defaultPlaybackRate + * New value to set the `defaultPlaybackRate` property to. + */ + +/** + * Set the value of `playbackRate` on the swf. `playbackRate` indicates + * the rate at which the media is currently playing back. Examples: + * - if playbackRate is set to 2, media will play twice as fast. + * - if playbackRate is set to 0.5, media will play half as fast. + * + * @method Flash#setPlaybackRate + * @param {number} playbackRate + * New value of `playbackRate` on the swf. A number indicating + * the current playback speed of the media, where 1 is normal speed. + */ + +/** + * Set the value of `autoplay` on the swf. `autoplay` indicates + * that the media should start to play as soon as the page is ready. + * + * @method Flash#setAutoplay + * @param {boolean} autoplay + * - The value of `autoplay` from the swf. + * - True indicates that the media ashould start as soon as the page loads. + * - False indicates that the media should not start as soon as the page loads. + */ + +/** + * Set the value of `loop` on the swf. `loop` indicates + * that the media should return to the start of the media and continue playing once + * it reaches the end. + * + * @method Flash#setLoop + * @param {boolean} loop + * - True indicates that playback should seek back to start once + * the end of a media is reached. + * - False indicates that playback should not loop back to the start when the + * end of the media is reached. + */ + +/** + * Set the value of `mediaGroup` on the swf. + * + * @method Flash#setMediaGroup + * @param {string} mediaGroup + * New value of `mediaGroup` to set on the swf. + */ + +/** + * Set the value of `controller` on the swf. + * + * @method Flash#setController + * @param {string} controller + * New value the current value of `controller` on the swf. + */ + +/** + * Get the value of `controls` from the swf. `controls` indicates + * whether the native flash controls should be shown or hidden. + * + * @method Flash#controls + * @return {boolean} + * - The value of `controls` from the swf. + * - True indicates that native controls should be showing. + * - False indicates that native controls should be hidden. + */ + +/** + * Set the value of the `volume` on the swf. `volume` indicates the current + * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and + * so on. + * + * @method Flash#setVolume + * @param {number} percentAsDecimal + * The volume percent as a decimal. Value will be between 0-1. + */ + +/** + * Set the value of the `muted` on the swf. `muted` indicates that the current + * audio level should be silent. + * + * @method Flash#setMuted + * @param {boolean} muted + * - True if the audio should be set to silent + * - False otherwise + */ + +/** + * Set the value of `defaultMuted` on the swf. `defaultMuted` indicates + * whether the media should start muted or not. Only changes the default state of the + * media. `muted` and `defaultMuted` can have different values. `muted` indicates the + * current state. + * + * @method Flash#setDefaultMuted + * @param {boolean} defaultMuted + * - True indicates that the media should start muted. + * - False indicates that the media should not start muted. + */ + +/* Flash Support Testing -------------------------------------------------------- */ + +/** + * Check if the Flash tech is currently supported. + * + * @return {boolean} + * - True if the flash tech is supported. + * - False otherwise. + */ +Flash.isSupported = function () { + return Flash.version()[0] >= 10; + // return swfobject.hasFlashPlayerVersion('10'); +}; + +// Add Source Handler pattern functions to this tech +_tech2['default'].withSourceHandlers(Flash); + +/* + * Native source handler for flash, simply passes the source to the swf element. + * + * @property {Tech~SourceObject} source + * The source object + * + * @property {Flash} tech + * The instance of the Flash tech + */ +Flash.nativeSourceHandler = {}; + +/** + * Check if the Flash can play the given mime type. + * + * @param {string} type + * The mimetype to check + * + * @return {string} + * 'maybe', or '' (empty string) + */ +Flash.nativeSourceHandler.canPlayType = function (type) { + if (type in Flash.formats) { + return 'maybe'; + } + + return ''; +}; + +/** + * Check if the media element can handle a source natively. + * + * @param {Tech~SourceObject} source + * The source object + * + * @param {Object} [options] + * Options to be passed to the tech. + * + * @return {string} + * 'maybe', or '' (empty string). + */ +Flash.nativeSourceHandler.canHandleSource = function (source, options) { + var type = void 0; + + function guessMimeType(src) { + var ext = Url.getFileExtension(src); + + if (ext) { + return 'video/' + ext; + } + return ''; + } + + if (!source.type) { + type = guessMimeType(source.src); + } else { + // Strip code information from the type because we don't get that specific + type = source.type.replace(/;.*/, '').toLowerCase(); + } + + return Flash.nativeSourceHandler.canPlayType(type); +}; + +/** + * Pass the source to the swf. + * + * @param {Tech~SourceObject} source + * The source object + * + * @param {Flash} tech + * The instance of the Flash tech + * + * @param {Object} [options] + * The options to pass to the source + */ +Flash.nativeSourceHandler.handleSource = function (source, tech, options) { + tech.setSrc(source.src); +}; + +/** + * noop for native source handler dispose, as cleanup will happen automatically. + */ +Flash.nativeSourceHandler.dispose = function () {}; + +// Register the native source handler +Flash.registerSourceHandler(Flash.nativeSourceHandler); + +/** + * Flash supported mime types. + * + * @constant {Object} + */ +Flash.formats = { + 'video/flv': 'FLV', + 'video/x-flv': 'FLV', + 'video/mp4': 'MP4', + 'video/m4v': 'MP4' +}; + +/** + * Called when the the swf is "ready", and makes sure that the swf is really + * ready using {@link Flash#checkReady} + */ +Flash.onReady = function (currSwf) { + var el = Dom.getEl(currSwf); + var tech = el && el.tech; + + // if there is no el then the tech has been disposed + // and the tech element was removed from the player div + if (tech && tech.el()) { + // check that the flash object is really ready + Flash.checkReady(tech); + } +}; + +/** + * The SWF isn't always ready when it says it is. Sometimes the API functions still + * need to be added to the object. If it's not ready, we set a timeout to check again + * shortly. + * + * @param {Flash} tech + * The instance of the flash tech to check. + */ +Flash.checkReady = function (tech) { + // stop worrying if the tech has been disposed + if (!tech.el()) { + return; + } + + // check if API property exists + if (tech.el().vjs_getProperty) { + // tell tech it's ready + tech.triggerReady(); + } else { + // wait longer + this.setTimeout(function () { + Flash.checkReady(tech); + }, 50); + } +}; + +/** + * Trigger events from the swf on the Flash Tech. + * + * @param {number} swfID + * The id of the swf that had the event + * + * @param {string} eventName + * The name of the event to trigger + */ +Flash.onEvent = function (swfID, eventName) { + var tech = Dom.getEl(swfID).tech; + var args = Array.prototype.slice.call(arguments, 2); + + // dispatch Flash events asynchronously for two reasons: + // - Flash swallows any exceptions generated by javascript it + // invokes + // - Flash is suspended until the javascript returns which may cause + // playback performance issues + tech.setTimeout(function () { + tech.trigger(eventName, args); + }, 1); +}; + +/** + * Log errors from the swf on the Flash tech. + * + * @param {number} swfID + * The id of the swf that had an error. + * + * @param {string} The error string + * The error to set on the Flash Tech. + * + * @return {MediaError|undefined} + * - Returns a MediaError when err is 'srcnotfound' + * - Returns undefined otherwise. + */ +Flash.onError = function (swfID, err) { + var tech = Dom.getEl(swfID).tech; + + // trigger MEDIA_ERR_SRC_NOT_SUPPORTED + if (err === 'srcnotfound') { + return tech.error(4); + } + + // trigger a custom error + tech.error('FLASH: ' + err); +}; + +/** + * Get the current version of Flash that is in use on the page. + * + * @return {Array} + * an array of versions that are available. + */ +Flash.version = function () { + var version = '0,0,0'; + + // IE + try { + version = new _window2['default'].ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1]; + + // other browsers + } catch (e) { + try { + if (navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin) { + version = (navigator.plugins['Shockwave Flash 2.0'] || navigator.plugins['Shockwave Flash']).description.replace(/\D+/g, ',').match(/^,?(.+),?$/)[1]; + } + } catch (err) { + // satisfy linter + } + } + return version.split(','); +}; + +/** + * Only use for non-iframe embeds. + * + * @param {Object} swf + * The videojs-swf object. + * + * @param {Object} flashVars + * Names and values to use as flash option variables. + * + * @param {Object} params + * Style parameters to set on the object. + * + * @param {Object} attributes + * Attributes to set on the element. + * + * @return {Element} + * The embeded Flash DOM element. + */ +Flash.embed = function (swf, flashVars, params, attributes) { + var code = Flash.getEmbedCode(swf, flashVars, params, attributes); + + // Get element by embedding code and retrieving created element + var obj = Dom.createEl('div', { innerHTML: code }).childNodes[0]; + + return obj; +}; + +/** + * Only use for non-iframe embeds. + * + * @param {Object} swf + * The videojs-swf object. + * + * @param {Object} flashVars + * Names and values to use as flash option variables. + * + * @param {Object} params + * Style parameters to set on the object. + * + * @param {Object} attributes + * Attributes to set on the element. + * + * @return {Element} + * The embeded Flash DOM element. + */ +Flash.getEmbedCode = function (swf, flashVars, params, attributes) { + var objTag = ''; + }); + + attributes = (0, _obj.assign)({ + // Add swf to attributes (need both for IE and Others to work) + data: swf, + + // Default to 100% width/height + width: '100%', + height: '100%' + + }, attributes); + + // Create Attributes string + Object.getOwnPropertyNames(attributes).forEach(function (key) { + attrsString += key + '="' + attributes[key] + '" '; + }); + + return '' + objTag + attrsString + '>' + paramsString + ''; +}; + +// Run Flash through the RTMP decorator +(0, _flashRtmp2['default'])(Flash); + +_component2['default'].registerComponent('Flash', Flash); +_tech2['default'].registerTech('Flash', Flash); +exports['default'] = Flash; + +},{"5":5,"58":58,"62":62,"81":81,"88":88,"90":90,"92":92,"95":95}],60:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _templateObject = _taggedTemplateLiteralLoose(['Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n This may prevent text tracks from loading.'], ['Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n This may prevent text tracks from loading.']); + +var _tech = _dereq_(62); + +var _tech2 = _interopRequireDefault(_tech); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _url = _dereq_(92); + +var Url = _interopRequireWildcard(_url); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _log = _dereq_(86); + +var _log2 = _interopRequireDefault(_log); + +var _tsml = _dereq_(98); + +var _tsml2 = _interopRequireDefault(_tsml); + +var _browser = _dereq_(78); + +var browser = _interopRequireWildcard(_browser); + +var _document = _dereq_(94); + +var _document2 = _interopRequireDefault(_document); + +var _window = _dereq_(95); + +var _window2 = _interopRequireDefault(_window); + +var _obj = _dereq_(88); + +var _mergeOptions = _dereq_(87); + +var _mergeOptions2 = _interopRequireDefault(_mergeOptions); + +var _toTitleCase = _dereq_(91); + +var _toTitleCase2 = _interopRequireDefault(_toTitleCase); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _taggedTemplateLiteralLoose(strings, raw) { strings.raw = raw; return strings; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file html5.js + */ + + +/** + * HTML5 Media Controller - Wrapper for HTML5 Media API + * + * @mixes Tech~SouceHandlerAdditions + * @extends Tech + */ +var Html5 = function (_Tech) { + _inherits(Html5, _Tech); + + /** + * Create an instance of this Tech. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} ready + * Callback function to call when the `HTML5` Tech is ready. + */ + function Html5(options, ready) { + _classCallCheck(this, Html5); + + var _this = _possibleConstructorReturn(this, _Tech.call(this, options, ready)); + + var source = options.source; + var crossoriginTracks = false; + + // Set the source if one is provided + // 1) Check if the source is new (if not, we want to keep the original so playback isn't interrupted) + // 2) Check to see if the network state of the tag was failed at init, and if so, reset the source + // anyway so the error gets fired. + if (source && (_this.el_.currentSrc !== source.src || options.tag && options.tag.initNetworkState_ === 3)) { + _this.setSource(source); + } else { + _this.handleLateInit_(_this.el_); + } + + if (_this.el_.hasChildNodes()) { + + var nodes = _this.el_.childNodes; + var nodesLength = nodes.length; + var removeNodes = []; + + while (nodesLength--) { + var node = nodes[nodesLength]; + var nodeName = node.nodeName.toLowerCase(); + + if (nodeName === 'track') { + if (!_this.featuresNativeTextTracks) { + // Empty video tag tracks so the built-in player doesn't use them also. + // This may not be fast enough to stop HTML5 browsers from reading the tags + // so we'll need to turn off any default tracks if we're manually doing + // captions and subtitles. videoElement.textTracks + removeNodes.push(node); + } else { + // store HTMLTrackElement and TextTrack to remote list + _this.remoteTextTrackEls().addTrackElement_(node); + _this.remoteTextTracks().addTrack_(node.track); + if (!crossoriginTracks && !_this.el_.hasAttribute('crossorigin') && Url.isCrossOrigin(node.src)) { + crossoriginTracks = true; + } + } + } + } + + for (var i = 0; i < removeNodes.length; i++) { + _this.el_.removeChild(removeNodes[i]); + } + } + + // TODO: add text tracks into this list + var trackTypes = ['audio', 'video']; + + // ProxyNative Video/Audio Track + trackTypes.forEach(function (type) { + var elTracks = _this.el()[type + 'Tracks']; + var techTracks = _this[type + 'Tracks'](); + var capitalType = (0, _toTitleCase2['default'])(type); + + if (!_this['featuresNative' + capitalType + 'Tracks'] || !elTracks || !elTracks.addEventListener) { + return; + } + + _this['handle' + capitalType + 'TrackChange_'] = function (e) { + techTracks.trigger({ + type: 'change', + target: techTracks, + currentTarget: techTracks, + srcElement: techTracks + }); + }; + + _this['handle' + capitalType + 'TrackAdd_'] = function (e) { + return techTracks.addTrack(e.track); + }; + _this['handle' + capitalType + 'TrackRemove_'] = function (e) { + return techTracks.removeTrack(e.track); + }; + + elTracks.addEventListener('change', _this['handle' + capitalType + 'TrackChange_']); + elTracks.addEventListener('addtrack', _this['handle' + capitalType + 'TrackAdd_']); + elTracks.addEventListener('removetrack', _this['handle' + capitalType + 'TrackRemove_']); + _this['removeOld' + capitalType + 'Tracks_'] = function (e) { + return _this.removeOldTracks_(techTracks, elTracks); + }; + + // Remove (native) tracks that are not used anymore + _this.on('loadstart', _this['removeOld' + capitalType + 'Tracks_']); + }); + + if (_this.featuresNativeTextTracks) { + if (crossoriginTracks) { + _log2['default'].warn((0, _tsml2['default'])(_templateObject)); + } + + _this.handleTextTrackChange_ = Fn.bind(_this, _this.handleTextTrackChange); + _this.handleTextTrackAdd_ = Fn.bind(_this, _this.handleTextTrackAdd); + _this.handleTextTrackRemove_ = Fn.bind(_this, _this.handleTextTrackRemove); + _this.proxyNativeTextTracks_(); + } + + // Determine if native controls should be used + // Our goal should be to get the custom controls on mobile solid everywhere + // so we can remove this all together. Right now this will block custom + // controls on touch enabled laptops like the Chrome Pixel + if ((browser.TOUCH_ENABLED || browser.IS_IPHONE || browser.IS_NATIVE_ANDROID) && options.nativeControlsForTouch === true) { + _this.setControls(true); + } + + // on iOS, we want to proxy `webkitbeginfullscreen` and `webkitendfullscreen` + // into a `fullscreenchange` event + _this.proxyWebkitFullscreen_(); + + _this.triggerReady(); + return _this; + } + + /** + * Dispose of `HTML5` media element and remove all tracks. + */ + + + Html5.prototype.dispose = function dispose() { + var _this2 = this; + + // Un-ProxyNativeTracks + ['audio', 'video', 'text'].forEach(function (type) { + var capitalType = (0, _toTitleCase2['default'])(type); + var tl = _this2.el_[type + 'Tracks']; + + if (tl && tl.removeEventListener) { + tl.removeEventListener('change', _this2['handle' + capitalType + 'TrackChange_']); + tl.removeEventListener('addtrack', _this2['handle' + capitalType + 'TrackAdd_']); + tl.removeEventListener('removetrack', _this2['handle' + capitalType + 'TrackRemove_']); + } + + // Stop removing old text tracks + if (tl) { + _this2.off('loadstart', _this2['removeOld' + capitalType + 'Tracks_']); + } + }); + + Html5.disposeMediaElement(this.el_); + // tech will handle clearing of the emulated track list + _Tech.prototype.dispose.call(this); + }; + + /** + * Create the `Html5` Tech's DOM element. + * + * @return {Element} + * The element that gets created. + */ + + + Html5.prototype.createEl = function createEl() { + var el = this.options_.tag; + + // Check if this browser supports moving the element into the box. + // On the iPhone video will break if you move the element, + // So we have to create a brand new element. + // If we ingested the player div, we do not need to move the media element. + if (!el || !(this.options_.playerElIngest || this.movingMediaElementInDOM)) { + + // If the original tag is still there, clone and remove it. + if (el) { + var clone = el.cloneNode(true); + + if (el.parentNode) { + el.parentNode.insertBefore(clone, el); + } + Html5.disposeMediaElement(el); + el = clone; + } else { + el = _document2['default'].createElement('video'); + + // determine if native controls should be used + var tagAttributes = this.options_.tag && Dom.getElAttributes(this.options_.tag); + var attributes = (0, _mergeOptions2['default'])({}, tagAttributes); + + if (!browser.TOUCH_ENABLED || this.options_.nativeControlsForTouch !== true) { + delete attributes.controls; + } + + Dom.setElAttributes(el, (0, _obj.assign)(attributes, { + id: this.options_.techId, + 'class': 'vjs-tech' + })); + } + + el.playerId = this.options_.playerId; + } + + // Update specific tag settings, in case they were overridden + var settingsAttrs = ['autoplay', 'preload', 'loop', 'muted', 'playsinline']; + + for (var i = settingsAttrs.length - 1; i >= 0; i--) { + var attr = settingsAttrs[i]; + var overwriteAttrs = {}; + + if (typeof this.options_[attr] !== 'undefined') { + overwriteAttrs[attr] = this.options_[attr]; + } + Dom.setElAttributes(el, overwriteAttrs); + } + + return el; + }; + + /** + * This will be triggered if the loadstart event has already fired, before videojs was + * ready. Two known examples of when this can happen are: + * 1. If we're loading the playback object after it has started loading + * 2. The media is already playing the (often with autoplay on) then + * + * This function will fire another loadstart so that videojs can catchup. + * + * @fires Tech#loadstart + * + * @return {undefined} + * returns nothing. + */ + + + Html5.prototype.handleLateInit_ = function handleLateInit_(el) { + if (el.networkState === 0 || el.networkState === 3) { + // The video element hasn't started loading the source yet + // or didn't find a source + return; + } + + if (el.readyState === 0) { + // NetworkState is set synchronously BUT loadstart is fired at the + // end of the current stack, usually before setInterval(fn, 0). + // So at this point we know loadstart may have already fired or is + // about to fire, and either way the player hasn't seen it yet. + // We don't want to fire loadstart prematurely here and cause a + // double loadstart so we'll wait and see if it happens between now + // and the next loop, and fire it if not. + // HOWEVER, we also want to make sure it fires before loadedmetadata + // which could also happen between now and the next loop, so we'll + // watch for that also. + var loadstartFired = false; + var setLoadstartFired = function setLoadstartFired() { + loadstartFired = true; + }; + + this.on('loadstart', setLoadstartFired); + + var triggerLoadstart = function triggerLoadstart() { + // We did miss the original loadstart. Make sure the player + // sees loadstart before loadedmetadata + if (!loadstartFired) { + this.trigger('loadstart'); + } + }; + + this.on('loadedmetadata', triggerLoadstart); + + this.ready(function () { + this.off('loadstart', setLoadstartFired); + this.off('loadedmetadata', triggerLoadstart); + + if (!loadstartFired) { + // We did miss the original native loadstart. Fire it now. + this.trigger('loadstart'); + } + }); + + return; + } + + // From here on we know that loadstart already fired and we missed it. + // The other readyState events aren't as much of a problem if we double + // them, so not going to go to as much trouble as loadstart to prevent + // that unless we find reason to. + var eventsToTrigger = ['loadstart']; + + // loadedmetadata: newly equal to HAVE_METADATA (1) or greater + eventsToTrigger.push('loadedmetadata'); + + // loadeddata: newly increased to HAVE_CURRENT_DATA (2) or greater + if (el.readyState >= 2) { + eventsToTrigger.push('loadeddata'); + } + + // canplay: newly increased to HAVE_FUTURE_DATA (3) or greater + if (el.readyState >= 3) { + eventsToTrigger.push('canplay'); + } + + // canplaythrough: newly equal to HAVE_ENOUGH_DATA (4) + if (el.readyState >= 4) { + eventsToTrigger.push('canplaythrough'); + } + + // We still need to give the player time to add event listeners + this.ready(function () { + eventsToTrigger.forEach(function (type) { + this.trigger(type); + }, this); + }); + }; + + /** + * Add event listeners to native text track events. This adds the native text tracks + * to our emulated {@link TextTrackList}. + */ + + + Html5.prototype.proxyNativeTextTracks_ = function proxyNativeTextTracks_() { + var tt = this.el().textTracks; + + if (tt) { + // Add tracks - if player is initialised after DOM loaded, textTracks + // will not trigger addtrack + for (var i = 0; i < tt.length; i++) { + this.textTracks().addTrack_(tt[i]); + } + + if (tt.addEventListener) { + tt.addEventListener('change', this.handleTextTrackChange_); + tt.addEventListener('addtrack', this.handleTextTrackAdd_); + tt.addEventListener('removetrack', this.handleTextTrackRemove_); + } + + // Remove (native) texttracks that are not used anymore + this.on('loadstart', this.removeOldTextTracks_); + } + }; + + /** + * Handle any {@link TextTrackList} `change` event. + * + * @param {EventTarget~Event} e + * The `change` event that caused this to run. + * + * @listens TextTrackList#change + */ + + + Html5.prototype.handleTextTrackChange = function handleTextTrackChange(e) { + var tt = this.textTracks(); + + this.textTracks().trigger({ + type: 'change', + target: tt, + currentTarget: tt, + srcElement: tt + }); + }; + + /** + * Handle any {@link TextTrackList} `addtrack` event. + * + * @param {EventTarget~Event} e + * The `addtrack` event that caused this to run. + * + * @listens TextTrackList#addtrack + */ + + + Html5.prototype.handleTextTrackAdd = function handleTextTrackAdd(e) { + this.textTracks().addTrack_(e.track); + }; + + /** + * Handle any {@link TextTrackList} `removetrack` event. + * + * @param {EventTarget~Event} e + * The `removetrack` event that caused this to run. + * + * @listens TextTrackList#removetrack + */ + + + Html5.prototype.handleTextTrackRemove = function handleTextTrackRemove(e) { + this.textTracks().removeTrack_(e.track); + }; + + /** + * This function removes any {@link AudioTrack}s, {@link VideoTrack}s, or + * {@link TextTrack}s that are not in the media elements TrackList. + * + * @param {TrackList} techTracks + * HTML5 Tech's TrackList to search through + * + * @param {TrackList} elTracks + * HTML5 media elements TrackList to search trough. + * + * @private + */ + + + Html5.prototype.removeOldTracks_ = function removeOldTracks_(techTracks, elTracks) { + // This will loop over the techTracks and check if they are still used by the HTML5 media element + // If not, they will be removed from the emulated list + var removeTracks = []; + + if (!elTracks) { + return; + } + + for (var i = 0; i < techTracks.length; i++) { + var techTrack = techTracks[i]; + var found = false; + + for (var j = 0; j < elTracks.length; j++) { + if (elTracks[j] === techTrack) { + found = true; + break; + } + } + + if (!found) { + removeTracks.push(techTrack); + } + } + + for (var _i = 0; _i < removeTracks.length; _i++) { + var track = removeTracks[_i]; + + techTracks.removeTrack_(track); + } + }; + + /** + * Remove {@link TextTrack}s that dont exist in the native track list from our + * emulated {@link TextTrackList}. + * + * @listens Tech#loadstart + */ + + + Html5.prototype.removeOldTextTracks_ = function removeOldTextTracks_(e) { + var techTracks = this.textTracks(); + var elTracks = this.el().textTracks; + + this.removeOldTracks_(techTracks, elTracks); + }; + + /** + * Called by {@link Player#play} to play using the `Html5` `Tech`. + */ + + + Html5.prototype.play = function play() { + var playPromise = this.el_.play(); + + // Catch/silence error when a pause interrupts a play request + // on browsers which return a promise + if (playPromise !== undefined && typeof playPromise.then === 'function') { + playPromise.then(null, function (e) {}); + } + }; + + /** + * Set current time for the `HTML5` tech. + * + * @param {number} seconds + * Set the current time of the media to this. + */ + + + Html5.prototype.setCurrentTime = function setCurrentTime(seconds) { + try { + this.el_.currentTime = seconds; + } catch (e) { + (0, _log2['default'])(e, 'Video is not ready. (Video.js)'); + // this.warning(VideoJS.warnings.videoNotReady); + } + }; + + /** + * Get the current duration of the HTML5 media element. + * + * @return {number} + * The duration of the media or 0 if there is no duration. + */ + + + Html5.prototype.duration = function duration() { + var _this3 = this; + + // Android Chrome will report duration as Infinity for VOD HLS until after + // playback has started, which triggers the live display erroneously. + // Return NaN if playback has not started and trigger a durationupdate once + // the duration can be reliably known. + if (this.el_.duration === Infinity && browser.IS_ANDROID && browser.IS_CHROME) { + if (this.el_.currentTime === 0) { + // Wait for the first `timeupdate` with currentTime > 0 - there may be + // several with 0 + var checkProgress = function checkProgress() { + if (_this3.el_.currentTime > 0) { + // Trigger durationchange for genuinely live video + if (_this3.el_.duration === Infinity) { + _this3.trigger('durationchange'); + } + _this3.off('timeupdate', checkProgress); + } + }; + + this.on('timeupdate', checkProgress); + return NaN; + } + } + return this.el_.duration || NaN; + }; + + /** + * Get the current width of the HTML5 media element. + * + * @return {number} + * The width of the HTML5 media element. + */ + + + Html5.prototype.width = function width() { + return this.el_.offsetWidth; + }; + + /** + * Get the current height of the HTML5 media element. + * + * @return {number} + * The heigth of the HTML5 media element. + */ + + + Html5.prototype.height = function height() { + return this.el_.offsetHeight; + }; + + /** + * Proxy iOS `webkitbeginfullscreen` and `webkitendfullscreen` into + * `fullscreenchange` event. + * + * @private + * @fires fullscreenchange + * @listens webkitendfullscreen + * @listens webkitbeginfullscreen + * @listens webkitbeginfullscreen + */ + + + Html5.prototype.proxyWebkitFullscreen_ = function proxyWebkitFullscreen_() { + var _this4 = this; + + if (!('webkitDisplayingFullscreen' in this.el_)) { + return; + } + + var endFn = function endFn() { + this.trigger('fullscreenchange', { isFullscreen: false }); + }; + + var beginFn = function beginFn() { + if ('webkitPresentationMode' in this.el_ && this.el_.webkitPresentationMode !== 'picture-in-picture') { + this.one('webkitendfullscreen', endFn); + + this.trigger('fullscreenchange', { isFullscreen: true }); + } + }; + + this.on('webkitbeginfullscreen', beginFn); + this.on('dispose', function () { + _this4.off('webkitbeginfullscreen', beginFn); + _this4.off('webkitendfullscreen', endFn); + }); + }; + + /** + * Check if fullscreen is supported on the current playback device. + * + * @return {boolean} + * - True if fullscreen is supported. + * - False if fullscreen is not supported. + */ + + + Html5.prototype.supportsFullScreen = function supportsFullScreen() { + if (typeof this.el_.webkitEnterFullScreen === 'function') { + var userAgent = _window2['default'].navigator && _window2['default'].navigator.userAgent || ''; + + // Seems to be broken in Chromium/Chrome && Safari in Leopard + if (/Android/.test(userAgent) || !/Chrome|Mac OS X 10.5/.test(userAgent)) { + return true; + } + } + return false; + }; + + /** + * Request that the `HTML5` Tech enter fullscreen. + */ + + + Html5.prototype.enterFullScreen = function enterFullScreen() { + var video = this.el_; + + if (video.paused && video.networkState <= video.HAVE_METADATA) { + // attempt to prime the video element for programmatic access + // this isn't necessary on the desktop but shouldn't hurt + this.el_.play(); + + // playing and pausing synchronously during the transition to fullscreen + // can get iOS ~6.1 devices into a play/pause loop + this.setTimeout(function () { + video.pause(); + video.webkitEnterFullScreen(); + }, 0); + } else { + video.webkitEnterFullScreen(); + } + }; + + /** + * Request that the `HTML5` Tech exit fullscreen. + */ + + + Html5.prototype.exitFullScreen = function exitFullScreen() { + this.el_.webkitExitFullScreen(); + }; + + /** + * A getter/setter for the `Html5` Tech's source object. + * > Note: Please use {@link Html5#setSource} + * + * @param {Tech~SourceObject} [src] + * The source object you want to set on the `HTML5` techs element. + * + * @return {Tech~SourceObject|undefined} + * - The current source object when a source is not passed in. + * - undefined when setting + * + * @deprecated Since version 5. + */ + + + Html5.prototype.src = function src(_src) { + if (_src === undefined) { + return this.el_.src; + } + + // Setting src through `src` instead of `setSrc` will be deprecated + this.setSrc(_src); + }; + + /** + * Reset the tech by removing all sources and then calling + * {@link Html5.resetMediaElement}. + */ + + + Html5.prototype.reset = function reset() { + Html5.resetMediaElement(this.el_); + }; + + /** + * Get the current source on the `HTML5` Tech. Falls back to returning the source from + * the HTML5 media element. + * + * @return {Tech~SourceObject} + * The current source object from the HTML5 tech. With a fallback to the + * elements source. + */ + + + Html5.prototype.currentSrc = function currentSrc() { + if (this.currentSource_) { + return this.currentSource_.src; + } + return this.el_.currentSrc; + }; + + /** + * Set controls attribute for the HTML5 media Element. + * + * @param {string} val + * Value to set the controls attribute to + */ + + + Html5.prototype.setControls = function setControls(val) { + this.el_.controls = !!val; + }; + + /** + * Create and returns a remote {@link TextTrack} object. + * + * @param {string} kind + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata) + * + * @param {string} [label] + * Label to identify the text track + * + * @param {string} [language] + * Two letter language abbreviation + * + * @return {TextTrack} + * The TextTrack that gets created. + */ + + + Html5.prototype.addTextTrack = function addTextTrack(kind, label, language) { + if (!this.featuresNativeTextTracks) { + return _Tech.prototype.addTextTrack.call(this, kind, label, language); + } + + return this.el_.addTextTrack(kind, label, language); + }; + + /** + * Creates either native TextTrack or an emulated TextTrack depending + * on the value of `featuresNativeTextTracks` + * + * @param {Object} options + * The object should contain the options to intialize the TextTrack with. + * + * @param {string} [options.kind] + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata). + * + * @param {string} [options.label]. + * Label to identify the text track + * + * @param {string} [options.language] + * Two letter language abbreviation. + * + * @param {boolean} [options.default] + * Default this track to on. + * + * @param {string} [options.id] + * The internal id to assign this track. + * + * @param {string} [options.src] + * A source url for the track. + * + * @return {HTMLTrackElement} + * The track element that gets created. + */ + + + Html5.prototype.createRemoteTextTrack = function createRemoteTextTrack(options) { + if (!this.featuresNativeTextTracks) { + return _Tech.prototype.createRemoteTextTrack.call(this, options); + } + var htmlTrackElement = _document2['default'].createElement('track'); + + if (options.kind) { + htmlTrackElement.kind = options.kind; + } + if (options.label) { + htmlTrackElement.label = options.label; + } + if (options.language || options.srclang) { + htmlTrackElement.srclang = options.language || options.srclang; + } + if (options['default']) { + htmlTrackElement['default'] = options['default']; + } + if (options.id) { + htmlTrackElement.id = options.id; + } + if (options.src) { + htmlTrackElement.src = options.src; + } + + return htmlTrackElement; + }; + + /** + * Creates a remote text track object and returns an html track element. + * + * @param {Object} options The object should contain values for + * kind, language, label, and src (location of the WebVTT file) + * @param {Boolean} [manualCleanup=true] if set to false, the TextTrack will be + * automatically removed from the video element whenever the source changes + * @return {HTMLTrackElement} An Html Track Element. + * This can be an emulated {@link HTMLTrackElement} or a native one. + * @deprecated The default value of the "manualCleanup" parameter will default + * to "false" in upcoming versions of Video.js + */ + + + Html5.prototype.addRemoteTextTrack = function addRemoteTextTrack(options, manualCleanup) { + var htmlTrackElement = _Tech.prototype.addRemoteTextTrack.call(this, options, manualCleanup); + + if (this.featuresNativeTextTracks) { + this.el().appendChild(htmlTrackElement); + } + + return htmlTrackElement; + }; + + /** + * Remove remote `TextTrack` from `TextTrackList` object + * + * @param {TextTrack} track + * `TextTrack` object to remove + */ + + + Html5.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) { + _Tech.prototype.removeRemoteTextTrack.call(this, track); + + if (this.featuresNativeTextTracks) { + var tracks = this.$$('track'); + + var i = tracks.length; + + while (i--) { + if (track === tracks[i] || track === tracks[i].track) { + this.el().removeChild(tracks[i]); + } + } + } + }; + + /** + * Get the value of `playsinline` from the media element. `playsinline` indicates + * to the browser that non-fullscreen playback is preferred when fullscreen + * playback is the native default, such as in iOS Safari. + * + * @method Html5#playsinline + * @return {boolean} + * - The value of `playsinline` from the media element. + * - True indicates that the media should play inline. + * - False indicates that the media should not play inline. + * + * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline} + */ + + + Html5.prototype.playsinline = function playsinline() { + return this.el_.hasAttribute('playsinline'); + }; + + /** + * Set the value of `playsinline` from the media element. `playsinline` indicates + * to the browser that non-fullscreen playback is preferred when fullscreen + * playback is the native default, such as in iOS Safari. + * + * @method Html5#setPlaysinline + * @param {boolean} playsinline + * - True indicates that the media should play inline. + * - False indicates that the media should not play inline. + * + * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline} + */ + + + Html5.prototype.setPlaysinline = function setPlaysinline(value) { + if (value) { + this.el_.setAttribute('playsinline', 'playsinline'); + } else { + this.el_.removeAttribute('playsinline'); + } + }; + + /** + * Gets available media playback quality metrics as specified by the W3C's Media + * Playback Quality API. + * + * @see [Spec]{@link https://wicg.github.io/media-playback-quality} + * + * @return {Object} + * An object with supported media playback quality metrics + */ + + + Html5.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() { + if (typeof this.el().getVideoPlaybackQuality === 'function') { + return this.el().getVideoPlaybackQuality(); + } + + var videoPlaybackQuality = {}; + + if (typeof this.el().webkitDroppedFrameCount !== 'undefined' && typeof this.el().webkitDecodedFrameCount !== 'undefined') { + videoPlaybackQuality.droppedVideoFrames = this.el().webkitDroppedFrameCount; + videoPlaybackQuality.totalVideoFrames = this.el().webkitDecodedFrameCount; + } + + if (_window2['default'].performance && typeof _window2['default'].performance.now === 'function') { + videoPlaybackQuality.creationTime = _window2['default'].performance.now(); + } else if (_window2['default'].performance && _window2['default'].performance.timing && typeof _window2['default'].performance.timing.navigationStart === 'number') { + videoPlaybackQuality.creationTime = _window2['default'].Date.now() - _window2['default'].performance.timing.navigationStart; + } + + return videoPlaybackQuality; + }; + + return Html5; +}(_tech2['default']); + +/* HTML5 Support Testing ---------------------------------------------------- */ + +if (Dom.isReal()) { + + /** + * Element for testing browser HTML5 media capabilities + * + * @type {Element} + * @constant + * @private + */ + Html5.TEST_VID = _document2['default'].createElement('video'); + var track = _document2['default'].createElement('track'); + + track.kind = 'captions'; + track.srclang = 'en'; + track.label = 'English'; + Html5.TEST_VID.appendChild(track); +} + +/** + * Check if HTML5 media is supported by this browser/device. + * + * @return {boolean} + * - True if HTML5 media is supported. + * - False if HTML5 media is not supported. + */ +Html5.isSupported = function () { + // IE9 with no Media Player is a LIAR! (#984) + try { + Html5.TEST_VID.volume = 0.5; + } catch (e) { + return false; + } + + return !!(Html5.TEST_VID && Html5.TEST_VID.canPlayType); +}; + +/** + * Check if the volume can be changed in this browser/device. + * Volume cannot be changed in a lot of mobile devices. + * Specifically, it can't be changed from 1 on iOS. + * + * @return {boolean} + * - True if volume can be controlled + * - False otherwise + */ +Html5.canControlVolume = function () { + // IE will error if Windows Media Player not installed #3315 + try { + var volume = Html5.TEST_VID.volume; + + Html5.TEST_VID.volume = volume / 2 + 0.1; + return volume !== Html5.TEST_VID.volume; + } catch (e) { + return false; + } +}; + +/** + * Check if the playback rate can be changed in this browser/device. + * + * @return {boolean} + * - True if playback rate can be controlled + * - False otherwise + */ +Html5.canControlPlaybackRate = function () { + // Playback rate API is implemented in Android Chrome, but doesn't do anything + // https://github.com/videojs/video.js/issues/3180 + if (browser.IS_ANDROID && browser.IS_CHROME && browser.CHROME_VERSION < 58) { + return false; + } + // IE will error if Windows Media Player not installed #3315 + try { + var playbackRate = Html5.TEST_VID.playbackRate; + + Html5.TEST_VID.playbackRate = playbackRate / 2 + 0.1; + return playbackRate !== Html5.TEST_VID.playbackRate; + } catch (e) { + return false; + } +}; + +/** + * Check to see if native `TextTrack`s are supported by this browser/device. + * + * @return {boolean} + * - True if native `TextTrack`s are supported. + * - False otherwise + */ +Html5.supportsNativeTextTracks = function () { + return browser.IS_ANY_SAFARI; +}; + +/** + * Check to see if native `VideoTrack`s are supported by this browser/device + * + * @return {boolean} + * - True if native `VideoTrack`s are supported. + * - False otherwise + */ +Html5.supportsNativeVideoTracks = function () { + return !!(Html5.TEST_VID && Html5.TEST_VID.videoTracks); +}; + +/** + * Check to see if native `AudioTrack`s are supported by this browser/device + * + * @return {boolean} + * - True if native `AudioTrack`s are supported. + * - False otherwise + */ +Html5.supportsNativeAudioTracks = function () { + return !!(Html5.TEST_VID && Html5.TEST_VID.audioTracks); +}; + +/** + * An array of events available on the Html5 tech. + * + * @private + * @type {Array} + */ +Html5.Events = ['loadstart', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'seeking', 'seeked', 'ended', 'durationchange', 'timeupdate', 'progress', 'play', 'pause', 'ratechange', 'volumechange']; + +/** + * Boolean indicating whether the `Tech` supports volume control. + * + * @type {boolean} + * @default {@link Html5.canControlVolume} + */ +Html5.prototype.featuresVolumeControl = Html5.canControlVolume(); + +/** + * Boolean indicating whether the `Tech` supports changing the speed at which the media + * plays. Examples: + * - Set player to play 2x (twice) as fast + * - Set player to play 0.5x (half) as fast + * + * @type {boolean} + * @default {@link Html5.canControlPlaybackRate} + */ +Html5.prototype.featuresPlaybackRate = Html5.canControlPlaybackRate(); + +/** + * Boolean indicating whether the `HTML5` tech currently supports the media element + * moving in the DOM. iOS breaks if you move the media element, so this is set this to + * false there. Everywhere else this should be true. + * + * @type {boolean} + * @default + */ +Html5.prototype.movingMediaElementInDOM = !browser.IS_IOS; + +// TODO: Previous comment: No longer appears to be used. Can probably be removed. +// Is this true? +/** + * Boolean indicating whether the `HTML5` tech currently supports automatic media resize + * when going into fullscreen. + * + * @type {boolean} + * @default + */ +Html5.prototype.featuresFullscreenResize = true; + +/** + * Boolean indicating whether the `HTML5` tech currently supports the progress event. + * If this is false, manual `progress` events will be triggred instead. + * + * @type {boolean} + * @default + */ +Html5.prototype.featuresProgressEvents = true; + +/** + * Boolean indicating whether the `HTML5` tech currently supports the timeupdate event. + * If this is false, manual `timeupdate` events will be triggred instead. + * + * @default + */ +Html5.prototype.featuresTimeupdateEvents = true; + +/** + * Boolean indicating whether the `HTML5` tech currently supports native `TextTrack`s. + * + * @type {boolean} + * @default {@link Html5.supportsNativeTextTracks} + */ +Html5.prototype.featuresNativeTextTracks = Html5.supportsNativeTextTracks(); + +/** + * Boolean indicating whether the `HTML5` tech currently supports native `VideoTrack`s. + * + * @type {boolean} + * @default {@link Html5.supportsNativeVideoTracks} + */ +Html5.prototype.featuresNativeVideoTracks = Html5.supportsNativeVideoTracks(); + +/** + * Boolean indicating whether the `HTML5` tech currently supports native `AudioTrack`s. + * + * @type {boolean} + * @default {@link Html5.supportsNativeAudioTracks} + */ +Html5.prototype.featuresNativeAudioTracks = Html5.supportsNativeAudioTracks(); + +// HTML5 Feature detection and Device Fixes --------------------------------- // +var canPlayType = Html5.TEST_VID && Html5.TEST_VID.constructor.prototype.canPlayType; +var mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i; +var mp4RE = /^video\/mp4/i; + +Html5.patchCanPlayType = function () { + + // Android 4.0 and above can play HLS to some extent but it reports being unable to do so + if (browser.ANDROID_VERSION >= 4.0 && !browser.IS_FIREFOX) { + Html5.TEST_VID.constructor.prototype.canPlayType = function (type) { + if (type && mpegurlRE.test(type)) { + return 'maybe'; + } + return canPlayType.call(this, type); + }; + + // Override Android 2.2 and less canPlayType method which is broken + } else if (browser.IS_OLD_ANDROID) { + Html5.TEST_VID.constructor.prototype.canPlayType = function (type) { + if (type && mp4RE.test(type)) { + return 'maybe'; + } + return canPlayType.call(this, type); + }; + } +}; + +Html5.unpatchCanPlayType = function () { + var r = Html5.TEST_VID.constructor.prototype.canPlayType; + + Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType; + return r; +}; + +// by default, patch the media element +Html5.patchCanPlayType(); + +Html5.disposeMediaElement = function (el) { + if (!el) { + return; + } + + if (el.parentNode) { + el.parentNode.removeChild(el); + } + + // remove any child track or source nodes to prevent their loading + while (el.hasChildNodes()) { + el.removeChild(el.firstChild); + } + + // remove any src reference. not setting `src=''` because that causes a warning + // in firefox + el.removeAttribute('src'); + + // force the media element to update its loading state by calling load() + // however IE on Windows 7N has a bug that throws an error so need a try/catch (#793) + if (typeof el.load === 'function') { + // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473) + (function () { + try { + el.load(); + } catch (e) { + // not supported + } + })(); + } +}; + +Html5.resetMediaElement = function (el) { + if (!el) { + return; + } + + var sources = el.querySelectorAll('source'); + var i = sources.length; + + while (i--) { + el.removeChild(sources[i]); + } + + // remove any src reference. + // not setting `src=''` because that throws an error + el.removeAttribute('src'); + + if (typeof el.load === 'function') { + // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473) + (function () { + try { + el.load(); + } catch (e) { + // satisfy linter + } + })(); + } +}; + +/* Native HTML5 element property wrapping ----------------------------------- */ +// Wrap native properties with a getter +[ +/** + * Get the value of `paused` from the media element. `paused` indicates whether the media element + * is currently paused or not. + * + * @method Html5#paused + * @return {boolean} + * The value of `paused` from the media element. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-paused} + */ +'paused', + +/** + * Get the value of `currentTime` from the media element. `currentTime` indicates + * the current second that the media is at in playback. + * + * @method Html5#currentTime + * @return {number} + * The value of `currentTime` from the media element. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-currenttime} + */ +'currentTime', + +/** + * Get the value of `buffered` from the media element. `buffered` is a `TimeRange` + * object that represents the parts of the media that are already downloaded and + * available for playback. + * + * @method Html5#buffered + * @return {TimeRange} + * The value of `buffered` from the media element. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-buffered} + */ +'buffered', + +/** + * Get the value of `volume` from the media element. `volume` indicates + * the current playback volume of audio for a media. `volume` will be a value from 0 + * (silent) to 1 (loudest and default). + * + * @method Html5#volume + * @return {number} + * The value of `volume` from the media element. Value will be between 0-1. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume} + */ +'volume', + +/** + * Get the value of `muted` from the media element. `muted` indicates + * that the volume for the media should be set to silent. This does not actually change + * the `volume` attribute. + * + * @method Html5#muted + * @return {boolean} + * - True if the value of `volume` should be ignored and the audio set to silent. + * - False if the value of `volume` should be used. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted} + */ +'muted', + +/** + * Get the value of `poster` from the media element. `poster` indicates + * that the url of an image file that can/will be shown when no media data is available. + * + * @method Html5#poster + * @return {string} + * The value of `poster` from the media element. Value will be a url to an + * image. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-video-poster} + */ +'poster', + +/** + * Get the value of `preload` from the media element. `preload` indicates + * what should download before the media is interacted with. It can have the following + * values: + * - none: nothing should be downloaded + * - metadata: poster and the first few frames of the media may be downloaded to get + * media dimensions and other metadata + * - auto: allow the media and metadata for the media to be downloaded before + * interaction + * + * @method Html5#preload + * @return {string} + * The value of `preload` from the media element. Will be 'none', 'metadata', + * or 'auto'. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload} + */ +'preload', + +/** + * Get the value of `autoplay` from the media element. `autoplay` indicates + * that the media should start to play as soon as the page is ready. + * + * @method Html5#autoplay + * @return {boolean} + * - The value of `autoplay` from the media element. + * - True indicates that the media should start as soon as the page loads. + * - False indicates that the media should not start as soon as the page loads. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay} + */ +'autoplay', + +/** + * Get the value of `controls` from the media element. `controls` indicates + * whether the native media controls should be shown or hidden. + * + * @method Html5#controls + * @return {boolean} + * - The value of `controls` from the media element. + * - True indicates that native controls should be showing. + * - False indicates that native controls should be hidden. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-controls} + */ +'controls', + +/** + * Get the value of `loop` from the media element. `loop` indicates + * that the media should return to the start of the media and continue playing once + * it reaches the end. + * + * @method Html5#loop + * @return {boolean} + * - The value of `loop` from the media element. + * - True indicates that playback should seek back to start once + * the end of a media is reached. + * - False indicates that playback should not loop back to the start when the + * end of the media is reached. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop} + */ +'loop', + +/** + * Get the value of the `error` from the media element. `error` indicates any + * MediaError that may have occured during playback. If error returns null there is no + * current error. + * + * @method Html5#error + * @return {MediaError|null} + * The value of `error` from the media element. Will be `MediaError` if there + * is a current error and null otherwise. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-error} + */ +'error', + +/** + * Get the value of `seeking` from the media element. `seeking` indicates whether the + * media is currently seeking to a new position or not. + * + * @method Html5#seeking + * @return {boolean} + * - The value of `seeking` from the media element. + * - True indicates that the media is currently seeking to a new position. + * - Flase indicates that the media is not seeking to a new position at this time. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seeking} + */ +'seeking', + +/** + * Get the value of `seekable` from the media element. `seekable` returns a + * `TimeRange` object indicating ranges of time that can currently be `seeked` to. + * + * @method Html5#seekable + * @return {TimeRange} + * The value of `seekable` from the media element. A `TimeRange` object + * indicating the current ranges of time that can be seeked to. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seekable} + */ +'seekable', + +/** + * Get the value of `ended` from the media element. `ended` indicates whether + * the media has reached the end or not. + * + * @method Html5#ended + * @return {boolean} + * - The value of `ended` from the media element. + * - True indicates that the media has ended. + * - False indicates that the media has not ended. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended} + */ +'ended', + +/** + * Get the value of `defaultMuted` from the media element. `defaultMuted` indicates + * whether the media should start muted or not. Only changes the default state of the + * media. `muted` and `defaultMuted` can have different values. `muted` indicates the + * current state. + * + * @method Html5#defaultMuted + * @return {boolean} + * - The value of `defaultMuted` from the media element. + * - True indicates that the media should start muted. + * - False indicates that the media should not start muted + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted} + */ +'defaultMuted', + +/** + * Get the value of `playbackRate` from the media element. `playbackRate` indicates + * the rate at which the media is currently playing back. Examples: + * - if playbackRate is set to 2, media will play twice as fast. + * - if playbackRate is set to 0.5, media will play half as fast. + * + * @method Html5#playbackRate + * @return {number} + * The value of `playbackRate` from the media element. A number indicating + * the current playback speed of the media, where 1 is normal speed. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate} + */ +'playbackRate', + +/** + * Get the value of `played` from the media element. `played` returns a `TimeRange` + * object representing points in the media timeline that have been played. + * + * @method Html5#played + * @return {TimeRange} + * The value of `played` from the media element. A `TimeRange` object indicating + * the ranges of time that have been played. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-played} + */ +'played', + +/** + * Get the value of `networkState` from the media element. `networkState` indicates + * the current network state. It returns an enumeration from the following list: + * - 0: NETWORK_EMPTY + * - 1: NEWORK_IDLE + * - 2: NETWORK_LOADING + * - 3: NETWORK_NO_SOURCE + * + * @method Html5#networkState + * @return {number} + * The value of `networkState` from the media element. This will be a number + * from the list in the description. + * + * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-networkstate} + */ +'networkState', + +/** + * Get the value of `readyState` from the media element. `readyState` indicates + * the current state of the media element. It returns an enumeration from the + * following list: + * - 0: HAVE_NOTHING + * - 1: HAVE_METADATA + * - 2: HAVE_CURRENT_DATA + * - 3: HAVE_FUTURE_DATA + * - 4: HAVE_ENOUGH_DATA + * + * @method Html5#readyState + * @return {number} + * The value of `readyState` from the media element. This will be a number + * from the list in the description. + * + * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#ready-states} + */ +'readyState', + +/** + * Get the value of `videoWidth` from the video element. `videoWidth` indicates + * the current width of the video in css pixels. + * + * @method Html5#videoWidth + * @return {number} + * The value of `videoWidth` from the video element. This will be a number + * in css pixels. + * + * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth} + */ +'videoWidth', + +/** + * Get the value of `videoHeight` from the video element. `videoHeigth` indicates + * the current height of the video in css pixels. + * + * @method Html5#videoHeight + * @return {number} + * The value of `videoHeight` from the video element. This will be a number + * in css pixels. + * + * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth} + */ +'videoHeight'].forEach(function (prop) { + Html5.prototype[prop] = function () { + return this.el_[prop]; + }; +}); + +// Wrap native properties with a setter in this format: +// set + toTitleCase(name) +[ +/** + * Set the value of `volume` on the media element. `volume` indicates the current + * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and + * so on. + * + * @method Html5#setVolume + * @param {number} percentAsDecimal + * The volume percent as a decimal. Valid range is from 0-1. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume} + */ +'volume', + +/** + * Set the value of `muted` on the media element. `muted` indicates the current + * audio level should be silent. + * + * @method Html5#setMuted + * @param {boolean} muted + * - True if the audio should be set to silent + * - False otherwise + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted} + */ +'muted', + +/** + * Set the value of `src` on the media element. `src` indicates the current + * {@link Tech~SourceObject} for the media. + * + * @method Html5#setSrc + * @param {Tech~SourceObject} src + * The source object to set as the current source. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-src} + */ +'src', + +/** + * Set the value of `poster` on the media element. `poster` is the url to + * an image file that can/will be shown when no media data is available. + * + * @method Html5#setPoster + * @param {string} poster + * The url to an image that should be used as the `poster` for the media + * element. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-poster} + */ +'poster', + +/** + * Set the value of `preload` on the media element. `preload` indicates + * what should download before the media is interacted with. It can have the following + * values: + * - none: nothing should be downloaded + * - metadata: poster and the first few frames of the media may be downloaded to get + * media dimensions and other metadata + * - auto: allow the media and metadata for the media to be downloaded before + * interaction + * + * @method Html5#setPreload + * @param {string} preload + * The value of `preload` to set on the media element. Must be 'none', 'metadata', + * or 'auto'. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload} + */ +'preload', + +/** + * Set the value of `autoplay` on the media element. `autoplay` indicates + * that the media should start to play as soon as the page is ready. + * + * @method Html5#setAutoplay + * @param {boolean} autoplay + * - True indicates that the media should start as soon as the page loads. + * - False indicates that the media should not start as soon as the page loads. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay} + */ +'autoplay', + +/** + * Set the value of `loop` on the media element. `loop` indicates + * that the media should return to the start of the media and continue playing once + * it reaches the end. + * + * @method Html5#setLoop + * @param {boolean} loop + * - True indicates that playback should seek back to start once + * the end of a media is reached. + * - False indicates that playback should not loop back to the start when the + * end of the media is reached. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop} + */ +'loop', + +/** + * Set the value of `playbackRate` on the media element. `playbackRate` indicates + * the rate at which the media should play back. Examples: + * - if playbackRate is set to 2, media will play twice as fast. + * - if playbackRate is set to 0.5, media will play half as fast. + * + * @method Html5#setPlaybackRate + * @return {number} + * The value of `playbackRate` from the media element. A number indicating + * the current playback speed of the media, where 1 is normal speed. + * + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate} + */ +'playbackRate'].forEach(function (prop) { + Html5.prototype['set' + (0, _toTitleCase2['default'])(prop)] = function (v) { + this.el_[prop] = v; + }; +}); + +// wrap native functions with a function +[ +/** + * A wrapper around the media elements `pause` function. This will call the `HTML5` + * media elements `pause` function. + * + * @method Html5#pause + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-pause} + */ +'pause', + +/** + * A wrapper around the media elements `load` function. This will call the `HTML5`s + * media element `load` function. + * + * @method Html5#load + * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-load} + */ +'load'].forEach(function (prop) { + Html5.prototype[prop] = function () { + return this.el_[prop](); + }; +}); + +_tech2['default'].withSourceHandlers(Html5); + +/** + * Native source handler for Html5, simply passes the source to the media element. + * + * @proprety {Tech~SourceObject} source + * The source object + * + * @proprety {Html5} tech + * The instance of the HTML5 tech. + */ +Html5.nativeSourceHandler = {}; + +/** + * Check if the media element can play the given mime type. + * + * @param {string} type + * The mimetype to check + * + * @return {string} + * 'probably', 'maybe', or '' (empty string) + */ +Html5.nativeSourceHandler.canPlayType = function (type) { + // IE9 on Windows 7 without MediaPlayer throws an error here + // https://github.com/videojs/video.js/issues/519 + try { + return Html5.TEST_VID.canPlayType(type); + } catch (e) { + return ''; + } +}; + +/** + * Check if the media element can handle a source natively. + * + * @param {Tech~SourceObject} source + * The source object + * + * @param {Object} [options] + * Options to be passed to the tech. + * + * @return {string} + * 'probably', 'maybe', or '' (empty string). + */ +Html5.nativeSourceHandler.canHandleSource = function (source, options) { + + // If a type was provided we should rely on that + if (source.type) { + return Html5.nativeSourceHandler.canPlayType(source.type); + + // If no type, fall back to checking 'video/[EXTENSION]' + } else if (source.src) { + var ext = Url.getFileExtension(source.src); + + return Html5.nativeSourceHandler.canPlayType('video/' + ext); + } + + return ''; +}; + +/** + * Pass the source to the native media element. + * + * @param {Tech~SourceObject} source + * The source object + * + * @param {Html5} tech + * The instance of the Html5 tech + * + * @param {Object} [options] + * The options to pass to the source + */ +Html5.nativeSourceHandler.handleSource = function (source, tech, options) { + tech.setSrc(source.src); +}; + +/** + * A noop for the native dispose function, as cleanup is not needed. + */ +Html5.nativeSourceHandler.dispose = function () {}; + +// Register the native source handler +Html5.registerSourceHandler(Html5.nativeSourceHandler); + +_component2['default'].registerComponent('Html5', Html5); +_tech2['default'].registerTech('Html5', Html5); +exports['default'] = Html5; + +},{"5":5,"62":62,"78":78,"81":81,"83":83,"86":86,"87":87,"88":88,"91":91,"92":92,"94":94,"95":95,"98":98}],61:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _tech = _dereq_(62); + +var _tech2 = _interopRequireDefault(_tech); + +var _toTitleCase = _dereq_(91); + +var _toTitleCase2 = _interopRequireDefault(_toTitleCase); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file loader.js + */ + + +/** + * The `MediaLoader` is the `Component` that decides which playback technology to load + * when a player is initialized. + * + * @extends Component + */ +var MediaLoader = function (_Component) { + _inherits(MediaLoader, _Component); + + /** + * Create an instance of this class. + * + * @param {Player} player + * The `Player` that this class should attach to. + * + * @param {Object} [options] + * The key/value stroe of player options. + * + * @param {Component~ReadyCallback} [ready] + * The function that is run when this component is ready. + */ + function MediaLoader(player, options, ready) { + _classCallCheck(this, MediaLoader); + + // If there are no sources when the player is initialized, + // load the first supported playback technology. + + var _this = _possibleConstructorReturn(this, _Component.call(this, player, options, ready)); + + if (!options.playerOptions.sources || options.playerOptions.sources.length === 0) { + for (var i = 0, j = options.playerOptions.techOrder; i < j.length; i++) { + var techName = (0, _toTitleCase2['default'])(j[i]); + var tech = _tech2['default'].getTech(techName); + + // Support old behavior of techs being registered as components. + // Remove once that deprecated behavior is removed. + if (!techName) { + tech = _component2['default'].getComponent(techName); + } + + // Check if the browser supports this technology + if (tech && tech.isSupported()) { + player.loadTech_(techName); + break; + } + } + } else { + // Loop through playback technologies (HTML5, Flash) and check for support. + // Then load the best source. + // A few assumptions here: + // All playback technologies respect preload false. + player.src(options.playerOptions.sources); + } + return _this; + } + + return MediaLoader; +}(_component2['default']); + +_component2['default'].registerComponent('MediaLoader', MediaLoader); +exports['default'] = MediaLoader; + +},{"5":5,"62":62,"91":91}],62:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _htmlTrackElement = _dereq_(66); + +var _htmlTrackElement2 = _interopRequireDefault(_htmlTrackElement); + +var _htmlTrackElementList = _dereq_(65); + +var _htmlTrackElementList2 = _interopRequireDefault(_htmlTrackElementList); + +var _mergeOptions = _dereq_(87); + +var _mergeOptions2 = _interopRequireDefault(_mergeOptions); + +var _textTrack = _dereq_(72); + +var _textTrack2 = _interopRequireDefault(_textTrack); + +var _textTrackList = _dereq_(70); + +var _textTrackList2 = _interopRequireDefault(_textTrackList); + +var _videoTrackList = _dereq_(76); + +var _videoTrackList2 = _interopRequireDefault(_videoTrackList); + +var _audioTrackList = _dereq_(63); + +var _audioTrackList2 = _interopRequireDefault(_audioTrackList); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _log = _dereq_(86); + +var _log2 = _interopRequireDefault(_log); + +var _timeRanges = _dereq_(90); + +var _buffer = _dereq_(79); + +var _mediaError = _dereq_(46); + +var _mediaError2 = _interopRequireDefault(_mediaError); + +var _window = _dereq_(95); + +var _window2 = _interopRequireDefault(_window); + +var _document = _dereq_(94); + +var _document2 = _interopRequireDefault(_document); + +var _obj = _dereq_(88); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * @file tech.js + */ + +/** + * An Object containing a structure like: `{src: 'url', type: 'mimetype'}` or string + * that just contains the src url alone. + * * `var SourceObject = {src: 'http://ex.com/video.mp4', type: 'video/mp4'};` + * `var SourceString = 'http://example.com/some-video.mp4';` + * + * @typedef {Object|string} Tech~SourceObject + * + * @property {string} src + * The url to the source + * + * @property {string} type + * The mime type of the source + */ + +/** + * A function used by {@link Tech} to create a new {@link TextTrack}. + * + * @param {Tech} self + * An instance of the Tech class. + * + * @param {string} kind + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata) + * + * @param {string} [label] + * Label to identify the text track + * + * @param {string} [language] + * Two letter language abbreviation + * + * @param {Object} [options={}] + * An object with additional text track options + * + * @return {TextTrack} + * The text track that was created. + */ +function createTrackHelper(self, kind, label, language) { + var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; + + var tracks = self.textTracks(); + + options.kind = kind; + + if (label) { + options.label = label; + } + if (language) { + options.language = language; + } + options.tech = self; + + var track = new _textTrack2['default'](options); + + tracks.addTrack_(track); + + return track; +} + +/** + * This is the base class for media playback technology controllers, such as + * {@link Flash} and {@link HTML5} + * + * @extends Component + */ + +var Tech = function (_Component) { + _inherits(Tech, _Component); + + /** + * Create an instance of this Tech. + * + * @param {Object} [options] + * The key/value store of player options. + * + * @param {Component~ReadyCallback} ready + * Callback function to call when the `HTML5` Tech is ready. + */ + function Tech() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var ready = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {}; + + _classCallCheck(this, Tech); + + // we don't want the tech to report user activity automatically. + // This is done manually in addControlsListeners + options.reportTouchActivity = false; + + // keep track of whether the current source has played at all to + // implement a very limited played() + var _this = _possibleConstructorReturn(this, _Component.call(this, null, options, ready)); + + _this.hasStarted_ = false; + _this.on('playing', function () { + this.hasStarted_ = true; + }); + _this.on('loadstart', function () { + this.hasStarted_ = false; + }); + + _this.textTracks_ = options.textTracks; + _this.videoTracks_ = options.videoTracks; + _this.audioTracks_ = options.audioTracks; + + // Manually track progress in cases where the browser/flash player doesn't report it. + if (!_this.featuresProgressEvents) { + _this.manualProgressOn(); + } + + // Manually track timeupdates in cases where the browser/flash player doesn't report it. + if (!_this.featuresTimeupdateEvents) { + _this.manualTimeUpdatesOn(); + } + + ['Text', 'Audio', 'Video'].forEach(function (track) { + if (options['native' + track + 'Tracks'] === false) { + _this['featuresNative' + track + 'Tracks'] = false; + } + }); + + if (options.nativeCaptions === false) { + _this.featuresNativeTextTracks = false; + } + + if (!_this.featuresNativeTextTracks) { + _this.emulateTextTracks(); + } + + _this.autoRemoteTextTracks_ = new _textTrackList2['default'](); + + _this.initTextTrackListeners(); + _this.initTrackListeners(); + + // Turn on component tap events only if not using native controls + if (!options.nativeControlsForTouch) { + _this.emitTapEvents(); + } + + if (_this.constructor) { + _this.name_ = _this.constructor.name || 'Unknown Tech'; + } + return _this; + } + + /* Fallbacks for unsupported event types + ================================================================================ */ + + /** + * Polyfill the `progress` event for browsers that don't support it natively. + * + * @see {@link Tech#trackProgress} + */ + + + Tech.prototype.manualProgressOn = function manualProgressOn() { + this.on('durationchange', this.onDurationChange); + + this.manualProgress = true; + + // Trigger progress watching when a source begins loading + this.one('ready', this.trackProgress); + }; + + /** + * Turn off the polyfill for `progress` events that was created in + * {@link Tech#manualProgressOn} + */ + + + Tech.prototype.manualProgressOff = function manualProgressOff() { + this.manualProgress = false; + this.stopTrackingProgress(); + + this.off('durationchange', this.onDurationChange); + }; + + /** + * This is used to trigger a `progress` event when the buffered percent changes. It + * sets an interval function that will be called every 500 milliseconds to check if the + * buffer end percent has changed. + * + * > This function is called by {@link Tech#manualProgressOn} + * + * @param {EventTarget~Event} event + * The `ready` event that caused this to run. + * + * @listens Tech#ready + * @fires Tech#progress + */ + + + Tech.prototype.trackProgress = function trackProgress(event) { + this.stopTrackingProgress(); + this.progressInterval = this.setInterval(Fn.bind(this, function () { + // Don't trigger unless buffered amount is greater than last time + + var numBufferedPercent = this.bufferedPercent(); + + if (this.bufferedPercent_ !== numBufferedPercent) { + /** + * See {@link Player#progress} + * + * @event Tech#progress + * @type {EventTarget~Event} + */ + this.trigger('progress'); + } + + this.bufferedPercent_ = numBufferedPercent; + + if (numBufferedPercent === 1) { + this.stopTrackingProgress(); + } + }), 500); + }; + + /** + * Update our internal duration on a `durationchange` event by calling + * {@link Tech#duration}. + * + * @param {EventTarget~Event} event + * The `durationchange` event that caused this to run. + * + * @listens Tech#durationchange + */ + + + Tech.prototype.onDurationChange = function onDurationChange(event) { + this.duration_ = this.duration(); + }; + + /** + * Get and create a `TimeRange` object for buffering. + * + * @return {TimeRange} + * The time range object that was created. + */ + + + Tech.prototype.buffered = function buffered() { + return (0, _timeRanges.createTimeRange)(0, 0); + }; + + /** + * Get the percentage of the current video that is currently buffered. + * + * @return {number} + * A number from 0 to 1 that represents the decimal percentage of the + * video that is buffered. + * + */ + + + Tech.prototype.bufferedPercent = function bufferedPercent() { + return (0, _buffer.bufferedPercent)(this.buffered(), this.duration_); + }; + + /** + * Turn off the polyfill for `progress` events that was created in + * {@link Tech#manualProgressOn} + * Stop manually tracking progress events by clearing the interval that was set in + * {@link Tech#trackProgress}. + */ + + + Tech.prototype.stopTrackingProgress = function stopTrackingProgress() { + this.clearInterval(this.progressInterval); + }; + + /** + * Polyfill the `timeupdate` event for browsers that don't support it. + * + * @see {@link Tech#trackCurrentTime} + */ + + + Tech.prototype.manualTimeUpdatesOn = function manualTimeUpdatesOn() { + this.manualTimeUpdates = true; + + this.on('play', this.trackCurrentTime); + this.on('pause', this.stopTrackingCurrentTime); + }; + + /** + * Turn off the polyfill for `timeupdate` events that was created in + * {@link Tech#manualTimeUpdatesOn} + */ + + + Tech.prototype.manualTimeUpdatesOff = function manualTimeUpdatesOff() { + this.manualTimeUpdates = false; + this.stopTrackingCurrentTime(); + this.off('play', this.trackCurrentTime); + this.off('pause', this.stopTrackingCurrentTime); + }; + + /** + * Sets up an interval function to track current time and trigger `timeupdate` every + * 250 milliseconds. + * + * @listens Tech#play + * @triggers Tech#timeupdate + */ + + + Tech.prototype.trackCurrentTime = function trackCurrentTime() { + if (this.currentTimeInterval) { + this.stopTrackingCurrentTime(); + } + this.currentTimeInterval = this.setInterval(function () { + /** + * Triggered at an interval of 250ms to indicated that time is passing in the video. + * + * @event Tech#timeupdate + * @type {EventTarget~Event} + */ + this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); + + // 42 = 24 fps // 250 is what Webkit uses // FF uses 15 + }, 250); + }; + + /** + * Stop the interval function created in {@link Tech#trackCurrentTime} so that the + * `timeupdate` event is no longer triggered. + * + * @listens {Tech#pause} + */ + + + Tech.prototype.stopTrackingCurrentTime = function stopTrackingCurrentTime() { + this.clearInterval(this.currentTimeInterval); + + // #1002 - if the video ends right before the next timeupdate would happen, + // the progress bar won't make it all the way to the end + this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); + }; + + /** + * Turn off all event polyfills, clear the `Tech`s {@link AudioTrackList}, + * {@link VideoTrackList}, and {@link TextTrackList}, and dispose of this Tech. + * + * @fires Component#dispose + */ + + + Tech.prototype.dispose = function dispose() { + + // clear out all tracks because we can't reuse them between techs + this.clearTracks(['audio', 'video', 'text']); + + // Turn off any manual progress or timeupdate tracking + if (this.manualProgress) { + this.manualProgressOff(); + } + + if (this.manualTimeUpdates) { + this.manualTimeUpdatesOff(); + } + + _Component.prototype.dispose.call(this); + }; + + /** + * Clear out a single `TrackList` or an array of `TrackLists` given their names. + * + * > Note: Techs without source handlers should call this between sources for `video` + * & `audio` tracks. You don't want to use them between tracks! + * + * @param {string[]|string} types + * TrackList names to clear, valid names are `video`, `audio`, and + * `text`. + */ + + + Tech.prototype.clearTracks = function clearTracks(types) { + var _this2 = this; + + types = [].concat(types); + // clear out all tracks because we can't reuse them between techs + types.forEach(function (type) { + var list = _this2[type + 'Tracks']() || []; + var i = list.length; + + while (i--) { + var track = list[i]; + + if (type === 'text') { + _this2.removeRemoteTextTrack(track); + } + list.removeTrack_(track); + } + }); + }; + + /** + * Remove any TextTracks added via addRemoteTextTrack that are + * flagged for automatic garbage collection + */ + + + Tech.prototype.cleanupAutoTextTracks = function cleanupAutoTextTracks() { + var list = this.autoRemoteTextTracks_ || []; + var i = list.length; + + while (i--) { + var track = list[i]; + + this.removeRemoteTextTrack(track); + } + }; + + /** + * Reset the tech, which will removes all sources and reset the internal readyState. + * + * @abstract + */ + + + Tech.prototype.reset = function reset() {}; + + /** + * Get or set an error on the Tech. + * + * @param {MediaError} [err] + * Error to set on the Tech + * + * @return {MediaError|null} + * The current error object on the tech, or null if there isn't one. + */ + + + Tech.prototype.error = function error(err) { + if (err !== undefined) { + this.error_ = new _mediaError2['default'](err); + this.trigger('error'); + } + return this.error_; + }; + + /** + * Returns the `TimeRange`s that have been played through for the current source. + * + * > NOTE: This implementation is incomplete. It does not track the played `TimeRange`. + * It only checks wether the source has played at all or not. + * + * @return {TimeRange} + * - A single time range if this video has played + * - An empty set of ranges if not. + */ + + + Tech.prototype.played = function played() { + if (this.hasStarted_) { + return (0, _timeRanges.createTimeRange)(0, 0); + } + return (0, _timeRanges.createTimeRange)(); + }; + + /** + * Causes a manual time update to occur if {@link Tech#manualTimeUpdatesOn} was + * previously called. + * + * @fires Tech#timeupdate + */ + + + Tech.prototype.setCurrentTime = function setCurrentTime() { + // improve the accuracy of manual timeupdates + if (this.manualTimeUpdates) { + /** + * A manual `timeupdate` event. + * + * @event Tech#timeupdate + * @type {EventTarget~Event} + */ + this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true }); + } + }; + + /** + * Turn on listeners for {@link TextTrackList} events. This adds + * {@link EventTarget~EventListeners} for `texttrackchange`, `addtrack` and + * `removetrack`. + * + * @fires Tech#texttrackchange + */ + + + Tech.prototype.initTextTrackListeners = function initTextTrackListeners() { + var textTrackListChanges = Fn.bind(this, function () { + /** + * Triggered when tracks are added or removed on the Tech {@link TextTrackList} + * + * @event Tech#texttrackchange + * @type {EventTarget~Event} + */ + this.trigger('texttrackchange'); + }); + + var tracks = this.textTracks(); + + if (!tracks) { + return; + } + + tracks.addEventListener('removetrack', textTrackListChanges); + tracks.addEventListener('addtrack', textTrackListChanges); + + this.on('dispose', Fn.bind(this, function () { + tracks.removeEventListener('removetrack', textTrackListChanges); + tracks.removeEventListener('addtrack', textTrackListChanges); + })); + }; + + /** + * Turn on listeners for {@link VideoTrackList} and {@link {AudioTrackList} events. + * This adds {@link EventTarget~EventListeners} for `addtrack`, and `removetrack`. + * + * @fires Tech#audiotrackchange + * @fires Tech#videotrackchange + */ + + + Tech.prototype.initTrackListeners = function initTrackListeners() { + var _this3 = this; + + var trackTypes = ['video', 'audio']; + + trackTypes.forEach(function (type) { + /** + * Triggered when tracks are added or removed on the Tech {@link AudioTrackList} + * + * @event Tech#audiotrackchange + * @type {EventTarget~Event} + */ + + /** + * Triggered when tracks are added or removed on the Tech {@link VideoTrackList} + * + * @event Tech#videotrackchange + * @type {EventTarget~Event} + */ + var trackListChanges = function trackListChanges() { + _this3.trigger(type + 'trackchange'); + }; + + var tracks = _this3[type + 'Tracks'](); + + tracks.addEventListener('removetrack', trackListChanges); + tracks.addEventListener('addtrack', trackListChanges); + + _this3.on('dispose', function () { + tracks.removeEventListener('removetrack', trackListChanges); + tracks.removeEventListener('addtrack', trackListChanges); + }); + }); + }; + + /** + * Emulate TextTracks using vtt.js if necessary + * + * @fires Tech#vttjsloaded + * @fires Tech#vttjserror + */ + + + Tech.prototype.addWebVttScript_ = function addWebVttScript_() { + var _this4 = this; + + if (_window2['default'].WebVTT) { + return; + } + + // Initially, Tech.el_ is a child of a dummy-div wait until the Component system + // signals that the Tech is ready at which point Tech.el_ is part of the DOM + // before inserting the WebVTT script + if (_document2['default'].body.contains(this.el())) { + var vtt = _dereq_(99); + + // load via require if available and vtt.js script location was not passed in + // as an option. novtt builds will turn the above require call into an empty object + // which will cause this if check to always fail. + if (!this.options_['vtt.js'] && (0, _obj.isPlain)(vtt) && Object.keys(vtt).length > 0) { + this.trigger('vttjsloaded'); + return; + } + + // load vtt.js via the script location option or the cdn of no location was + // passed in + var script = _document2['default'].createElement('script'); + + script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.12.4/vtt.min.js'; + script.onload = function () { + /** + * Fired when vtt.js is loaded. + * + * @event Tech#vttjsloaded + * @type {EventTarget~Event} + */ + _this4.trigger('vttjsloaded'); + }; + script.onerror = function () { + /** + * Fired when vtt.js was not loaded due to an error + * + * @event Tech#vttjsloaded + * @type {EventTarget~Event} + */ + _this4.trigger('vttjserror'); + }; + this.on('dispose', function () { + script.onload = null; + script.onerror = null; + }); + // but have not loaded yet and we set it to true before the inject so that + // we don't overwrite the injected window.WebVTT if it loads right away + _window2['default'].WebVTT = true; + this.el().parentNode.appendChild(script); + } else { + this.ready(this.addWebVttScript_); + } + }; + + /** + * Emulate texttracks + * + * @method emulateTextTracks + */ + + + Tech.prototype.emulateTextTracks = function emulateTextTracks() { + var _this5 = this; + + var tracks = this.textTracks(); + + if (!tracks) { + return; + } + + var remoteTracks = this.remoteTextTracks(); + var handleAddTrack = function handleAddTrack(e) { + return tracks.addTrack_(e.track); + }; + var handleRemoveTrack = function handleRemoveTrack(e) { + return tracks.removeTrack_(e.track); + }; + + remoteTracks.on('addtrack', handleAddTrack); + remoteTracks.on('removetrack', handleRemoveTrack); + + this.addWebVttScript_(); + + var updateDisplay = function updateDisplay() { + return _this5.trigger('texttrackchange'); + }; + + var textTracksChanges = function textTracksChanges() { + updateDisplay(); + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + track.removeEventListener('cuechange', updateDisplay); + if (track.mode === 'showing') { + track.addEventListener('cuechange', updateDisplay); + } + } + }; + + textTracksChanges(); + tracks.addEventListener('change', textTracksChanges); + tracks.addEventListener('addtrack', textTracksChanges); + tracks.addEventListener('removetrack', textTracksChanges); + + this.on('dispose', function () { + remoteTracks.off('addtrack', handleAddTrack); + remoteTracks.off('removetrack', handleRemoveTrack); + tracks.removeEventListener('change', textTracksChanges); + tracks.removeEventListener('addtrack', textTracksChanges); + tracks.removeEventListener('removetrack', textTracksChanges); + + for (var i = 0; i < tracks.length; i++) { + var track = tracks[i]; + + track.removeEventListener('cuechange', updateDisplay); + } + }); + }; + + /** + * Get the `Tech`s {@link VideoTrackList}. + * + * @return {VideoTrackList} + * The video track list that the Tech is currently using. + */ + + + Tech.prototype.videoTracks = function videoTracks() { + this.videoTracks_ = this.videoTracks_ || new _videoTrackList2['default'](); + return this.videoTracks_; + }; + + /** + * Get the `Tech`s {@link AudioTrackList}. + * + * @return {AudioTrackList} + * The audio track list that the Tech is currently using. + */ + + + Tech.prototype.audioTracks = function audioTracks() { + this.audioTracks_ = this.audioTracks_ || new _audioTrackList2['default'](); + return this.audioTracks_; + }; + + /** + * Get the `Tech`s {@link TextTrackList}. + * + * @return {TextTrackList} + * The text track list that the Tech is currently using. + */ + + + Tech.prototype.textTracks = function textTracks() { + this.textTracks_ = this.textTracks_ || new _textTrackList2['default'](); + return this.textTracks_; + }; + + /** + * Get the `Tech`s remote {@link TextTrackList}, which is created from elements + * that were added to the DOM. + * + * @return {TextTrackList} + * The remote text track list that the Tech is currently using. + */ + + + Tech.prototype.remoteTextTracks = function remoteTextTracks() { + this.remoteTextTracks_ = this.remoteTextTracks_ || new _textTrackList2['default'](); + return this.remoteTextTracks_; + }; + + /** + * Get The `Tech`s {HTMLTrackElementList}, which are the elements in the DOM that are + * being used as TextTracks. + * + * @return {HTMLTrackElementList} + * The current HTML track elements that exist for the tech. + */ + + + Tech.prototype.remoteTextTrackEls = function remoteTextTrackEls() { + this.remoteTextTrackEls_ = this.remoteTextTrackEls_ || new _htmlTrackElementList2['default'](); + return this.remoteTextTrackEls_; + }; + + /** + * Create and returns a remote {@link TextTrack} object. + * + * @param {string} kind + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata) + * + * @param {string} [label] + * Label to identify the text track + * + * @param {string} [language] + * Two letter language abbreviation + * + * @return {TextTrack} + * The TextTrack that gets created. + */ + + + Tech.prototype.addTextTrack = function addTextTrack(kind, label, language) { + if (!kind) { + throw new Error('TextTrack kind is required but was not provided'); + } + + return createTrackHelper(this, kind, label, language); + }; + + /** + * Create an emulated TextTrack for use by addRemoteTextTrack + * + * This is intended to be overridden by classes that inherit from + * Tech in order to create native or custom TextTracks. + * + * @param {Object} options + * The object should contain the options to initialize the TextTrack with. + * + * @param {string} [options.kind] + * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata). + * + * @param {string} [options.label]. + * Label to identify the text track + * + * @param {string} [options.language] + * Two letter language abbreviation. + * + * @return {HTMLTrackElement} + * The track element that gets created. + */ + + + Tech.prototype.createRemoteTextTrack = function createRemoteTextTrack(options) { + var track = (0, _mergeOptions2['default'])(options, { + tech: this + }); + + return new _htmlTrackElement2['default'](track); + }; + + /** + * Creates a remote text track object and returns an html track element. + * + * > Note: This can be an emulated {@link HTMLTrackElement} or a native one. + * + * @param {Object} options + * See {@link Tech#createRemoteTextTrack} for more detailed properties. + * + * @param {boolean} [manualCleanup=true] + * - When false: the TextTrack will be automatically removed from the video + * element whenever the source changes + * - When True: The TextTrack will have to be cleaned up manually + * + * @return {HTMLTrackElement} + * An Html Track Element. + * + * @deprecated The default functionality for this function will be equivalent + * to "manualCleanup=false" in the future. The manualCleanup parameter will + * also be removed. + */ + + + Tech.prototype.addRemoteTextTrack = function addRemoteTextTrack() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + var manualCleanup = arguments[1]; + + var htmlTrackElement = this.createRemoteTextTrack(options); + + if (manualCleanup !== true && manualCleanup !== false) { + // deprecation warning + _log2['default'].warn('Calling addRemoteTextTrack without explicitly setting the "manualCleanup" parameter to `true` is deprecated and default to `false` in future version of video.js'); + manualCleanup = true; + } + + // store HTMLTrackElement and TextTrack to remote list + this.remoteTextTrackEls().addTrackElement_(htmlTrackElement); + this.remoteTextTracks().addTrack_(htmlTrackElement.track); + + if (manualCleanup !== true) { + // create the TextTrackList if it doesn't exist + this.autoRemoteTextTracks_.addTrack_(htmlTrackElement.track); + } + + return htmlTrackElement; + }; + + /** + * Remove a remote text track from the remote `TextTrackList`. + * + * @param {TextTrack} track + * `TextTrack` to remove from the `TextTrackList` + */ + + + Tech.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) { + var trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track); + + // remove HTMLTrackElement and TextTrack from remote list + this.remoteTextTrackEls().removeTrackElement_(trackElement); + this.remoteTextTracks().removeTrack_(track); + this.autoRemoteTextTracks_.removeTrack_(track); + }; + + /** + * Gets available media playback quality metrics as specified by the W3C's Media + * Playback Quality API. + * + * @see [Spec]{@link https://wicg.github.io/media-playback-quality} + * + * @return {Object} + * An object with supported media playback quality metrics + * + * @abstract + */ + + + Tech.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() { + return {}; + }; + + /** + * A method to set a poster from a `Tech`. + * + * @abstract + */ + + + Tech.prototype.setPoster = function setPoster() {}; + + /** + * A method to check for the presence of the 'playsinine' '; + a = div.firstChild; + // prevent the div from affecting layout + div.setAttribute('style', 'display:none; position:absolute;'); + _document2['default'].body.appendChild(div); + } + + // Copy the specific URL properties to a new object + // This is also needed for IE8 because the anchor loses its + // properties when it's removed from the dom + var details = {}; + + for (var i = 0; i < props.length; i++) { + details[props[i]] = a[props[i]]; + } + + // IE9 adds the port to the host property unlike everyone else. If + // a port identifier is added for standard ports, strip it. + if (details.protocol === 'http:') { + details.host = details.host.replace(/:80$/, ''); + } + + if (details.protocol === 'https:') { + details.host = details.host.replace(/:443$/, ''); + } + + if (addToBody) { + _document2['default'].body.removeChild(div); + } + + return details; +}; + +/** + * Get absolute version of relative URL. Used to tell flash correct URL. + * + * + * @param {string} url + * URL to make absolute + * + * @return {string} + * Absolute URL + * + * @see http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue + */ +var getAbsoluteURL = exports.getAbsoluteURL = function getAbsoluteURL(url) { + // Check if absolute URL + if (!url.match(/^https?:\/\//)) { + // Convert to absolute URL. Flash hosted off-site needs an absolute URL. + var div = _document2['default'].createElement('div'); + + div.innerHTML = 'x'; + url = div.firstChild.href; + } + + return url; +}; + +/** + * Returns the extension of the passed file name. It will return an empty string + * if passed an invalid path. + * + * @param {string} path + * The fileName path like '/path/to/file.mp4' + * + * @returns {string} + * The extension in lower case or an empty string if no + * extension could be found. + */ +var getFileExtension = exports.getFileExtension = function getFileExtension(path) { + if (typeof path === 'string') { + var splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/i; + var pathParts = splitPathRe.exec(path); + + if (pathParts) { + return pathParts.pop().toLowerCase(); + } + } + + return ''; +}; + +/** + * Returns whether the url passed is a cross domain request or not. + * + * @param {string} url + * The url to check. + * + * @return {boolean} + * Whether it is a cross domain request or not. + */ +var isCrossOrigin = exports.isCrossOrigin = function isCrossOrigin(url) { + var winLoc = _window2['default'].location; + var urlInfo = parseUrl(url); + + // IE8 protocol relative urls will return ':' for protocol + var srcProtocol = urlInfo.protocol === ':' ? winLoc.protocol : urlInfo.protocol; + + // Check if url is for another domain/origin + // IE8 doesn't know location.origin, so we won't rely on it here + var crossOrigin = srcProtocol + urlInfo.host !== winLoc.protocol + winLoc.host; + + return crossOrigin; +}; + +},{"94":94,"95":95}],93:[function(_dereq_,module,exports){ +'use strict'; + +exports.__esModule = true; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; /** + * @file video.js + * @module videojs + */ + +/* global define */ + +// Include the built-in techs + + +var _window = _dereq_(95); + +var _window2 = _interopRequireDefault(_window); + +var _document = _dereq_(94); + +var _document2 = _interopRequireDefault(_document); + +var _browser = _dereq_(78); + +var browser = _interopRequireWildcard(_browser); + +var _dom = _dereq_(81); + +var Dom = _interopRequireWildcard(_dom); + +var _setup = _dereq_(56); + +var setup = _interopRequireWildcard(_setup); + +var _stylesheet = _dereq_(89); + +var stylesheet = _interopRequireWildcard(_stylesheet); + +var _component = _dereq_(5); + +var _component2 = _interopRequireDefault(_component); + +var _eventTarget = _dereq_(42); + +var _eventTarget2 = _interopRequireDefault(_eventTarget); + +var _events = _dereq_(82); + +var Events = _interopRequireWildcard(_events); + +var _player = _dereq_(51); + +var _player2 = _interopRequireDefault(_player); + +var _plugins = _dereq_(52); + +var _plugins2 = _interopRequireDefault(_plugins); + +var _mergeOptions2 = _dereq_(87); + +var _mergeOptions3 = _interopRequireDefault(_mergeOptions2); + +var _fn = _dereq_(83); + +var Fn = _interopRequireWildcard(_fn); + +var _textTrack = _dereq_(72); + +var _textTrack2 = _interopRequireDefault(_textTrack); + +var _audioTrack = _dereq_(64); + +var _audioTrack2 = _interopRequireDefault(_audioTrack); + +var _videoTrack = _dereq_(77); + +var _videoTrack2 = _interopRequireDefault(_videoTrack); + +var _timeRanges = _dereq_(90); + +var _formatTime = _dereq_(84); + +var _formatTime2 = _interopRequireDefault(_formatTime); + +var _log = _dereq_(86); + +var _log2 = _interopRequireDefault(_log); + +var _url = _dereq_(92); + +var Url = _interopRequireWildcard(_url); + +var _obj = _dereq_(88); + +var _computedStyle = _dereq_(80); + +var _computedStyle2 = _interopRequireDefault(_computedStyle); + +var _extend = _dereq_(43); + +var _extend2 = _interopRequireDefault(_extend); + +var _xhr = _dereq_(104); + +var _xhr2 = _interopRequireDefault(_xhr); + +var _tech = _dereq_(62); + +var _tech2 = _interopRequireDefault(_tech); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + +// HTML5 Element Shim for IE8 +if (typeof HTMLVideoElement === 'undefined' && Dom.isReal()) { + _document2['default'].createElement('video'); + _document2['default'].createElement('audio'); + _document2['default'].createElement('track'); +} + +/** + * Doubles as the main function for users to create a player instance and also + * the main library object. + * The `videojs` function can be used to initialize or retrieve a player. + * + * @param {string|Element} id + * Video element or video element ID + * + * @param {Object} [options] + * Optional options object for config/settings + * + * @param {Component~ReadyCallback} [ready] + * Optional ready callback + * + * @return {Player} + * A player instance + * + * @mixes videojs + */ +function videojs(id, options, ready) { + var tag = void 0; + + // Allow for element or ID to be passed in + // String ID + if (typeof id === 'string') { + + // Adjust for jQuery ID syntax + if (id.indexOf('#') === 0) { + id = id.slice(1); + } + + // If a player instance has already been created for this ID return it. + if (videojs.getPlayers()[id]) { + + // If options or ready funtion are passed, warn + if (options) { + _log2['default'].warn('Player "' + id + '" is already initialised. Options will not be applied.'); + } + + if (ready) { + videojs.getPlayers()[id].ready(ready); + } + + return videojs.getPlayers()[id]; + } + + // Otherwise get element for ID + tag = Dom.getEl(id); + + // ID is a media element + } else { + tag = id; + } + + // Check for a useable element + // re: nodeName, could be a box div also + if (!tag || !tag.nodeName) { + throw new TypeError('The element or ID supplied is not valid. (videojs)'); + } + + // Element may have a player attr referring to an already created player instance. + // If so return that otherwise set up a new player below + if (tag.player || _player2['default'].players[tag.playerId]) { + return tag.player || _player2['default'].players[tag.playerId]; + } + + options = options || {}; + + videojs.hooks('beforesetup').forEach(function (hookFunction) { + var opts = hookFunction(tag, (0, _mergeOptions3['default'])(options)); + + if (!(0, _obj.isObject)(opts) || Array.isArray(opts)) { + _log2['default'].error('please return an object in beforesetup hooks'); + return; + } + + options = (0, _mergeOptions3['default'])(options, opts); + }); + + var PlayerComponent = _component2['default'].getComponent('Player'); + // If not, set up a new player + var player = new PlayerComponent(tag, options, ready); + + videojs.hooks('setup').forEach(function (hookFunction) { + return hookFunction(player); + }); + + return player; +} + +/** + * An Object that contains lifecycle hooks as keys which point to an array + * of functions that are run when a lifecycle is triggered + */ +videojs.hooks_ = {}; + +/** + * Get a list of hooks for a specific lifecycle + * + * @param {string} type + * the lifecyle to get hooks from + * + * @param {Function} [fn] + * Optionally add a hook to the lifecycle that your are getting. + * + * @return {Array} + * an array of hooks, or an empty array if there are none. + */ +videojs.hooks = function (type, fn) { + videojs.hooks_[type] = videojs.hooks_[type] || []; + if (fn) { + videojs.hooks_[type] = videojs.hooks_[type].concat(fn); + } + return videojs.hooks_[type]; +}; + +/** + * Add a function hook to a specific videojs lifecycle. + * + * @param {string} type + * the lifecycle to hook the function to. + * + * @param {Function|Function[]} + * The function or array of functions to attach. + */ +videojs.hook = function (type, fn) { + videojs.hooks(type, fn); +}; + +/** + * Remove a hook from a specific videojs lifecycle. + * + * @param {string} type + * the lifecycle that the function hooked to + * + * @param {Function} fn + * The hooked function to remove + * + * @return {boolean} + * The function that was removed or undef + */ +videojs.removeHook = function (type, fn) { + var index = videojs.hooks(type).indexOf(fn); + + if (index <= -1) { + return false; + } + + videojs.hooks_[type] = videojs.hooks_[type].slice(); + videojs.hooks_[type].splice(index, 1); + + return true; +}; + +// Add default styles +if (_window2['default'].VIDEOJS_NO_DYNAMIC_STYLE !== true && Dom.isReal()) { + var style = Dom.$('.vjs-styles-defaults'); + + if (!style) { + style = stylesheet.createStyleElement('vjs-styles-defaults'); + var head = Dom.$('head'); + + if (head) { + head.insertBefore(style, head.firstChild); + } + stylesheet.setTextContent(style, '\n .video-js {\n width: 300px;\n height: 150px;\n }\n\n .vjs-fluid {\n padding-top: 56.25%\n }\n '); + } +} + +// Run Auto-load players +// You have to wait at least once in case this script is loaded after your +// video in the DOM (weird behavior only with minified version) +setup.autoSetupTimeout(1, videojs); + +/** + * Current software version. Follows semver. + * + * @type {string} + */ +videojs.VERSION = '5.20.2'; + +/** + * The global options object. These are the settings that take effect + * if no overrides are specified when the player is created. + * + * @type {Object} + */ +videojs.options = _player2['default'].prototype.options_; + +/** + * Get an object with the currently created players, keyed by player ID + * + * @return {Object} + * The created players + */ +videojs.getPlayers = function () { + return _player2['default'].players; +}; + +/** + * Expose players object. + * + * @memberOf videojs + * @property {Object} players + */ +videojs.players = _player2['default'].players; + +/** + * Get a component class object by name + * + * @borrows Component.getComponent as videojs.getComponent + */ +videojs.getComponent = _component2['default'].getComponent; + +/** + * Register a component so it can referred to by name. Used when adding to other + * components, either through addChild `component.addChild('myComponent')` or through + * default children options `{ children: ['myComponent'] }`. + * + * > NOTE: You could also just initialize the component before adding. + * `component.addChild(new MyComponent());` + * + * @param {string} name + * The class name of the component + * + * @param {Component} comp + * The component class + * + * @return {Component} + * The newly registered component + */ +videojs.registerComponent = function (name, comp) { + if (_tech2['default'].isTech(comp)) { + _log2['default'].warn('The ' + name + ' tech was registered as a component. It should instead be registered using videojs.registerTech(name, tech)'); + } + + _component2['default'].registerComponent.call(_component2['default'], name, comp); +}; + +/** + * Get a Tech class object by name + * + * @borrows Tech.getTech as videojs.getTech + */ +videojs.getTech = _tech2['default'].getTech; + +/** + * Register a Tech so it can referred to by name. + * This is used in the tech order for the player. + * + * @borrows Tech.registerTech as videojs.registerTech + */ +videojs.registerTech = _tech2['default'].registerTech; + +/** + * A suite of browser and device tests from {@link browser}. + * + * @type {Object} + * @private + */ +videojs.browser = browser; + +/** + * Whether or not the browser supports touch events. Included for backward + * compatibility with 4.x, but deprecated. Use `videojs.browser.TOUCH_ENABLED` + * instead going forward. + * + * @deprecated since version 5.0 + * @type {boolean} + */ +videojs.TOUCH_ENABLED = browser.TOUCH_ENABLED; + +/** + * Subclass an existing class + * Mimics ES6 subclassing with the `extend` keyword + * + * @borrows extend:extendFn as videojs.extend + */ +videojs.extend = _extend2['default']; + +/** + * Merge two options objects recursively + * Performs a deep merge like lodash.merge but **only merges plain objects** + * (not arrays, elements, anything else) + * Other values will be copied directly from the second object. + * + * @borrows merge-options:mergeOptions as videojs.mergeOptions + */ +videojs.mergeOptions = _mergeOptions3['default']; + +/** + * Change the context (this) of a function + * + * > NOTE: as of v5.0 we require an ES5 shim, so you should use the native + * `function() {}.bind(newContext);` instead of this. + * + * @borrows fn:bind as videojs.bind + */ +videojs.bind = Fn.bind; + +/** + * Create a Video.js player plugin. + * Plugins are only initialized when options for the plugin are included + * in the player options, or the plugin function on the player instance is + * called. + * + * @borrows plugin:plugin as videojs.plugin + */ +videojs.plugin = _plugins2['default']; + +/** + * Adding languages so that they're available to all players. + * Example: `videojs.addLanguage('es', { 'Hello': 'Hola' });` + * + * @param {string} code + * The language code or dictionary property + * + * @param {Object} data + * The data values to be translated + * + * @return {Object} + * The resulting language dictionary object + */ +videojs.addLanguage = function (code, data) { + var _mergeOptions; + + code = ('' + code).toLowerCase(); + + videojs.options.languages = (0, _mergeOptions3['default'])(videojs.options.languages, (_mergeOptions = {}, _mergeOptions[code] = data, _mergeOptions)); + + return videojs.options.languages[code]; +}; + +/** + * Log messages + * + * @borrows log:log as videojs.log + */ +videojs.log = _log2['default']; + +/** + * Creates an emulated TimeRange object. + * + * @borrows time-ranges:createTimeRanges as videojs.createTimeRange + */ +/** + * @borrows time-ranges:createTimeRanges as videojs.createTimeRanges + */ +videojs.createTimeRange = videojs.createTimeRanges = _timeRanges.createTimeRanges; + +/** + * Format seconds as a time string, H:MM:SS or M:SS + * Supplying a guide (in seconds) will force a number of leading zeros + * to cover the length of the guide + * + * @borrows format-time:formatTime as videojs.formatTime + */ +videojs.formatTime = _formatTime2['default']; + +/** + * Resolve and parse the elements of a URL + * + * @borrows url:parseUrl as videojs.parseUrl + */ +videojs.parseUrl = Url.parseUrl; + +/** + * Returns whether the url passed is a cross domain request or not. + * + * @borrows url:isCrossOrigin as videojs.isCrossOrigin + */ +videojs.isCrossOrigin = Url.isCrossOrigin; + +/** + * Event target class. + * + * @borrows EventTarget as videojs.EventTarget + */ +videojs.EventTarget = _eventTarget2['default']; + +/** + * Add an event listener to element + * It stores the handler function in a separate cache object + * and adds a generic handler to the element's event, + * along with a unique id (guid) to the element. + * + * @borrows events:on as videojs.on + */ +videojs.on = Events.on; + +/** + * Trigger a listener only once for an event + * + * @borrows events:one as videojs.one + */ +videojs.one = Events.one; + +/** + * Removes event listeners from an element + * + * @borrows events:off as videojs.off + */ +videojs.off = Events.off; + +/** + * Trigger an event for an element + * + * @borrows events:trigger as videojs.trigger + */ +videojs.trigger = Events.trigger; + +/** + * A cross-browser XMLHttpRequest wrapper. Here's a simple example: + * + * @param {Object} options + * settings for the request. + * + * @return {XMLHttpRequest|XDomainRequest} + * The request object. + * + * @see https://github.com/Raynos/xhr + */ +videojs.xhr = _xhr2['default']; + +/** + * TextTrack class + * + * @borrows TextTrack as videojs.TextTrack + */ +videojs.TextTrack = _textTrack2['default']; + +/** + * export the AudioTrack class so that source handlers can create + * AudioTracks and then add them to the players AudioTrackList + * + * @borrows AudioTrack as videojs.AudioTrack + */ +videojs.AudioTrack = _audioTrack2['default']; + +/** + * export the VideoTrack class so that source handlers can create + * VideoTracks and then add them to the players VideoTrackList + * + * @borrows VideoTrack as videojs.VideoTrack + */ +videojs.VideoTrack = _videoTrack2['default']; + +/** + * Determines, via duck typing, whether or not a value is a DOM element. + * + * @borrows dom:isEl as videojs.isEl + */ +videojs.isEl = Dom.isEl; + +/** + * Determines, via duck typing, whether or not a value is a text node. + * + * @borrows dom:isTextNode as videojs.isTextNode + */ +videojs.isTextNode = Dom.isTextNode; + +/** + * Creates an element and applies properties. + * + * @borrows dom:createEl as videojs.createEl + */ +videojs.createEl = Dom.createEl; + +/** + * Check if an element has a CSS class + * + * @borrows dom:hasElClass as videojs.hasClass + */ +videojs.hasClass = Dom.hasElClass; + +/** + * Add a CSS class name to an element + * + * @borrows dom:addElClass as videojs.addClass + */ +videojs.addClass = Dom.addElClass; + +/** + * Remove a CSS class name from an element + * + * @borrows dom:removeElClass as videojs.removeClass + */ +videojs.removeClass = Dom.removeElClass; + +/** + * Adds or removes a CSS class name on an element depending on an optional + * condition or the presence/absence of the class name. + * + * @borrows dom:toggleElClass as videojs.toggleClass + */ +videojs.toggleClass = Dom.toggleElClass; + +/** + * Apply attributes to an HTML element. + * + * @borrows dom:setElAttributes as videojs.setAttribute + */ +videojs.setAttributes = Dom.setElAttributes; + +/** + * Get an element's attribute values, as defined on the HTML tag + * Attributes are not the same as properties. They're defined on the tag + * or with setAttribute (which shouldn't be used with HTML) + * This will return true or false for boolean attributes. + * + * @borrows dom:getElAttributes as videojs.getAttributes + */ +videojs.getAttributes = Dom.getElAttributes; + +/** + * Empties the contents of an element. + * + * @borrows dom:emptyEl as videojs.emptyEl + */ +videojs.emptyEl = Dom.emptyEl; + +/** + * Normalizes and appends content to an element. + * + * The content for an element can be passed in multiple types and + * combinations, whose behavior is as follows: + * + * - String + * Normalized into a text node. + * + * - Element, TextNode + * Passed through. + * + * - Array + * A one-dimensional array of strings, elements, nodes, or functions (which + * return single strings, elements, or nodes). + * + * - Function + * If the sole argument, is expected to produce a string, element, + * node, or array. + * + * @borrows dom:appendContents as videojs.appendContet + */ +videojs.appendContent = Dom.appendContent; + +/** + * Normalizes and inserts content into an element; this is identical to + * `appendContent()`, except it empties the element first. + * + * The content for an element can be passed in multiple types and + * combinations, whose behavior is as follows: + * + * - String + * Normalized into a text node. + * + * - Element, TextNode + * Passed through. + * + * - Array + * A one-dimensional array of strings, elements, nodes, or functions (which + * return single strings, elements, or nodes). + * + * - Function + * If the sole argument, is expected to produce a string, element, + * node, or array. + * + * @borrows dom:insertContent as videojs.insertContent + */ +videojs.insertContent = Dom.insertContent; + +/** + * A safe getComputedStyle with an IE8 fallback. + * + * This is because in Firefox, if the player is loaded in an iframe with `display:none`, + * then `getComputedStyle` returns `null`, so, we do a null-check to make sure + * that the player doesn't break in these cases. + * See https://bugzilla.mozilla.org/show_bug.cgi?id=548397 for more details. + * + * @borrows computed-style:computedStyle as videojs.computedStyle + */ +videojs.computedStyle = _computedStyle2['default']; + +/* + * Custom Universal Module Definition (UMD) + * + * Video.js will never be a non-browser lib so we can simplify UMD a bunch and + * still support requirejs and browserify. This also needs to be closure + * compiler compatible, so string keys are used. + */ +if (typeof define === 'function' && define.amd) { + define('videojs', [], function () { + return videojs; + }); + + // checking that module is an object too because of umdjs/umd#35 +} else if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object' && (typeof module === 'undefined' ? 'undefined' : _typeof(module)) === 'object') { + module.exports = videojs; +} + +exports['default'] = videojs; + +},{"104":104,"42":42,"43":43,"5":5,"51":51,"52":52,"56":56,"62":62,"64":64,"72":72,"77":77,"78":78,"80":80,"81":81,"82":82,"83":83,"84":84,"86":86,"87":87,"88":88,"89":89,"90":90,"92":92,"94":94,"95":95}],94:[function(_dereq_,module,exports){ +(function (global){ +var topLevel = typeof global !== 'undefined' ? global : + typeof window !== 'undefined' ? window : {} +var minDoc = _dereq_(96); + +if (typeof document !== 'undefined') { + module.exports = document; +} else { + var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; + + if (!doccy) { + doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; + } + + module.exports = doccy; +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"96":96}],95:[function(_dereq_,module,exports){ +(function (global){ +if (typeof window !== "undefined") { + module.exports = window; +} else if (typeof global !== "undefined") { + module.exports = global; +} else if (typeof self !== "undefined"){ + module.exports = self; +} else { + module.exports = {}; +} + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],96:[function(_dereq_,module,exports){ + +},{}],97:[function(_dereq_,module,exports){ +module.exports = SafeParseTuple + +function SafeParseTuple(obj, reviver) { + var json + var error = null + + try { + json = JSON.parse(obj, reviver) + } catch (err) { + error = err + } + + return [error, json] +} + +},{}],98:[function(_dereq_,module,exports){ +function clean (s) { + return s.replace(/\n\r?\s*/g, '') +} + + +module.exports = function tsml (sa) { + var s = '' + , i = 0 + + for (; i < arguments.length; i++) + s += clean(sa[i]) + (arguments[i + 1] || '') + + return s +} +},{}],99:[function(_dereq_,module,exports){ +/** + * Copyright 2013 vtt.js Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Default exports for Node. Export the extended versions of VTTCue and +// VTTRegion in Node since we likely want the capability to convert back and +// forth between JSON. If we don't then it's not that big of a deal since we're +// off browser. + +var window = _dereq_(103); + +var vttjs = module.exports = { + WebVTT: _dereq_(100), + VTTCue: _dereq_(101), + VTTRegion: _dereq_(102) +}; + +window.vttjs = vttjs; +window.WebVTT = vttjs.WebVTT; + +var cueShim = vttjs.VTTCue; +var regionShim = vttjs.VTTRegion; +var nativeVTTCue = window.VTTCue; +var nativeVTTRegion = window.VTTRegion; + +vttjs.shim = function() { + window.VTTCue = cueShim; + window.VTTRegion = regionShim; +}; + +vttjs.restore = function() { + window.VTTCue = nativeVTTCue; + window.VTTRegion = nativeVTTRegion; +}; + +if (!window.VTTCue) { + vttjs.shim(); +} + +},{"100":100,"101":101,"102":102,"103":103}],100:[function(_dereq_,module,exports){ +/** + * Copyright 2013 vtt.js Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +var _objCreate = Object.create || (function() { + function F() {} + return function(o) { + if (arguments.length !== 1) { + throw new Error('Object.create shim only accepts one parameter.'); + } + F.prototype = o; + return new F(); + }; +})(); + +// Creates a new ParserError object from an errorData object. The errorData +// object should have default code and message properties. The default message +// property can be overriden by passing in a message parameter. +// See ParsingError.Errors below for acceptable errors. +function ParsingError(errorData, message) { + this.name = "ParsingError"; + this.code = errorData.code; + this.message = message || errorData.message; +} +ParsingError.prototype = _objCreate(Error.prototype); +ParsingError.prototype.constructor = ParsingError; + +// ParsingError metadata for acceptable ParsingErrors. +ParsingError.Errors = { + BadSignature: { + code: 0, + message: "Malformed WebVTT signature." + }, + BadTimeStamp: { + code: 1, + message: "Malformed time stamp." + } +}; + +// Try to parse input as a time stamp. +function parseTimeStamp(input) { + + function computeSeconds(h, m, s, f) { + return (h | 0) * 3600 + (m | 0) * 60 + (s | 0) + (f | 0) / 1000; + } + + var m = input.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/); + if (!m) { + return null; + } + + if (m[3]) { + // Timestamp takes the form of [hours]:[minutes]:[seconds].[milliseconds] + return computeSeconds(m[1], m[2], m[3].replace(":", ""), m[4]); + } else if (m[1] > 59) { + // Timestamp takes the form of [hours]:[minutes].[milliseconds] + // First position is hours as it's over 59. + return computeSeconds(m[1], m[2], 0, m[4]); + } else { + // Timestamp takes the form of [minutes]:[seconds].[milliseconds] + return computeSeconds(0, m[1], m[2], m[4]); + } +} + +// A settings object holds key/value pairs and will ignore anything but the first +// assignment to a specific key. +function Settings() { + this.values = _objCreate(null); +} + +Settings.prototype = { + // Only accept the first assignment to any key. + set: function(k, v) { + if (!this.get(k) && v !== "") { + this.values[k] = v; + } + }, + // Return the value for a key, or a default value. + // If 'defaultKey' is passed then 'dflt' is assumed to be an object with + // a number of possible default values as properties where 'defaultKey' is + // the key of the property that will be chosen; otherwise it's assumed to be + // a single value. + get: function(k, dflt, defaultKey) { + if (defaultKey) { + return this.has(k) ? this.values[k] : dflt[defaultKey]; + } + return this.has(k) ? this.values[k] : dflt; + }, + // Check whether we have a value for a key. + has: function(k) { + return k in this.values; + }, + // Accept a setting if its one of the given alternatives. + alt: function(k, v, a) { + for (var n = 0; n < a.length; ++n) { + if (v === a[n]) { + this.set(k, v); + break; + } + } + }, + // Accept a setting if its a valid (signed) integer. + integer: function(k, v) { + if (/^-?\d+$/.test(v)) { // integer + this.set(k, parseInt(v, 10)); + } + }, + // Accept a setting if its a valid percentage. + percent: function(k, v) { + var m; + if ((m = v.match(/^([\d]{1,3})(\.[\d]*)?%$/))) { + v = parseFloat(v); + if (v >= 0 && v <= 100) { + this.set(k, v); + return true; + } + } + return false; + } +}; + +// Helper function to parse input into groups separated by 'groupDelim', and +// interprete each group as a key/value pair separated by 'keyValueDelim'. +function parseOptions(input, callback, keyValueDelim, groupDelim) { + var groups = groupDelim ? input.split(groupDelim) : [input]; + for (var i in groups) { + if (typeof groups[i] !== "string") { + continue; + } + var kv = groups[i].split(keyValueDelim); + if (kv.length !== 2) { + continue; + } + var k = kv[0]; + var v = kv[1]; + callback(k, v); + } +} + +function parseCue(input, cue, regionList) { + // Remember the original input if we need to throw an error. + var oInput = input; + // 4.1 WebVTT timestamp + function consumeTimeStamp() { + var ts = parseTimeStamp(input); + if (ts === null) { + throw new ParsingError(ParsingError.Errors.BadTimeStamp, + "Malformed timestamp: " + oInput); + } + // Remove time stamp from input. + input = input.replace(/^[^\sa-zA-Z-]+/, ""); + return ts; + } + + // 4.4.2 WebVTT cue settings + function consumeCueSettings(input, cue) { + var settings = new Settings(); + + parseOptions(input, function (k, v) { + switch (k) { + case "region": + // Find the last region we parsed with the same region id. + for (var i = regionList.length - 1; i >= 0; i--) { + if (regionList[i].id === v) { + settings.set(k, regionList[i].region); + break; + } + } + break; + case "vertical": + settings.alt(k, v, ["rl", "lr"]); + break; + case "line": + var vals = v.split(","), + vals0 = vals[0]; + settings.integer(k, vals0); + settings.percent(k, vals0) ? settings.set("snapToLines", false) : null; + settings.alt(k, vals0, ["auto"]); + if (vals.length === 2) { + settings.alt("lineAlign", vals[1], ["start", "middle", "end"]); + } + break; + case "position": + vals = v.split(","); + settings.percent(k, vals[0]); + if (vals.length === 2) { + settings.alt("positionAlign", vals[1], ["start", "middle", "end"]); + } + break; + case "size": + settings.percent(k, v); + break; + case "align": + settings.alt(k, v, ["start", "middle", "end", "left", "right"]); + break; + } + }, /:/, /\s/); + + // Apply default values for any missing fields. + cue.region = settings.get("region", null); + cue.vertical = settings.get("vertical", ""); + cue.line = settings.get("line", "auto"); + cue.lineAlign = settings.get("lineAlign", "start"); + cue.snapToLines = settings.get("snapToLines", true); + cue.size = settings.get("size", 100); + cue.align = settings.get("align", "middle"); + cue.position = settings.get("position", { + start: 0, + left: 0, + middle: 50, + end: 100, + right: 100 + }, cue.align); + cue.positionAlign = settings.get("positionAlign", { + start: "start", + left: "start", + middle: "middle", + end: "end", + right: "end" + }, cue.align); + } + + function skipWhitespace() { + input = input.replace(/^\s+/, ""); + } + + // 4.1 WebVTT cue timings. + skipWhitespace(); + cue.startTime = consumeTimeStamp(); // (1) collect cue start time + skipWhitespace(); + if (input.substr(0, 3) !== "-->") { // (3) next characters must match "-->" + throw new ParsingError(ParsingError.Errors.BadTimeStamp, + "Malformed time stamp (time stamps must be separated by '-->'): " + + oInput); + } + input = input.substr(3); + skipWhitespace(); + cue.endTime = consumeTimeStamp(); // (5) collect cue end time + + // 4.1 WebVTT cue settings list. + skipWhitespace(); + consumeCueSettings(input, cue); +} + +var ESCAPE = { + "&": "&", + "<": "<", + ">": ">", + "‎": "\u200e", + "‏": "\u200f", + " ": "\u00a0" +}; + +var TAG_NAME = { + c: "span", + i: "i", + b: "b", + u: "u", + ruby: "ruby", + rt: "rt", + v: "span", + lang: "span" +}; + +var TAG_ANNOTATION = { + v: "title", + lang: "lang" +}; + +var NEEDS_PARENT = { + rt: "ruby" +}; + +// Parse content into a document fragment. +function parseContent(window, input) { + function nextToken() { + // Check for end-of-string. + if (!input) { + return null; + } + + // Consume 'n' characters from the input. + function consume(result) { + input = input.substr(result.length); + return result; + } + + var m = input.match(/^([^<]*)(<[^>]+>?)?/); + // If there is some text before the next tag, return it, otherwise return + // the tag. + return consume(m[1] ? m[1] : m[2]); + } + + // Unescape a string 's'. + function unescape1(e) { + return ESCAPE[e]; + } + function unescape(s) { + while ((m = s.match(/&(amp|lt|gt|lrm|rlm|nbsp);/))) { + s = s.replace(m[0], unescape1); + } + return s; + } + + function shouldAdd(current, element) { + return !NEEDS_PARENT[element.localName] || + NEEDS_PARENT[element.localName] === current.localName; + } + + // Create an element for this tag. + function createElement(type, annotation) { + var tagName = TAG_NAME[type]; + if (!tagName) { + return null; + } + var element = window.document.createElement(tagName); + element.localName = tagName; + var name = TAG_ANNOTATION[type]; + if (name && annotation) { + element[name] = annotation.trim(); + } + return element; + } + + var rootDiv = window.document.createElement("div"), + current = rootDiv, + t, + tagStack = []; + + while ((t = nextToken()) !== null) { + if (t[0] === '<') { + if (t[1] === "/") { + // If the closing tag matches, move back up to the parent node. + if (tagStack.length && + tagStack[tagStack.length - 1] === t.substr(2).replace(">", "")) { + tagStack.pop(); + current = current.parentNode; + } + // Otherwise just ignore the end tag. + continue; + } + var ts = parseTimeStamp(t.substr(1, t.length - 2)); + var node; + if (ts) { + // Timestamps are lead nodes as well. + node = window.document.createProcessingInstruction("timestamp", ts); + current.appendChild(node); + continue; + } + var m = t.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/); + // If we can't parse the tag, skip to the next tag. + if (!m) { + continue; + } + // Try to construct an element, and ignore the tag if we couldn't. + node = createElement(m[1], m[3]); + if (!node) { + continue; + } + // Determine if the tag should be added based on the context of where it + // is placed in the cuetext. + if (!shouldAdd(current, node)) { + continue; + } + // Set the class list (as a list of classes, separated by space). + if (m[2]) { + node.className = m[2].substr(1).replace('.', ' '); + } + // Append the node to the current node, and enter the scope of the new + // node. + tagStack.push(m[1]); + current.appendChild(node); + current = node; + continue; + } + + // Text nodes are leaf nodes. + current.appendChild(window.document.createTextNode(unescape(t))); + } + + return rootDiv; +} + +// This is a list of all the Unicode characters that have a strong +// right-to-left category. What this means is that these characters are +// written right-to-left for sure. It was generated by pulling all the strong +// right-to-left characters out of the Unicode data table. That table can +// found at: http://www.unicode.org/Public/UNIDATA/UnicodeData.txt +var strongRTLRanges = [[0x5be, 0x5be], [0x5c0, 0x5c0], [0x5c3, 0x5c3], [0x5c6, 0x5c6], + [0x5d0, 0x5ea], [0x5f0, 0x5f4], [0x608, 0x608], [0x60b, 0x60b], [0x60d, 0x60d], + [0x61b, 0x61b], [0x61e, 0x64a], [0x66d, 0x66f], [0x671, 0x6d5], [0x6e5, 0x6e6], + [0x6ee, 0x6ef], [0x6fa, 0x70d], [0x70f, 0x710], [0x712, 0x72f], [0x74d, 0x7a5], + [0x7b1, 0x7b1], [0x7c0, 0x7ea], [0x7f4, 0x7f5], [0x7fa, 0x7fa], [0x800, 0x815], + [0x81a, 0x81a], [0x824, 0x824], [0x828, 0x828], [0x830, 0x83e], [0x840, 0x858], + [0x85e, 0x85e], [0x8a0, 0x8a0], [0x8a2, 0x8ac], [0x200f, 0x200f], + [0xfb1d, 0xfb1d], [0xfb1f, 0xfb28], [0xfb2a, 0xfb36], [0xfb38, 0xfb3c], + [0xfb3e, 0xfb3e], [0xfb40, 0xfb41], [0xfb43, 0xfb44], [0xfb46, 0xfbc1], + [0xfbd3, 0xfd3d], [0xfd50, 0xfd8f], [0xfd92, 0xfdc7], [0xfdf0, 0xfdfc], + [0xfe70, 0xfe74], [0xfe76, 0xfefc], [0x10800, 0x10805], [0x10808, 0x10808], + [0x1080a, 0x10835], [0x10837, 0x10838], [0x1083c, 0x1083c], [0x1083f, 0x10855], + [0x10857, 0x1085f], [0x10900, 0x1091b], [0x10920, 0x10939], [0x1093f, 0x1093f], + [0x10980, 0x109b7], [0x109be, 0x109bf], [0x10a00, 0x10a00], [0x10a10, 0x10a13], + [0x10a15, 0x10a17], [0x10a19, 0x10a33], [0x10a40, 0x10a47], [0x10a50, 0x10a58], + [0x10a60, 0x10a7f], [0x10b00, 0x10b35], [0x10b40, 0x10b55], [0x10b58, 0x10b72], + [0x10b78, 0x10b7f], [0x10c00, 0x10c48], [0x1ee00, 0x1ee03], [0x1ee05, 0x1ee1f], + [0x1ee21, 0x1ee22], [0x1ee24, 0x1ee24], [0x1ee27, 0x1ee27], [0x1ee29, 0x1ee32], + [0x1ee34, 0x1ee37], [0x1ee39, 0x1ee39], [0x1ee3b, 0x1ee3b], [0x1ee42, 0x1ee42], + [0x1ee47, 0x1ee47], [0x1ee49, 0x1ee49], [0x1ee4b, 0x1ee4b], [0x1ee4d, 0x1ee4f], + [0x1ee51, 0x1ee52], [0x1ee54, 0x1ee54], [0x1ee57, 0x1ee57], [0x1ee59, 0x1ee59], + [0x1ee5b, 0x1ee5b], [0x1ee5d, 0x1ee5d], [0x1ee5f, 0x1ee5f], [0x1ee61, 0x1ee62], + [0x1ee64, 0x1ee64], [0x1ee67, 0x1ee6a], [0x1ee6c, 0x1ee72], [0x1ee74, 0x1ee77], + [0x1ee79, 0x1ee7c], [0x1ee7e, 0x1ee7e], [0x1ee80, 0x1ee89], [0x1ee8b, 0x1ee9b], + [0x1eea1, 0x1eea3], [0x1eea5, 0x1eea9], [0x1eeab, 0x1eebb], [0x10fffd, 0x10fffd]]; + +function isStrongRTLChar(charCode) { + for (var i = 0; i < strongRTLRanges.length; i++) { + var currentRange = strongRTLRanges[i]; + if (charCode >= currentRange[0] && charCode <= currentRange[1]) { + return true; + } + } + + return false; +} + +function determineBidi(cueDiv) { + var nodeStack = [], + text = "", + charCode; + + if (!cueDiv || !cueDiv.childNodes) { + return "ltr"; + } + + function pushNodes(nodeStack, node) { + for (var i = node.childNodes.length - 1; i >= 0; i--) { + nodeStack.push(node.childNodes[i]); + } + } + + function nextTextNode(nodeStack) { + if (!nodeStack || !nodeStack.length) { + return null; + } + + var node = nodeStack.pop(), + text = node.textContent || node.innerText; + if (text) { + // TODO: This should match all unicode type B characters (paragraph + // separator characters). See issue #115. + var m = text.match(/^.*(\n|\r)/); + if (m) { + nodeStack.length = 0; + return m[0]; + } + return text; + } + if (node.tagName === "ruby") { + return nextTextNode(nodeStack); + } + if (node.childNodes) { + pushNodes(nodeStack, node); + return nextTextNode(nodeStack); + } + } + + pushNodes(nodeStack, cueDiv); + while ((text = nextTextNode(nodeStack))) { + for (var i = 0; i < text.length; i++) { + charCode = text.charCodeAt(i); + if (isStrongRTLChar(charCode)) { + return "rtl"; + } + } + } + return "ltr"; +} + +function computeLinePos(cue) { + if (typeof cue.line === "number" && + (cue.snapToLines || (cue.line >= 0 && cue.line <= 100))) { + return cue.line; + } + if (!cue.track || !cue.track.textTrackList || + !cue.track.textTrackList.mediaElement) { + return -1; + } + var track = cue.track, + trackList = track.textTrackList, + count = 0; + for (var i = 0; i < trackList.length && trackList[i] !== track; i++) { + if (trackList[i].mode === "showing") { + count++; + } + } + return ++count * -1; +} + +function StyleBox() { +} + +// Apply styles to a div. If there is no div passed then it defaults to the +// div on 'this'. +StyleBox.prototype.applyStyles = function(styles, div) { + div = div || this.div; + for (var prop in styles) { + if (styles.hasOwnProperty(prop)) { + div.style[prop] = styles[prop]; + } + } +}; + +StyleBox.prototype.formatStyle = function(val, unit) { + return val === 0 ? 0 : val + unit; +}; + +// Constructs the computed display state of the cue (a div). Places the div +// into the overlay which should be a block level element (usually a div). +function CueStyleBox(window, cue, styleOptions) { + var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent); + var color = "rgba(255, 255, 255, 1)"; + var backgroundColor = "rgba(0, 0, 0, 0.8)"; + + if (isIE8) { + color = "rgb(255, 255, 255)"; + backgroundColor = "rgb(0, 0, 0)"; + } + + StyleBox.call(this); + this.cue = cue; + + // Parse our cue's text into a DOM tree rooted at 'cueDiv'. This div will + // have inline positioning and will function as the cue background box. + this.cueDiv = parseContent(window, cue.text); + var styles = { + color: color, + backgroundColor: backgroundColor, + position: "relative", + left: 0, + right: 0, + top: 0, + bottom: 0, + display: "inline" + }; + + if (!isIE8) { + styles.writingMode = cue.vertical === "" ? "horizontal-tb" + : cue.vertical === "lr" ? "vertical-lr" + : "vertical-rl"; + styles.unicodeBidi = "plaintext"; + } + this.applyStyles(styles, this.cueDiv); + + // Create an absolutely positioned div that will be used to position the cue + // div. Note, all WebVTT cue-setting alignments are equivalent to the CSS + // mirrors of them except "middle" which is "center" in CSS. + this.div = window.document.createElement("div"); + styles = { + textAlign: cue.align === "middle" ? "center" : cue.align, + font: styleOptions.font, + whiteSpace: "pre-line", + position: "absolute" + }; + + if (!isIE8) { + styles.direction = determineBidi(this.cueDiv); + styles.writingMode = cue.vertical === "" ? "horizontal-tb" + : cue.vertical === "lr" ? "vertical-lr" + : "vertical-rl". + stylesunicodeBidi = "plaintext"; + } + + this.applyStyles(styles); + + this.div.appendChild(this.cueDiv); + + // Calculate the distance from the reference edge of the viewport to the text + // position of the cue box. The reference edge will be resolved later when + // the box orientation styles are applied. + var textPos = 0; + switch (cue.positionAlign) { + case "start": + textPos = cue.position; + break; + case "middle": + textPos = cue.position - (cue.size / 2); + break; + case "end": + textPos = cue.position - cue.size; + break; + } + + // Horizontal box orientation; textPos is the distance from the left edge of the + // area to the left edge of the box and cue.size is the distance extending to + // the right from there. + if (cue.vertical === "") { + this.applyStyles({ + left: this.formatStyle(textPos, "%"), + width: this.formatStyle(cue.size, "%") + }); + // Vertical box orientation; textPos is the distance from the top edge of the + // area to the top edge of the box and cue.size is the height extending + // downwards from there. + } else { + this.applyStyles({ + top: this.formatStyle(textPos, "%"), + height: this.formatStyle(cue.size, "%") + }); + } + + this.move = function(box) { + this.applyStyles({ + top: this.formatStyle(box.top, "px"), + bottom: this.formatStyle(box.bottom, "px"), + left: this.formatStyle(box.left, "px"), + right: this.formatStyle(box.right, "px"), + height: this.formatStyle(box.height, "px"), + width: this.formatStyle(box.width, "px") + }); + }; +} +CueStyleBox.prototype = _objCreate(StyleBox.prototype); +CueStyleBox.prototype.constructor = CueStyleBox; + +// Represents the co-ordinates of an Element in a way that we can easily +// compute things with such as if it overlaps or intersects with another Element. +// Can initialize it with either a StyleBox or another BoxPosition. +function BoxPosition(obj) { + var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent); + + // Either a BoxPosition was passed in and we need to copy it, or a StyleBox + // was passed in and we need to copy the results of 'getBoundingClientRect' + // as the object returned is readonly. All co-ordinate values are in reference + // to the viewport origin (top left). + var lh, height, width, top; + if (obj.div) { + height = obj.div.offsetHeight; + width = obj.div.offsetWidth; + top = obj.div.offsetTop; + + var rects = (rects = obj.div.childNodes) && (rects = rects[0]) && + rects.getClientRects && rects.getClientRects(); + obj = obj.div.getBoundingClientRect(); + // In certain cases the outter div will be slightly larger then the sum of + // the inner div's lines. This could be due to bold text, etc, on some platforms. + // In this case we should get the average line height and use that. This will + // result in the desired behaviour. + lh = rects ? Math.max((rects[0] && rects[0].height) || 0, obj.height / rects.length) + : 0; + + } + this.left = obj.left; + this.right = obj.right; + this.top = obj.top || top; + this.height = obj.height || height; + this.bottom = obj.bottom || (top + (obj.height || height)); + this.width = obj.width || width; + this.lineHeight = lh !== undefined ? lh : obj.lineHeight; + + if (isIE8 && !this.lineHeight) { + this.lineHeight = 13; + } +} + +// Move the box along a particular axis. Optionally pass in an amount to move +// the box. If no amount is passed then the default is the line height of the +// box. +BoxPosition.prototype.move = function(axis, toMove) { + toMove = toMove !== undefined ? toMove : this.lineHeight; + switch (axis) { + case "+x": + this.left += toMove; + this.right += toMove; + break; + case "-x": + this.left -= toMove; + this.right -= toMove; + break; + case "+y": + this.top += toMove; + this.bottom += toMove; + break; + case "-y": + this.top -= toMove; + this.bottom -= toMove; + break; + } +}; + +// Check if this box overlaps another box, b2. +BoxPosition.prototype.overlaps = function(b2) { + return this.left < b2.right && + this.right > b2.left && + this.top < b2.bottom && + this.bottom > b2.top; +}; + +// Check if this box overlaps any other boxes in boxes. +BoxPosition.prototype.overlapsAny = function(boxes) { + for (var i = 0; i < boxes.length; i++) { + if (this.overlaps(boxes[i])) { + return true; + } + } + return false; +}; + +// Check if this box is within another box. +BoxPosition.prototype.within = function(container) { + return this.top >= container.top && + this.bottom <= container.bottom && + this.left >= container.left && + this.right <= container.right; +}; + +// Check if this box is entirely within the container or it is overlapping +// on the edge opposite of the axis direction passed. For example, if "+x" is +// passed and the box is overlapping on the left edge of the container, then +// return true. +BoxPosition.prototype.overlapsOppositeAxis = function(container, axis) { + switch (axis) { + case "+x": + return this.left < container.left; + case "-x": + return this.right > container.right; + case "+y": + return this.top < container.top; + case "-y": + return this.bottom > container.bottom; + } +}; + +// Find the percentage of the area that this box is overlapping with another +// box. +BoxPosition.prototype.intersectPercentage = function(b2) { + var x = Math.max(0, Math.min(this.right, b2.right) - Math.max(this.left, b2.left)), + y = Math.max(0, Math.min(this.bottom, b2.bottom) - Math.max(this.top, b2.top)), + intersectArea = x * y; + return intersectArea / (this.height * this.width); +}; + +// Convert the positions from this box to CSS compatible positions using +// the reference container's positions. This has to be done because this +// box's positions are in reference to the viewport origin, whereas, CSS +// values are in referecne to their respective edges. +BoxPosition.prototype.toCSSCompatValues = function(reference) { + return { + top: this.top - reference.top, + bottom: reference.bottom - this.bottom, + left: this.left - reference.left, + right: reference.right - this.right, + height: this.height, + width: this.width + }; +}; + +// Get an object that represents the box's position without anything extra. +// Can pass a StyleBox, HTMLElement, or another BoxPositon. +BoxPosition.getSimpleBoxPosition = function(obj) { + var height = obj.div ? obj.div.offsetHeight : obj.tagName ? obj.offsetHeight : 0; + var width = obj.div ? obj.div.offsetWidth : obj.tagName ? obj.offsetWidth : 0; + var top = obj.div ? obj.div.offsetTop : obj.tagName ? obj.offsetTop : 0; + + obj = obj.div ? obj.div.getBoundingClientRect() : + obj.tagName ? obj.getBoundingClientRect() : obj; + var ret = { + left: obj.left, + right: obj.right, + top: obj.top || top, + height: obj.height || height, + bottom: obj.bottom || (top + (obj.height || height)), + width: obj.width || width + }; + return ret; +}; + +// Move a StyleBox to its specified, or next best, position. The containerBox +// is the box that contains the StyleBox, such as a div. boxPositions are +// a list of other boxes that the styleBox can't overlap with. +function moveBoxToLinePosition(window, styleBox, containerBox, boxPositions) { + + // Find the best position for a cue box, b, on the video. The axis parameter + // is a list of axis, the order of which, it will move the box along. For example: + // Passing ["+x", "-x"] will move the box first along the x axis in the positive + // direction. If it doesn't find a good position for it there it will then move + // it along the x axis in the negative direction. + function findBestPosition(b, axis) { + var bestPosition, + specifiedPosition = new BoxPosition(b), + percentage = 1; // Highest possible so the first thing we get is better. + + for (var i = 0; i < axis.length; i++) { + while (b.overlapsOppositeAxis(containerBox, axis[i]) || + (b.within(containerBox) && b.overlapsAny(boxPositions))) { + b.move(axis[i]); + } + // We found a spot where we aren't overlapping anything. This is our + // best position. + if (b.within(containerBox)) { + return b; + } + var p = b.intersectPercentage(containerBox); + // If we're outside the container box less then we were on our last try + // then remember this position as the best position. + if (percentage > p) { + bestPosition = new BoxPosition(b); + percentage = p; + } + // Reset the box position to the specified position. + b = new BoxPosition(specifiedPosition); + } + return bestPosition || specifiedPosition; + } + + var boxPosition = new BoxPosition(styleBox), + cue = styleBox.cue, + linePos = computeLinePos(cue), + axis = []; + + // If we have a line number to align the cue to. + if (cue.snapToLines) { + var size; + switch (cue.vertical) { + case "": + axis = [ "+y", "-y" ]; + size = "height"; + break; + case "rl": + axis = [ "+x", "-x" ]; + size = "width"; + break; + case "lr": + axis = [ "-x", "+x" ]; + size = "width"; + break; + } + + var step = boxPosition.lineHeight, + position = step * Math.round(linePos), + maxPosition = containerBox[size] + step, + initialAxis = axis[0]; + + // If the specified intial position is greater then the max position then + // clamp the box to the amount of steps it would take for the box to + // reach the max position. + if (Math.abs(position) > maxPosition) { + position = position < 0 ? -1 : 1; + position *= Math.ceil(maxPosition / step) * step; + } + + // If computed line position returns negative then line numbers are + // relative to the bottom of the video instead of the top. Therefore, we + // need to increase our initial position by the length or width of the + // video, depending on the writing direction, and reverse our axis directions. + if (linePos < 0) { + position += cue.vertical === "" ? containerBox.height : containerBox.width; + axis = axis.reverse(); + } + + // Move the box to the specified position. This may not be its best + // position. + boxPosition.move(initialAxis, position); + + } else { + // If we have a percentage line value for the cue. + var calculatedPercentage = (boxPosition.lineHeight / containerBox.height) * 100; + + switch (cue.lineAlign) { + case "middle": + linePos -= (calculatedPercentage / 2); + break; + case "end": + linePos -= calculatedPercentage; + break; + } + + // Apply initial line position to the cue box. + switch (cue.vertical) { + case "": + styleBox.applyStyles({ + top: styleBox.formatStyle(linePos, "%") + }); + break; + case "rl": + styleBox.applyStyles({ + left: styleBox.formatStyle(linePos, "%") + }); + break; + case "lr": + styleBox.applyStyles({ + right: styleBox.formatStyle(linePos, "%") + }); + break; + } + + axis = [ "+y", "-x", "+x", "-y" ]; + + // Get the box position again after we've applied the specified positioning + // to it. + boxPosition = new BoxPosition(styleBox); + } + + var bestPosition = findBestPosition(boxPosition, axis); + styleBox.move(bestPosition.toCSSCompatValues(containerBox)); +} + +function WebVTT() { + // Nothing +} + +// Helper to allow strings to be decoded instead of the default binary utf8 data. +WebVTT.StringDecoder = function() { + return { + decode: function(data) { + if (!data) { + return ""; + } + if (typeof data !== "string") { + throw new Error("Error - expected string data."); + } + return decodeURIComponent(encodeURIComponent(data)); + } + }; +}; + +WebVTT.convertCueToDOMTree = function(window, cuetext) { + if (!window || !cuetext) { + return null; + } + return parseContent(window, cuetext); +}; + +var FONT_SIZE_PERCENT = 0.05; +var FONT_STYLE = "sans-serif"; +var CUE_BACKGROUND_PADDING = "1.5%"; + +// Runs the processing model over the cues and regions passed to it. +// @param overlay A block level element (usually a div) that the computed cues +// and regions will be placed into. +WebVTT.processCues = function(window, cues, overlay) { + if (!window || !cues || !overlay) { + return null; + } + + // Remove all previous children. + while (overlay.firstChild) { + overlay.removeChild(overlay.firstChild); + } + + var paddedOverlay = window.document.createElement("div"); + paddedOverlay.style.position = "absolute"; + paddedOverlay.style.left = "0"; + paddedOverlay.style.right = "0"; + paddedOverlay.style.top = "0"; + paddedOverlay.style.bottom = "0"; + paddedOverlay.style.margin = CUE_BACKGROUND_PADDING; + overlay.appendChild(paddedOverlay); + + // Determine if we need to compute the display states of the cues. This could + // be the case if a cue's state has been changed since the last computation or + // if it has not been computed yet. + function shouldCompute(cues) { + for (var i = 0; i < cues.length; i++) { + if (cues[i].hasBeenReset || !cues[i].displayState) { + return true; + } + } + return false; + } + + // We don't need to recompute the cues' display states. Just reuse them. + if (!shouldCompute(cues)) { + for (var i = 0; i < cues.length; i++) { + paddedOverlay.appendChild(cues[i].displayState); + } + return; + } + + var boxPositions = [], + containerBox = BoxPosition.getSimpleBoxPosition(paddedOverlay), + fontSize = Math.round(containerBox.height * FONT_SIZE_PERCENT * 100) / 100; + var styleOptions = { + font: fontSize + "px " + FONT_STYLE + }; + + (function() { + var styleBox, cue; + + for (var i = 0; i < cues.length; i++) { + cue = cues[i]; + + // Compute the intial position and styles of the cue div. + styleBox = new CueStyleBox(window, cue, styleOptions); + paddedOverlay.appendChild(styleBox.div); + + // Move the cue div to it's correct line position. + moveBoxToLinePosition(window, styleBox, containerBox, boxPositions); + + // Remember the computed div so that we don't have to recompute it later + // if we don't have too. + cue.displayState = styleBox.div; + + boxPositions.push(BoxPosition.getSimpleBoxPosition(styleBox)); + } + })(); +}; + +WebVTT.Parser = function(window, vttjs, decoder) { + if (!decoder) { + decoder = vttjs; + vttjs = {}; + } + if (!vttjs) { + vttjs = {}; + } + + this.window = window; + this.vttjs = vttjs; + this.state = "INITIAL"; + this.buffer = ""; + this.decoder = decoder || new TextDecoder("utf8"); + this.regionList = []; +}; + +WebVTT.Parser.prototype = { + // If the error is a ParsingError then report it to the consumer if + // possible. If it's not a ParsingError then throw it like normal. + reportOrThrowError: function(e) { + if (e instanceof ParsingError) { + this.onparsingerror && this.onparsingerror(e); + } else { + throw e; + } + }, + parse: function (data) { + var self = this; + + // If there is no data then we won't decode it, but will just try to parse + // whatever is in buffer already. This may occur in circumstances, for + // example when flush() is called. + if (data) { + // Try to decode the data that we received. + self.buffer += self.decoder.decode(data, {stream: true}); + } + + function collectNextLine() { + var buffer = self.buffer; + var pos = 0; + while (pos < buffer.length && buffer[pos] !== '\r' && buffer[pos] !== '\n') { + ++pos; + } + var line = buffer.substr(0, pos); + // Advance the buffer early in case we fail below. + if (buffer[pos] === '\r') { + ++pos; + } + if (buffer[pos] === '\n') { + ++pos; + } + self.buffer = buffer.substr(pos); + return line; + } + + // 3.4 WebVTT region and WebVTT region settings syntax + function parseRegion(input) { + var settings = new Settings(); + + parseOptions(input, function (k, v) { + switch (k) { + case "id": + settings.set(k, v); + break; + case "width": + settings.percent(k, v); + break; + case "lines": + settings.integer(k, v); + break; + case "regionanchor": + case "viewportanchor": + var xy = v.split(','); + if (xy.length !== 2) { + break; + } + // We have to make sure both x and y parse, so use a temporary + // settings object here. + var anchor = new Settings(); + anchor.percent("x", xy[0]); + anchor.percent("y", xy[1]); + if (!anchor.has("x") || !anchor.has("y")) { + break; + } + settings.set(k + "X", anchor.get("x")); + settings.set(k + "Y", anchor.get("y")); + break; + case "scroll": + settings.alt(k, v, ["up"]); + break; + } + }, /=/, /\s/); + + // Create the region, using default values for any values that were not + // specified. + if (settings.has("id")) { + var region = new (self.vttjs.VTTRegion || self.window.VTTRegion)(); + region.width = settings.get("width", 100); + region.lines = settings.get("lines", 3); + region.regionAnchorX = settings.get("regionanchorX", 0); + region.regionAnchorY = settings.get("regionanchorY", 100); + region.viewportAnchorX = settings.get("viewportanchorX", 0); + region.viewportAnchorY = settings.get("viewportanchorY", 100); + region.scroll = settings.get("scroll", ""); + // Register the region. + self.onregion && self.onregion(region); + // Remember the VTTRegion for later in case we parse any VTTCues that + // reference it. + self.regionList.push({ + id: settings.get("id"), + region: region + }); + } + } + + // draft-pantos-http-live-streaming-20 + // https://tools.ietf.org/html/draft-pantos-http-live-streaming-20#section-3.5 + // 3.5 WebVTT + function parseTimestampMap(input) { + var settings = new Settings(); + + parseOptions(input, function(k, v) { + switch(k) { + case "MPEGT": + settings.integer(k + 'S', v); + break; + case "LOCA": + settings.set(k + 'L', parseTimeStamp(v)); + break; + } + }, /[^\d]:/, /,/); + + self.ontimestampmap && self.ontimestampmap({ + "MPEGTS": settings.get("MPEGTS"), + "LOCAL": settings.get("LOCAL") + }); + } + + // 3.2 WebVTT metadata header syntax + function parseHeader(input) { + if (input.match(/X-TIMESTAMP-MAP/)) { + // This line contains HLS X-TIMESTAMP-MAP metadata + parseOptions(input, function(k, v) { + switch(k) { + case "X-TIMESTAMP-MAP": + parseTimestampMap(v); + break; + } + }, /=/); + } else { + parseOptions(input, function (k, v) { + switch (k) { + case "Region": + // 3.3 WebVTT region metadata header syntax + parseRegion(v); + break; + } + }, /:/); + } + + } + + // 5.1 WebVTT file parsing. + try { + var line; + if (self.state === "INITIAL") { + // We can't start parsing until we have the first line. + if (!/\r\n|\n/.test(self.buffer)) { + return this; + } + + line = collectNextLine(); + + var m = line.match(/^WEBVTT([ \t].*)?$/); + if (!m || !m[0]) { + throw new ParsingError(ParsingError.Errors.BadSignature); + } + + self.state = "HEADER"; + } + + var alreadyCollectedLine = false; + while (self.buffer) { + // We can't parse a line until we have the full line. + if (!/\r\n|\n/.test(self.buffer)) { + return this; + } + + if (!alreadyCollectedLine) { + line = collectNextLine(); + } else { + alreadyCollectedLine = false; + } + + switch (self.state) { + case "HEADER": + // 13-18 - Allow a header (metadata) under the WEBVTT line. + if (/:/.test(line)) { + parseHeader(line); + } else if (!line) { + // An empty line terminates the header and starts the body (cues). + self.state = "ID"; + } + continue; + case "NOTE": + // Ignore NOTE blocks. + if (!line) { + self.state = "ID"; + } + continue; + case "ID": + // Check for the start of NOTE blocks. + if (/^NOTE($|[ \t])/.test(line)) { + self.state = "NOTE"; + break; + } + // 19-29 - Allow any number of line terminators, then initialize new cue values. + if (!line) { + continue; + } + self.cue = new (self.vttjs.VTTCue || self.window.VTTCue)(0, 0, ""); + self.state = "CUE"; + // 30-39 - Check if self line contains an optional identifier or timing data. + if (line.indexOf("-->") === -1) { + self.cue.id = line; + continue; + } + // Process line as start of a cue. + /*falls through*/ + case "CUE": + // 40 - Collect cue timings and settings. + try { + parseCue(line, self.cue, self.regionList); + } catch (e) { + self.reportOrThrowError(e); + // In case of an error ignore rest of the cue. + self.cue = null; + self.state = "BADCUE"; + continue; + } + self.state = "CUETEXT"; + continue; + case "CUETEXT": + var hasSubstring = line.indexOf("-->") !== -1; + // 34 - If we have an empty line then report the cue. + // 35 - If we have the special substring '-->' then report the cue, + // but do not collect the line as we need to process the current + // one as a new cue. + if (!line || hasSubstring && (alreadyCollectedLine = true)) { + // We are done parsing self cue. + self.oncue && self.oncue(self.cue); + self.cue = null; + self.state = "ID"; + continue; + } + if (self.cue.text) { + self.cue.text += "\n"; + } + self.cue.text += line; + continue; + case "BADCUE": // BADCUE + // 54-62 - Collect and discard the remaining cue. + if (!line) { + self.state = "ID"; + } + continue; + } + } + } catch (e) { + self.reportOrThrowError(e); + + // If we are currently parsing a cue, report what we have. + if (self.state === "CUETEXT" && self.cue && self.oncue) { + self.oncue(self.cue); + } + self.cue = null; + // Enter BADWEBVTT state if header was not parsed correctly otherwise + // another exception occurred so enter BADCUE state. + self.state = self.state === "INITIAL" ? "BADWEBVTT" : "BADCUE"; + } + return this; + }, + flush: function () { + var self = this; + try { + // Finish decoding the stream. + self.buffer += self.decoder.decode(); + // Synthesize the end of the current cue or region. + if (self.cue || self.state === "HEADER") { + self.buffer += "\n\n"; + self.parse(); + } + // If we've flushed, parsed, and we're still on the INITIAL state then + // that means we don't have enough of the stream to parse the first + // line. + if (self.state === "INITIAL") { + throw new ParsingError(ParsingError.Errors.BadSignature); + } + } catch(e) { + self.reportOrThrowError(e); + } + self.onflush && self.onflush(); + return this; + } +}; + +module.exports = WebVTT; + +},{}],101:[function(_dereq_,module,exports){ +/** + * Copyright 2013 vtt.js Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var autoKeyword = "auto"; +var directionSetting = { + "": true, + "lr": true, + "rl": true +}; +var alignSetting = { + "start": true, + "middle": true, + "end": true, + "left": true, + "right": true +}; + +function findDirectionSetting(value) { + if (typeof value !== "string") { + return false; + } + var dir = directionSetting[value.toLowerCase()]; + return dir ? value.toLowerCase() : false; +} + +function findAlignSetting(value) { + if (typeof value !== "string") { + return false; + } + var align = alignSetting[value.toLowerCase()]; + return align ? value.toLowerCase() : false; +} + +function extend(obj) { + var i = 1; + for (; i < arguments.length; i++) { + var cobj = arguments[i]; + for (var p in cobj) { + obj[p] = cobj[p]; + } + } + + return obj; +} + +function VTTCue(startTime, endTime, text) { + var cue = this; + var isIE8 = (/MSIE\s8\.0/).test(navigator.userAgent); + var baseObj = {}; + + if (isIE8) { + cue = document.createElement('custom'); + } else { + baseObj.enumerable = true; + } + + /** + * Shim implementation specific properties. These properties are not in + * the spec. + */ + + // Lets us know when the VTTCue's data has changed in such a way that we need + // to recompute its display state. This lets us compute its display state + // lazily. + cue.hasBeenReset = false; + + /** + * VTTCue and TextTrackCue properties + * http://dev.w3.org/html5/webvtt/#vttcue-interface + */ + + var _id = ""; + var _pauseOnExit = false; + var _startTime = startTime; + var _endTime = endTime; + var _text = text; + var _region = null; + var _vertical = ""; + var _snapToLines = true; + var _line = "auto"; + var _lineAlign = "start"; + var _position = 50; + var _positionAlign = "middle"; + var _size = 50; + var _align = "middle"; + + Object.defineProperty(cue, + "id", extend({}, baseObj, { + get: function() { + return _id; + }, + set: function(value) { + _id = "" + value; + } + })); + + Object.defineProperty(cue, + "pauseOnExit", extend({}, baseObj, { + get: function() { + return _pauseOnExit; + }, + set: function(value) { + _pauseOnExit = !!value; + } + })); + + Object.defineProperty(cue, + "startTime", extend({}, baseObj, { + get: function() { + return _startTime; + }, + set: function(value) { + if (typeof value !== "number") { + throw new TypeError("Start time must be set to a number."); + } + _startTime = value; + this.hasBeenReset = true; + } + })); + + Object.defineProperty(cue, + "endTime", extend({}, baseObj, { + get: function() { + return _endTime; + }, + set: function(value) { + if (typeof value !== "number") { + throw new TypeError("End time must be set to a number."); + } + _endTime = value; + this.hasBeenReset = true; + } + })); + + Object.defineProperty(cue, + "text", extend({}, baseObj, { + get: function() { + return _text; + }, + set: function(value) { + _text = "" + value; + this.hasBeenReset = true; + } + })); + + Object.defineProperty(cue, + "region", extend({}, baseObj, { + get: function() { + return _region; + }, + set: function(value) { + _region = value; + this.hasBeenReset = true; + } + })); + + Object.defineProperty(cue, + "vertical", extend({}, baseObj, { + get: function() { + return _vertical; + }, + set: function(value) { + var setting = findDirectionSetting(value); + // Have to check for false because the setting an be an empty string. + if (setting === false) { + throw new SyntaxError("An invalid or illegal string was specified."); + } + _vertical = setting; + this.hasBeenReset = true; + } + })); + + Object.defineProperty(cue, + "snapToLines", extend({}, baseObj, { + get: function() { + return _snapToLines; + }, + set: function(value) { + _snapToLines = !!value; + this.hasBeenReset = true; + } + })); + + Object.defineProperty(cue, + "line", extend({}, baseObj, { + get: function() { + return _line; + }, + set: function(value) { + if (typeof value !== "number" && value !== autoKeyword) { + throw new SyntaxError("An invalid number or illegal string was specified."); + } + _line = value; + this.hasBeenReset = true; + } + })); + + Object.defineProperty(cue, + "lineAlign", extend({}, baseObj, { + get: function() { + return _lineAlign; + }, + set: function(value) { + var setting = findAlignSetting(value); + if (!setting) { + throw new SyntaxError("An invalid or illegal string was specified."); + } + _lineAlign = setting; + this.hasBeenReset = true; + } + })); + + Object.defineProperty(cue, + "position", extend({}, baseObj, { + get: function() { + return _position; + }, + set: function(value) { + if (value < 0 || value > 100) { + throw new Error("Position must be between 0 and 100."); + } + _position = value; + this.hasBeenReset = true; + } + })); + + Object.defineProperty(cue, + "positionAlign", extend({}, baseObj, { + get: function() { + return _positionAlign; + }, + set: function(value) { + var setting = findAlignSetting(value); + if (!setting) { + throw new SyntaxError("An invalid or illegal string was specified."); + } + _positionAlign = setting; + this.hasBeenReset = true; + } + })); + + Object.defineProperty(cue, + "size", extend({}, baseObj, { + get: function() { + return _size; + }, + set: function(value) { + if (value < 0 || value > 100) { + throw new Error("Size must be between 0 and 100."); + } + _size = value; + this.hasBeenReset = true; + } + })); + + Object.defineProperty(cue, + "align", extend({}, baseObj, { + get: function() { + return _align; + }, + set: function(value) { + var setting = findAlignSetting(value); + if (!setting) { + throw new SyntaxError("An invalid or illegal string was specified."); + } + _align = setting; + this.hasBeenReset = true; + } + })); + + /** + * Other spec defined properties + */ + + // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-display-state + cue.displayState = undefined; + + if (isIE8) { + return cue; + } +} + +/** + * VTTCue methods + */ + +VTTCue.prototype.getCueAsHTML = function() { + // Assume WebVTT.convertCueToDOMTree is on the global. + return WebVTT.convertCueToDOMTree(window, this.text); +}; + +module.exports = VTTCue; + +},{}],102:[function(_dereq_,module,exports){ +/** + * Copyright 2013 vtt.js Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var scrollSetting = { + "": true, + "up": true +}; + +function findScrollSetting(value) { + if (typeof value !== "string") { + return false; + } + var scroll = scrollSetting[value.toLowerCase()]; + return scroll ? value.toLowerCase() : false; +} + +function isValidPercentValue(value) { + return typeof value === "number" && (value >= 0 && value <= 100); +} + +// VTTRegion shim http://dev.w3.org/html5/webvtt/#vttregion-interface +function VTTRegion() { + var _width = 100; + var _lines = 3; + var _regionAnchorX = 0; + var _regionAnchorY = 100; + var _viewportAnchorX = 0; + var _viewportAnchorY = 100; + var _scroll = ""; + + Object.defineProperties(this, { + "width": { + enumerable: true, + get: function() { + return _width; + }, + set: function(value) { + if (!isValidPercentValue(value)) { + throw new Error("Width must be between 0 and 100."); + } + _width = value; + } + }, + "lines": { + enumerable: true, + get: function() { + return _lines; + }, + set: function(value) { + if (typeof value !== "number") { + throw new TypeError("Lines must be set to a number."); + } + _lines = value; + } + }, + "regionAnchorY": { + enumerable: true, + get: function() { + return _regionAnchorY; + }, + set: function(value) { + if (!isValidPercentValue(value)) { + throw new Error("RegionAnchorX must be between 0 and 100."); + } + _regionAnchorY = value; + } + }, + "regionAnchorX": { + enumerable: true, + get: function() { + return _regionAnchorX; + }, + set: function(value) { + if(!isValidPercentValue(value)) { + throw new Error("RegionAnchorY must be between 0 and 100."); + } + _regionAnchorX = value; + } + }, + "viewportAnchorY": { + enumerable: true, + get: function() { + return _viewportAnchorY; + }, + set: function(value) { + if (!isValidPercentValue(value)) { + throw new Error("ViewportAnchorY must be between 0 and 100."); + } + _viewportAnchorY = value; + } + }, + "viewportAnchorX": { + enumerable: true, + get: function() { + return _viewportAnchorX; + }, + set: function(value) { + if (!isValidPercentValue(value)) { + throw new Error("ViewportAnchorX must be between 0 and 100."); + } + _viewportAnchorX = value; + } + }, + "scroll": { + enumerable: true, + get: function() { + return _scroll; + }, + set: function(value) { + var setting = findScrollSetting(value); + // Have to check for false as an empty string is a legal value. + if (setting === false) { + throw new SyntaxError("An invalid or illegal string was specified."); + } + _scroll = setting; + } + } + }); +} + +module.exports = VTTRegion; + +},{}],103:[function(_dereq_,module,exports){ +(function (global){ +var win; + +if (typeof window !== "undefined") { + win = window; +} else if (typeof global !== "undefined") { + win = global; +} else if (typeof self !== "undefined"){ + win = self; +} else { + win = {}; +} + +module.exports = win; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],104:[function(_dereq_,module,exports){ +"use strict"; +var window = _dereq_(95) +var isFunction = _dereq_(105) +var parseHeaders = _dereq_(108) +var xtend = _dereq_(109) + +module.exports = createXHR +createXHR.XMLHttpRequest = window.XMLHttpRequest || noop +createXHR.XDomainRequest = "withCredentials" in (new createXHR.XMLHttpRequest()) ? createXHR.XMLHttpRequest : window.XDomainRequest + +forEachArray(["get", "put", "post", "patch", "head", "delete"], function(method) { + createXHR[method === "delete" ? "del" : method] = function(uri, options, callback) { + options = initParams(uri, options, callback) + options.method = method.toUpperCase() + return _createXHR(options) + } +}) + +function forEachArray(array, iterator) { + for (var i = 0; i < array.length; i++) { + iterator(array[i]) + } +} + +function isEmpty(obj){ + for(var i in obj){ + if(obj.hasOwnProperty(i)) return false + } + return true +} + +function initParams(uri, options, callback) { + var params = uri + + if (isFunction(options)) { + callback = options + if (typeof uri === "string") { + params = {uri:uri} + } + } else { + params = xtend(options, {uri: uri}) + } + + params.callback = callback + return params +} + +function createXHR(uri, options, callback) { + options = initParams(uri, options, callback) + return _createXHR(options) +} + +function _createXHR(options) { + if(typeof options.callback === "undefined"){ + throw new Error("callback argument missing") + } + + var called = false + var callback = function cbOnce(err, response, body){ + if(!called){ + called = true + options.callback(err, response, body) + } + } + + function readystatechange() { + if (xhr.readyState === 4) { + loadFunc() + } + } + + function getBody() { + // Chrome with requestType=blob throws errors arround when even testing access to responseText + var body = undefined + + if (xhr.response) { + body = xhr.response + } else { + body = xhr.responseText || getXml(xhr) + } + + if (isJson) { + try { + body = JSON.parse(body) + } catch (e) {} + } + + return body + } + + var failureResponse = { + body: undefined, + headers: {}, + statusCode: 0, + method: method, + url: uri, + rawRequest: xhr + } + + function errorFunc(evt) { + clearTimeout(timeoutTimer) + if(!(evt instanceof Error)){ + evt = new Error("" + (evt || "Unknown XMLHttpRequest Error") ) + } + evt.statusCode = 0 + return callback(evt, failureResponse) + } + + // will load the data & process the response in a special response object + function loadFunc() { + if (aborted) return + var status + clearTimeout(timeoutTimer) + if(options.useXDR && xhr.status===undefined) { + //IE8 CORS GET successful response doesn't have a status field, but body is fine + status = 200 + } else { + status = (xhr.status === 1223 ? 204 : xhr.status) + } + var response = failureResponse + var err = null + + if (status !== 0){ + response = { + body: getBody(), + statusCode: status, + method: method, + headers: {}, + url: uri, + rawRequest: xhr + } + if(xhr.getAllResponseHeaders){ //remember xhr can in fact be XDR for CORS in IE + response.headers = parseHeaders(xhr.getAllResponseHeaders()) + } + } else { + err = new Error("Internal XMLHttpRequest Error") + } + return callback(err, response, response.body) + } + + var xhr = options.xhr || null + + if (!xhr) { + if (options.cors || options.useXDR) { + xhr = new createXHR.XDomainRequest() + }else{ + xhr = new createXHR.XMLHttpRequest() + } + } + + var key + var aborted + var uri = xhr.url = options.uri || options.url + var method = xhr.method = options.method || "GET" + var body = options.body || options.data || null + var headers = xhr.headers = options.headers || {} + var sync = !!options.sync + var isJson = false + var timeoutTimer + + if ("json" in options) { + isJson = true + headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json") //Don't override existing accept header declared by user + if (method !== "GET" && method !== "HEAD") { + headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json") //Don't override existing accept header declared by user + body = JSON.stringify(options.json) + } + } + + xhr.onreadystatechange = readystatechange + xhr.onload = loadFunc + xhr.onerror = errorFunc + // IE9 must have onprogress be set to a unique function. + xhr.onprogress = function () { + // IE must die + } + xhr.ontimeout = errorFunc + xhr.open(method, uri, !sync, options.username, options.password) + //has to be after open + if(!sync) { + xhr.withCredentials = !!options.withCredentials + } + // Cannot set timeout with sync request + // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly + // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent + if (!sync && options.timeout > 0 ) { + timeoutTimer = setTimeout(function(){ + aborted=true//IE9 may still call readystatechange + xhr.abort("timeout") + var e = new Error("XMLHttpRequest timeout") + e.code = "ETIMEDOUT" + errorFunc(e) + }, options.timeout ) + } + + if (xhr.setRequestHeader) { + for(key in headers){ + if(headers.hasOwnProperty(key)){ + xhr.setRequestHeader(key, headers[key]) + } + } + } else if (options.headers && !isEmpty(options.headers)) { + throw new Error("Headers cannot be set on an XDomainRequest object") + } + + if ("responseType" in options) { + xhr.responseType = options.responseType + } + + if ("beforeSend" in options && + typeof options.beforeSend === "function" + ) { + options.beforeSend(xhr) + } + + xhr.send(body) + + return xhr + + +} + +function getXml(xhr) { + if (xhr.responseType === "document") { + return xhr.responseXML + } + var firefoxBugTakenEffect = xhr.status === 204 && xhr.responseXML && xhr.responseXML.documentElement.nodeName === "parsererror" + if (xhr.responseType === "" && !firefoxBugTakenEffect) { + return xhr.responseXML + } + + return null +} + +function noop() {} + +},{"105":105,"108":108,"109":109,"95":95}],105:[function(_dereq_,module,exports){ +module.exports = isFunction + +var toString = Object.prototype.toString + +function isFunction (fn) { + var string = toString.call(fn) + return string === '[object Function]' || + (typeof fn === 'function' && string !== '[object RegExp]') || + (typeof window !== 'undefined' && + // IE8 and below + (fn === window.setTimeout || + fn === window.alert || + fn === window.confirm || + fn === window.prompt)) +}; + +},{}],106:[function(_dereq_,module,exports){ +var isFunction = _dereq_(105) + +module.exports = forEach + +var toString = Object.prototype.toString +var hasOwnProperty = Object.prototype.hasOwnProperty + +function forEach(list, iterator, context) { + if (!isFunction(iterator)) { + throw new TypeError('iterator must be a function') + } + + if (arguments.length < 3) { + context = this + } + + if (toString.call(list) === '[object Array]') + forEachArray(list, iterator, context) + else if (typeof list === 'string') + forEachString(list, iterator, context) + else + forEachObject(list, iterator, context) +} + +function forEachArray(array, iterator, context) { + for (var i = 0, len = array.length; i < len; i++) { + if (hasOwnProperty.call(array, i)) { + iterator.call(context, array[i], i, array) + } + } +} + +function forEachString(string, iterator, context) { + for (var i = 0, len = string.length; i < len; i++) { + // no such thing as a sparse string. + iterator.call(context, string.charAt(i), i, string) + } +} + +function forEachObject(object, iterator, context) { + for (var k in object) { + if (hasOwnProperty.call(object, k)) { + iterator.call(context, object[k], k, object) + } + } +} + +},{"105":105}],107:[function(_dereq_,module,exports){ + +exports = module.exports = trim; + +function trim(str){ + return str.replace(/^\s*|\s*$/g, ''); +} + +exports.left = function(str){ + return str.replace(/^\s*/, ''); +}; + +exports.right = function(str){ + return str.replace(/\s*$/, ''); +}; + +},{}],108:[function(_dereq_,module,exports){ +var trim = _dereq_(107) + , forEach = _dereq_(106) + , isArray = function(arg) { + return Object.prototype.toString.call(arg) === '[object Array]'; + } + +module.exports = function (headers) { + if (!headers) + return {} + + var result = {} + + forEach( + trim(headers).split('\n') + , function (row) { + var index = row.indexOf(':') + , key = trim(row.slice(0, index)).toLowerCase() + , value = trim(row.slice(index + 1)) + + if (typeof(result[key]) === 'undefined') { + result[key] = value + } else if (isArray(result[key])) { + result[key].push(value) + } else { + result[key] = [ result[key], value ] + } + } + ) + + return result +} +},{"106":106,"107":107}],109:[function(_dereq_,module,exports){ +module.exports = extend + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +function extend() { + var target = {} + + for (var i = 0; i < arguments.length; i++) { + var source = arguments[i] + + for (var key in source) { + if (hasOwnProperty.call(source, key)) { + target[key] = source[key] + } + } + } + + return target +} + +},{}]},{},[93])(93) +}); \ No newline at end of file -- 2.39.5