mediaelement
Advanced tools
Comparing version 5.1.1 to 6.0.0
@@ -0,0 +0,0 @@ /*! |
@@ -0,0 +0,0 @@ /*! |
@@ -0,0 +0,0 @@ /*! |
@@ -0,0 +0,0 @@ /*! |
@@ -0,0 +0,0 @@ /*! |
@@ -66,3 +66,3 @@ /*! | ||
mejs.version = '5.1.1'; | ||
mejs.version = '6.0.0'; | ||
@@ -69,0 +69,0 @@ mejs.html5media = { |
@@ -12,2 +12,2 @@ /*! | ||
*/ | ||
!function o(i,u,s){function l(r,e){if(!u[r]){if(!i[r]){var t="function"==typeof require&&require;if(!e&&t)return t(r,!0);if(d)return d(r,!0);var n=new Error("Cannot find module '"+r+"'");throw n.code="MODULE_NOT_FOUND",n}var a=u[r]={exports:{}};i[r][0].call(a.exports,function(e){var t=i[r][1][e];return l(t||e)},a,a.exports,o,i,u,s)}return u[r].exports}for(var d="function"==typeof require&&require,e=0;e<s.length;e++)l(s[e]);return l}({1:[function(e,t,r){},{}],2:[function(a,o,e){(function(e){var t,r=void 0!==e?e:"undefined"!=typeof window?window:{},n=a(1);"undefined"!=typeof document?t=document:(t=r["__GLOBAL_DOCUMENT_CACHE@4"])||(t=r["__GLOBAL_DOCUMENT_CACHE@4"]=n),o.exports=t}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{1:1}],3:[function(e,r,t){(function(e){var t;t="undefined"!=typeof window?window:void 0!==e?e:"undefined"!=typeof self?self:{},r.exports=t}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],4:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n,a=e(3);var o={version:"5.1.1",html5media:{properties:["volume","src","currentTime","muted","duration","paused","ended","buffered","error","networkState","readyState","seeking","seekable","currentSrc","preload","bufferedBytes","bufferedTime","initialTime","startOffsetTime","defaultPlaybackRate","playbackRate","played","autoplay","loop","controls"],readOnlyProperties:["duration","paused","ended","buffered","error","networkState","readyState","seeking","seekable"],methods:["load","play","pause","canPlayType"],events:["loadstart","durationchange","loadedmetadata","loadeddata","progress","canplay","canplaythrough","suspend","abort","error","emptied","stalled","play","playing","pause","waiting","seeking","seeked","timeupdate","ended","ratechange","volumechange"],mediaTypes:["audio/mp3","audio/ogg","audio/oga","audio/wav","audio/x-wav","audio/wave","audio/x-pn-wav","audio/mpeg","audio/mp4","video/mp4","video/webm","video/ogg","video/ogv"]}};((n=a)&&n.__esModule?n:{default:n}).default.mejs=o,r.default=o},{3:3}],5:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.renderer=void 0;var n,a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o=function(){function n(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(e,t,r){return t&&n(e.prototype,t),r&&n(e,r),e}}(),i=e(4),u=(n=i)&&n.__esModule?n:{default:n};var s=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.renderers={},this.order=[]}return o(e,[{key:"add",value:function(e){if(void 0===e.name)throw new TypeError("renderer must contain at least `name` property");this.renderers[e.name]=e,this.order.push(e.name)}},{key:"select",value:function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:[],r=t.length;if(t=t.length?t:this.order,!r){var n=[/^(html5|native)/i,/^flash/i,/iframe$/i],a=function(e){for(var t=0,r=n.length;t<r;t++)if(n[t].test(e))return t;return n.length};t.sort(function(e,t){return a(e)-a(t)})}for(var o=0,i=t.length;o<i;o++){var u=t[o],s=this.renderers[u];if(null!=s)for(var l=0,d=e.length;l<d;l++)if("function"==typeof s.canPlayType&&"string"==typeof e[l].type&&s.canPlayType(e[l].type))return{rendererName:s.name,src:e[l].src}}return null}},{key:"order",set:function(e){if(!Array.isArray(e))throw new TypeError("order must be an array of strings.");this._order=e},get:function(){return this._order}},{key:"renderers",set:function(e){if(null!==e&&"object"!==(void 0===e?"undefined":a(e)))throw new TypeError("renderers must be an array of objects.");this._renderers=e},get:function(){return this._renderers}}]),e}(),l=r.renderer=new s;u.default.Renderers=l},{4:4}],6:[function(e,t,r){"use strict";var k=i(e(3)),x=i(e(2)),U=i(e(4)),n=e(5),I=e(8),a=e(9),o=e(7);function i(e){return e&&e.__esModule?e:{default:e}}var _={isIframeStarted:!1,isIframeLoaded:!1,iframeQueue:[],enqueueIframe:function(e){_.isLoaded="undefined"!=typeof YT&&YT.loaded,_.isLoaded?_.createIframe(e):(_.loadIframeApi(),_.iframeQueue.push(e))},loadIframeApi:function(){_.isIframeStarted||((0,o.loadScript)("https://www.youtube.com/player_api"),_.isIframeStarted=!0)},iFrameReady:function(){for(_.isLoaded=!0,_.isIframeLoaded=!0;0<_.iframeQueue.length;){var e=_.iframeQueue.pop();_.createIframe(e)}},createIframe:function(e){return new YT.Player(e.containerId,e)},getYouTubeId:function(e){var t="";return 0<e.indexOf("?")?""===(t=_.getYouTubeIdFromParam(e))&&(t=_.getYouTubeIdFromUrl(e)):t=_.getYouTubeIdFromUrl(e),(t=t.substring(t.lastIndexOf("/")+1).split("?"))[0]},getYouTubeIdFromParam:function(e){if(null==e||!e.trim().length)return null;for(var t=e.split("?")[1].split("&"),r="",n=0,a=t.length;n<a;n++){var o=t[n].split("=");if("v"===o[0]){r=o[1];break}}return r},getYouTubeIdFromUrl:function(e){return null!=e&&e.trim().length?(e=e.split("?")[0]).substring(e.lastIndexOf("/")+1):null},getYouTubeNoCookieUrl:function(e){if(null==e||!e.trim().length||-1===e.indexOf("//www.youtube"))return e;var t=e.split("/");return t[2]=t[2].replace(".com","-nocookie.com"),t.join("/")}},u={name:"youtube_iframe",options:{prefix:"youtube_iframe",youtube:{autoplay:0,controls:0,disablekb:1,end:0,loop:0,modestbranding:0,playsinline:0,rel:0,showinfo:0,start:0,iv_load_policy:3,nocookie:!1,imageQuality:null}},canPlayType:function(e){return~["video/youtube","video/x-youtube"].indexOf(e.toLowerCase())},create:function(m,r,n){var v={},y=[],g=null,o=!0,i=!1,h=null;v.options=r,v.id=m.id+"_"+r.prefix,v.mediaElement=m;for(var e=U.default.html5media.properties,t=function(a){var e=""+a.substring(0,1).toUpperCase()+a.substring(1);v["get"+e]=function(){if(null!==g){switch(a){case"currentTime":return g.getCurrentTime();case"duration":return g.getDuration();case"volume":return g.getVolume()/100;case"playbackRate":return g.getPlaybackRate();case"paused":return o;case"ended":return i;case"muted":return g.isMuted();case"buffered":var e=g.getVideoLoadedFraction(),t=g.getDuration();return{start:function(){return 0},end:function(){return e*t},length:1};case"src":return g.getVideoUrl();case"readyState":return 4}return null}return null},v["set"+e]=function(e){if(null!==g)switch(a){case"src":var t="string"==typeof e?e:e[0].src,r=_.getYouTubeId(t);m.originalNode.autoplay?g.loadVideoById(r):g.cueVideoById(r);break;case"currentTime":g.seekTo(e);break;case"muted":e?g.mute():g.unMute(),setTimeout(function(){var e=(0,I.createEvent)("volumechange",v);m.dispatchEvent(e)},50);break;case"volume":e,g.setVolume(100*e),setTimeout(function(){var e=(0,I.createEvent)("volumechange",v);m.dispatchEvent(e)},50);break;case"playbackRate":g.setPlaybackRate(e),setTimeout(function(){var e=(0,I.createEvent)("ratechange",v);m.dispatchEvent(e)},50);break;case"readyState":var n=(0,I.createEvent)("canplay",v);m.dispatchEvent(n)}else y.push({type:"set",propName:a,value:e})}},a=0,u=e.length;a<u;a++)t(e[a]);for(var s=U.default.html5media.methods,l=function(e){v[e]=function(){if(null!==g)switch(e){case"play":return o=!1,g.playVideo();case"pause":return o=!0,g.pauseVideo();case"load":return null}else y.push({type:"call",methodName:e})}},d=0,f=s.length;d<f;d++)l(s[d]);var c=x.default.createElement("div");c.id=v.id,v.options.youtube.nocookie&&(m.originalNode.src=_.getYouTubeNoCookieUrl(n[0].src)),m.originalNode.parentNode.insertBefore(c,m.originalNode),m.originalNode.style.display="none";var p="audio"===m.originalNode.tagName.toLowerCase(),b=p?"1":m.originalNode.height,w=p?"1":m.originalNode.width,T=_.getYouTubeId(n[0].src),E={id:v.id,containerId:c.id,videoId:T,height:b,width:w,host:v.options.youtube&&v.options.youtube.nocookie?"https://www.youtube-nocookie.com":void 0,playerVars:Object.assign({controls:0,rel:0,disablekb:1,showinfo:0,modestbranding:0,html5:1,iv_load_policy:3},v.options.youtube),origin:k.default.location.host,events:{onReady:function(e){if(m.youTubeApi=g=e.target,m.youTubeState={paused:!0,ended:!1},y.length)for(var t=0,r=y.length;t<r;t++){var n=y[t];if("set"===n.type){var a=n.propName,o=""+a.substring(0,1).toUpperCase()+a.substring(1);v["set"+o](n.value)}else"call"===n.type&&v[n.methodName]()}h=g.getIframe(),m.originalNode.muted&&g.mute();for(var i=["mouseover","mouseout"],u=function(e){var t=(0,I.createEvent)(e.type,v);m.dispatchEvent(t)},s=0,l=i.length;s<l;s++)h.addEventListener(i[s],u,!1);for(var d=["rendererready","loadedmetadata","loadeddata","canplay"],f=0,c=d.length;f<c;f++){var p=(0,I.createEvent)(d[f],v);m.dispatchEvent(p)}},onStateChange:function(e){var t=[];switch(e.data){case-1:t=["loadedmetadata"],o=!0,i=!1;break;case 0:t=["ended"],o=!1,i=!v.options.youtube.loop,v.options.youtube.loop||v.stopInterval();break;case 1:t=["play","playing"],i=o=!1,v.startInterval();break;case 2:t=["pause"],o=!0,i=!1,v.stopInterval();break;case 3:t=["progress"],i=!1;break;case 5:t=["loadeddata","loadedmetadata","canplay"],o=!0,i=!1}for(var r=0,n=t.length;r<n;r++){var a=(0,I.createEvent)(t[r],v);m.dispatchEvent(a)}},onError:function(e){return function(e){var t="";switch(e.data){case 2:t="The request contains an invalid parameter value. Verify that video ID has 11 characters and that contains no invalid characters, such as exclamation points or asterisks.";break;case 5:t="The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.";break;case 100:t="The video requested was not found. Either video has been removed or has been marked as private.";break;case 101:case 105:t="The owner of the requested video does not allow it to be played in embedded players.";break;default:t="Unknown error."}m.generateError("Code "+e.data+": "+t,n)}(e)}}};return(p||m.originalNode.hasAttribute("playsinline"))&&(E.playerVars.playsinline=1),m.originalNode.controls&&(E.playerVars.controls=1),m.originalNode.autoplay&&(E.playerVars.autoplay=1),m.originalNode.loop&&(E.playerVars.loop=1),(E.playerVars.loop&&1===parseInt(E.playerVars.loop,10)||-1<m.originalNode.src.indexOf("loop="))&&!E.playerVars.playlist&&-1===m.originalNode.src.indexOf("playlist=")&&(E.playerVars.playlist=_.getYouTubeId(m.originalNode.src)),_.enqueueIframe(E),v.onEvent=function(e,t,r){null!=r&&(m.youTubeState=r)},v.setSize=function(e,t){null!==g&&g.setSize(e,t)},v.hide=function(){v.stopInterval(),v.pause(),h&&(h.style.display="none")},v.show=function(){h&&(h.style.display="")},v.destroy=function(){g.destroy()},v.interval=null,v.startInterval=function(){v.interval=setInterval(function(){var e=(0,I.createEvent)("timeupdate",v);m.dispatchEvent(e)},250)},v.stopInterval=function(){v.interval&&clearInterval(v.interval)},v.getPosterUrl=function(){var e=r.youtube.imageQuality,t=_.getYouTubeId(m.originalNode.src);return e&&-1<["default","hqdefault","mqdefault","sddefault","maxresdefault"].indexOf(e)&&t?"https://img.youtube.com/vi/"+t+"/"+e+".jpg":""},v}};k.default.onYouTubePlayerAPIReady=function(){_.iFrameReady()},a.typeChecks.push(function(e){return/\/\/(www\.youtube|youtu\.?be)/i.test(e)?"video/x-youtube":null}),n.renderer.add(u)},{2:2,3:3,4:4,5:5,7:7,8:8,9:9}],7:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.removeClass=r.addClass=r.hasClass=void 0,r.loadScript=i,r.offset=u,r.toggleClass=v,r.fadeOut=y,r.fadeIn=g,r.siblings=h,r.visible=b,r.ajax=w;var s=o(e(3)),a=o(e(2)),n=o(e(4));function o(e){return e&&e.__esModule?e:{default:e}}function i(n){return new Promise(function(e,t){var r=a.default.createElement("script");r.src=n,r.async=!0,r.onload=function(){r.remove(),e()},r.onerror=function(){r.remove(),t()},a.default.head.appendChild(r)})}function u(e){var t=e.getBoundingClientRect(),r=s.default.pageXOffset||a.default.documentElement.scrollLeft,n=s.default.pageYOffset||a.default.documentElement.scrollTop;return{top:t.top+n,left:t.left+r}}var l=void 0,d=void 0,f=void 0;"classList"in a.default.documentElement?(l=function(e,t){return void 0!==e.classList&&e.classList.contains(t)},d=function(e,t){return e.classList.add(t)},f=function(e,t){return e.classList.remove(t)}):(l=function(e,t){return new RegExp("\\b"+t+"\\b").test(e.className)},d=function(e,t){c(e,t)||(e.className+=" "+t)},f=function(e,t){e.className=e.className.replace(new RegExp("\\b"+t+"\\b","g"),"")});var c=r.hasClass=l,p=r.addClass=d,m=r.removeClass=f;function v(e,t){c(e,t)?m(e,t):p(e,t)}function y(a){var o=1<arguments.length&&void 0!==arguments[1]?arguments[1]:400,i=arguments[2];a.style.opacity||(a.style.opacity=1);var u=null;s.default.requestAnimationFrame(function e(t){var r=t-(u=u||t),n=parseFloat(1-r/o,2);a.style.opacity=n<0?0:n,o<r?i&&"function"==typeof i&&i():s.default.requestAnimationFrame(e)})}function g(a){var o=1<arguments.length&&void 0!==arguments[1]?arguments[1]:400,i=arguments[2];a.style.opacity||(a.style.opacity=0);var u=null;s.default.requestAnimationFrame(function e(t){var r=t-(u=u||t),n=parseFloat(r/o,2);a.style.opacity=1<n?1:n,o<r?i&&"function"==typeof i&&i():s.default.requestAnimationFrame(e)})}function h(e,t){var r=[];for(e=e.parentNode.firstChild;t&&!t(e)||r.push(e),e=e.nextSibling;);return r}function b(e){return void 0!==e.getClientRects&&"function"===e.getClientRects?!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length):!(!e.offsetWidth&&!e.offsetHeight)}function w(e,t,r,n){var a=s.default.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP"),o="application/x-www-form-urlencoded; charset=UTF-8",i=!1,u="*/".concat("*");switch(t){case"text":o="text/plain";break;case"json":o="application/json, text/javascript";break;case"html":o="text/html";break;case"xml":o="application/xml, text/xml"}"application/x-www-form-urlencoded"!==o&&(u=o+", */*; q=0.01"),a&&(a.open("GET",e,!0),a.setRequestHeader("Accept",u),a.onreadystatechange=function(){if(!i&&4===a.readyState)if(200===a.status){i=!0;var e=void 0;switch(t){case"json":e=JSON.parse(a.responseText);break;case"xml":e=a.responseXML;break;default:e=a.responseText}r(e)}else"function"==typeof n&&n(a.status)},a.send())}n.default.Utils=n.default.Utils||{},n.default.Utils.offset=u,n.default.Utils.hasClass=c,n.default.Utils.addClass=p,n.default.Utils.removeClass=m,n.default.Utils.toggleClass=v,n.default.Utils.fadeIn=g,n.default.Utils.fadeOut=y,n.default.Utils.siblings=h,n.default.Utils.visible=b,n.default.Utils.ajax=w,n.default.Utils.loadScript=i},{2:2,3:3,4:4}],8:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.escapeHTML=i,r.debounce=u,r.isObjectEmpty=s,r.splitEvents=l,r.createEvent=d,r.isNodeAfter=f,r.isString=c;var n,a=e(4),o=(n=a)&&n.__esModule?n:{default:n};function i(e){if("string"!=typeof e)throw new Error("Argument passed must be a string");var t={"&":"&","<":"<",">":">",'"':"""};return e.replace(/[&<>"]/g,function(e){return t[e]})}function u(n,a){var o=this,i=arguments,u=2<arguments.length&&void 0!==arguments[2]&&arguments[2];if("function"!=typeof n)throw new Error("First argument must be a function");if("number"!=typeof a)throw new Error("Second argument must be a numeric value");var s=void 0;return function(){var e=o,t=i,r=u&&!s;clearTimeout(s),s=setTimeout(function(){s=null,u||n.apply(e,t)},a),r&&n.apply(e,t)}}function s(e){return Object.getOwnPropertyNames(e).length<=0}function l(e,r){var n=/^((after|before)print|(before)?unload|hashchange|message|o(ff|n)line|page(hide|show)|popstate|resize|storage)\b/,a={d:[],w:[]};return(e||"").split(" ").forEach(function(e){var t=e+(r?"."+r:"");t.startsWith(".")?(a.d.push(t),a.w.push(t)):a[n.test(e)?"w":"d"].push(t)}),a.d=a.d.join(" "),a.w=a.w.join(" "),a}function d(e,t){if("string"!=typeof e)throw new Error("Event name must be a string");var r=e.match(/([a-z]+\.([a-z]+))/i),n={target:t};return null!==r&&(e=r[1],n.namespace=r[2]),new window.CustomEvent(e,{detail:n})}function f(e,t){return!!(e&&t&&2&e.compareDocumentPosition(t))}function c(e){return"string"==typeof e}o.default.Utils=o.default.Utils||{},o.default.Utils.escapeHTML=i,o.default.Utils.debounce=u,o.default.Utils.isObjectEmpty=s,o.default.Utils.splitEvents=l,o.default.Utils.createEvent=d,o.default.Utils.isNodeAfter=f,o.default.Utils.isString=c},{4:4}],9:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.typeChecks=void 0,r.absolutizeUrl=s,r.formatType=l,r.getMimeFromType=d,r.getTypeFromFile=f,r.getExtension=c,r.normalizeExtension=p;var n,a=e(4),o=(n=a)&&n.__esModule?n:{default:n},i=e(8);var u=r.typeChecks=[];function s(e){if("string"!=typeof e)throw new Error("`url` argument must be a string");var t=document.createElement("div");return t.innerHTML='<a href="'+(0,i.escapeHTML)(e)+'">x</a>',t.firstChild.href}function l(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:"";return e&&!t?f(e):t}function d(e){if("string"!=typeof e)throw new Error("`type` argument must be a string");return e&&-1<e.indexOf(";")?e.substr(0,e.indexOf(";")):e}function f(e){if("string"!=typeof e)throw new Error("`url` argument must be a string");for(var t=0,r=u.length;t<r;t++){var n=u[t](e);if(n)return n}var a=p(c(e)),o="video/mp4";return a&&(~["mp4","m4v","ogg","ogv","webm","flv","mpeg"].indexOf(a)?o="video/"+a:"mov"===a?o="video/quicktime":~["mp3","oga","wav","mid","midi"].indexOf(a)&&(o="audio/"+a)),o}function c(e){if("string"!=typeof e)throw new Error("`url` argument must be a string");var t=e.split("?")[0].split("\\").pop().split("/").pop();return~t.indexOf(".")?t.substring(t.lastIndexOf(".")+1):""}function p(e){if("string"!=typeof e)throw new Error("`extension` argument must be a string");switch(e){case"mp4":case"m4v":return"mp4";case"webm":case"webma":case"webmv":return"webm";case"ogg":case"oga":case"ogv":return"ogg";default:return e}}o.default.Utils=o.default.Utils||{},o.default.Utils.typeChecks=u,o.default.Utils.absolutizeUrl=s,o.default.Utils.formatType=l,o.default.Utils.getMimeFromType=d,o.default.Utils.getTypeFromFile=f,o.default.Utils.getExtension=c,o.default.Utils.normalizeExtension=p},{4:4,8:8}]},{},[6]); | ||
!function o(i,u,s){function l(r,e){if(!u[r]){if(!i[r]){var t="function"==typeof require&&require;if(!e&&t)return t(r,!0);if(d)return d(r,!0);var n=new Error("Cannot find module '"+r+"'");throw n.code="MODULE_NOT_FOUND",n}var a=u[r]={exports:{}};i[r][0].call(a.exports,function(e){var t=i[r][1][e];return l(t||e)},a,a.exports,o,i,u,s)}return u[r].exports}for(var d="function"==typeof require&&require,e=0;e<s.length;e++)l(s[e]);return l}({1:[function(e,t,r){},{}],2:[function(a,o,e){(function(e){var t,r=void 0!==e?e:"undefined"!=typeof window?window:{},n=a(1);"undefined"!=typeof document?t=document:(t=r["__GLOBAL_DOCUMENT_CACHE@4"])||(t=r["__GLOBAL_DOCUMENT_CACHE@4"]=n),o.exports=t}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{1:1}],3:[function(e,r,t){(function(e){var t;t="undefined"!=typeof window?window:void 0!==e?e:"undefined"!=typeof self?self:{},r.exports=t}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],4:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n,a=e(3);var o={version:"6.0.0",html5media:{properties:["volume","src","currentTime","muted","duration","paused","ended","buffered","error","networkState","readyState","seeking","seekable","currentSrc","preload","bufferedBytes","bufferedTime","initialTime","startOffsetTime","defaultPlaybackRate","playbackRate","played","autoplay","loop","controls"],readOnlyProperties:["duration","paused","ended","buffered","error","networkState","readyState","seeking","seekable"],methods:["load","play","pause","canPlayType"],events:["loadstart","durationchange","loadedmetadata","loadeddata","progress","canplay","canplaythrough","suspend","abort","error","emptied","stalled","play","playing","pause","waiting","seeking","seeked","timeupdate","ended","ratechange","volumechange"],mediaTypes:["audio/mp3","audio/ogg","audio/oga","audio/wav","audio/x-wav","audio/wave","audio/x-pn-wav","audio/mpeg","audio/mp4","video/mp4","video/webm","video/ogg","video/ogv"]}};((n=a)&&n.__esModule?n:{default:n}).default.mejs=o,r.default=o},{3:3}],5:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.renderer=void 0;var n,a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o=function(){function n(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(e,t,r){return t&&n(e.prototype,t),r&&n(e,r),e}}(),i=e(4),u=(n=i)&&n.__esModule?n:{default:n};var s=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.renderers={},this.order=[]}return o(e,[{key:"add",value:function(e){if(void 0===e.name)throw new TypeError("renderer must contain at least `name` property");this.renderers[e.name]=e,this.order.push(e.name)}},{key:"select",value:function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:[],r=t.length;if(t=t.length?t:this.order,!r){var n=[/^(html5|native)/i,/^flash/i,/iframe$/i],a=function(e){for(var t=0,r=n.length;t<r;t++)if(n[t].test(e))return t;return n.length};t.sort(function(e,t){return a(e)-a(t)})}for(var o=0,i=t.length;o<i;o++){var u=t[o],s=this.renderers[u];if(null!=s)for(var l=0,d=e.length;l<d;l++)if("function"==typeof s.canPlayType&&"string"==typeof e[l].type&&s.canPlayType(e[l].type))return{rendererName:s.name,src:e[l].src}}return null}},{key:"order",set:function(e){if(!Array.isArray(e))throw new TypeError("order must be an array of strings.");this._order=e},get:function(){return this._order}},{key:"renderers",set:function(e){if(null!==e&&"object"!==(void 0===e?"undefined":a(e)))throw new TypeError("renderers must be an array of objects.");this._renderers=e},get:function(){return this._renderers}}]),e}(),l=r.renderer=new s;u.default.Renderers=l},{4:4}],6:[function(e,t,r){"use strict";var k=i(e(3)),x=i(e(2)),U=i(e(4)),n=e(5),I=e(8),a=e(9),o=e(7);function i(e){return e&&e.__esModule?e:{default:e}}var _={isIframeStarted:!1,isIframeLoaded:!1,iframeQueue:[],enqueueIframe:function(e){_.isLoaded="undefined"!=typeof YT&&YT.loaded,_.isLoaded?_.createIframe(e):(_.loadIframeApi(),_.iframeQueue.push(e))},loadIframeApi:function(){_.isIframeStarted||((0,o.loadScript)("https://www.youtube.com/player_api"),_.isIframeStarted=!0)},iFrameReady:function(){for(_.isLoaded=!0,_.isIframeLoaded=!0;0<_.iframeQueue.length;){var e=_.iframeQueue.pop();_.createIframe(e)}},createIframe:function(e){return new YT.Player(e.containerId,e)},getYouTubeId:function(e){var t="";return 0<e.indexOf("?")?""===(t=_.getYouTubeIdFromParam(e))&&(t=_.getYouTubeIdFromUrl(e)):t=_.getYouTubeIdFromUrl(e),(t=t.substring(t.lastIndexOf("/")+1).split("?"))[0]},getYouTubeIdFromParam:function(e){if(null==e||!e.trim().length)return null;for(var t=e.split("?")[1].split("&"),r="",n=0,a=t.length;n<a;n++){var o=t[n].split("=");if("v"===o[0]){r=o[1];break}}return r},getYouTubeIdFromUrl:function(e){return null!=e&&e.trim().length?(e=e.split("?")[0]).substring(e.lastIndexOf("/")+1):null},getYouTubeNoCookieUrl:function(e){if(null==e||!e.trim().length||-1===e.indexOf("//www.youtube"))return e;var t=e.split("/");return t[2]=t[2].replace(".com","-nocookie.com"),t.join("/")}},u={name:"youtube_iframe",options:{prefix:"youtube_iframe",youtube:{autoplay:0,controls:0,disablekb:1,end:0,loop:0,modestbranding:0,playsinline:0,rel:0,showinfo:0,start:0,iv_load_policy:3,nocookie:!1,imageQuality:null}},canPlayType:function(e){return~["video/youtube","video/x-youtube"].indexOf(e.toLowerCase())},create:function(m,r,n){var v={},y=[],g=null,o=!0,i=!1,h=null;v.options=r,v.id=m.id+"_"+r.prefix,v.mediaElement=m;for(var e=U.default.html5media.properties,t=function(a){var e=""+a.substring(0,1).toUpperCase()+a.substring(1);v["get"+e]=function(){if(null!==g){switch(a){case"currentTime":return g.getCurrentTime();case"duration":return g.getDuration();case"volume":return g.getVolume()/100;case"playbackRate":return g.getPlaybackRate();case"paused":return o;case"ended":return i;case"muted":return g.isMuted();case"buffered":var e=g.getVideoLoadedFraction(),t=g.getDuration();return{start:function(){return 0},end:function(){return e*t},length:1};case"src":return g.getVideoUrl();case"readyState":return 4}return null}return null},v["set"+e]=function(e){if(null!==g)switch(a){case"src":var t="string"==typeof e?e:e[0].src,r=_.getYouTubeId(t);m.originalNode.autoplay?g.loadVideoById(r):g.cueVideoById(r);break;case"currentTime":g.seekTo(e);break;case"muted":e?g.mute():g.unMute(),setTimeout(function(){var e=(0,I.createEvent)("volumechange",v);m.dispatchEvent(e)},50);break;case"volume":e,g.setVolume(100*e),setTimeout(function(){var e=(0,I.createEvent)("volumechange",v);m.dispatchEvent(e)},50);break;case"playbackRate":g.setPlaybackRate(e),setTimeout(function(){var e=(0,I.createEvent)("ratechange",v);m.dispatchEvent(e)},50);break;case"readyState":var n=(0,I.createEvent)("canplay",v);m.dispatchEvent(n)}else y.push({type:"set",propName:a,value:e})}},a=0,u=e.length;a<u;a++)t(e[a]);for(var s=U.default.html5media.methods,l=function(e){v[e]=function(){if(null!==g)switch(e){case"play":return o=!1,g.playVideo();case"pause":return o=!0,g.pauseVideo();case"load":return null}else y.push({type:"call",methodName:e})}},d=0,f=s.length;d<f;d++)l(s[d]);var c=x.default.createElement("div");c.id=v.id,v.options.youtube.nocookie&&(m.originalNode.src=_.getYouTubeNoCookieUrl(n[0].src)),m.originalNode.parentNode.insertBefore(c,m.originalNode),m.originalNode.style.display="none";var p="audio"===m.originalNode.tagName.toLowerCase(),b=p?"1":m.originalNode.height,w=p?"1":m.originalNode.width,T=_.getYouTubeId(n[0].src),E={id:v.id,containerId:c.id,videoId:T,height:b,width:w,host:v.options.youtube&&v.options.youtube.nocookie?"https://www.youtube-nocookie.com":void 0,playerVars:Object.assign({controls:0,rel:0,disablekb:1,showinfo:0,modestbranding:0,html5:1,iv_load_policy:3},v.options.youtube),origin:k.default.location.host,events:{onReady:function(e){if(m.youTubeApi=g=e.target,m.youTubeState={paused:!0,ended:!1},y.length)for(var t=0,r=y.length;t<r;t++){var n=y[t];if("set"===n.type){var a=n.propName,o=""+a.substring(0,1).toUpperCase()+a.substring(1);v["set"+o](n.value)}else"call"===n.type&&v[n.methodName]()}h=g.getIframe(),m.originalNode.muted&&g.mute();for(var i=["mouseover","mouseout"],u=function(e){var t=(0,I.createEvent)(e.type,v);m.dispatchEvent(t)},s=0,l=i.length;s<l;s++)h.addEventListener(i[s],u,!1);for(var d=["rendererready","loadedmetadata","loadeddata","canplay"],f=0,c=d.length;f<c;f++){var p=(0,I.createEvent)(d[f],v);m.dispatchEvent(p)}},onStateChange:function(e){var t=[];switch(e.data){case-1:t=["loadedmetadata"],o=!0,i=!1;break;case 0:t=["ended"],o=!1,i=!v.options.youtube.loop,v.options.youtube.loop||v.stopInterval();break;case 1:t=["play","playing"],i=o=!1,v.startInterval();break;case 2:t=["pause"],o=!0,i=!1,v.stopInterval();break;case 3:t=["progress"],i=!1;break;case 5:t=["loadeddata","loadedmetadata","canplay"],o=!0,i=!1}for(var r=0,n=t.length;r<n;r++){var a=(0,I.createEvent)(t[r],v);m.dispatchEvent(a)}},onError:function(e){return function(e){var t="";switch(e.data){case 2:t="The request contains an invalid parameter value. Verify that video ID has 11 characters and that contains no invalid characters, such as exclamation points or asterisks.";break;case 5:t="The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.";break;case 100:t="The video requested was not found. Either video has been removed or has been marked as private.";break;case 101:case 105:t="The owner of the requested video does not allow it to be played in embedded players.";break;default:t="Unknown error."}m.generateError("Code "+e.data+": "+t,n)}(e)}}};return(p||m.originalNode.hasAttribute("playsinline"))&&(E.playerVars.playsinline=1),m.originalNode.controls&&(E.playerVars.controls=1),m.originalNode.autoplay&&(E.playerVars.autoplay=1),m.originalNode.loop&&(E.playerVars.loop=1),(E.playerVars.loop&&1===parseInt(E.playerVars.loop,10)||-1<m.originalNode.src.indexOf("loop="))&&!E.playerVars.playlist&&-1===m.originalNode.src.indexOf("playlist=")&&(E.playerVars.playlist=_.getYouTubeId(m.originalNode.src)),_.enqueueIframe(E),v.onEvent=function(e,t,r){null!=r&&(m.youTubeState=r)},v.setSize=function(e,t){null!==g&&g.setSize(e,t)},v.hide=function(){v.stopInterval(),v.pause(),h&&(h.style.display="none")},v.show=function(){h&&(h.style.display="")},v.destroy=function(){g.destroy()},v.interval=null,v.startInterval=function(){v.interval=setInterval(function(){var e=(0,I.createEvent)("timeupdate",v);m.dispatchEvent(e)},250)},v.stopInterval=function(){v.interval&&clearInterval(v.interval)},v.getPosterUrl=function(){var e=r.youtube.imageQuality,t=_.getYouTubeId(m.originalNode.src);return e&&-1<["default","hqdefault","mqdefault","sddefault","maxresdefault"].indexOf(e)&&t?"https://img.youtube.com/vi/"+t+"/"+e+".jpg":""},v}};k.default.onYouTubePlayerAPIReady=function(){_.iFrameReady()},a.typeChecks.push(function(e){return/\/\/(www\.youtube|youtu\.?be)/i.test(e)?"video/x-youtube":null}),n.renderer.add(u)},{2:2,3:3,4:4,5:5,7:7,8:8,9:9}],7:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.removeClass=r.addClass=r.hasClass=void 0,r.loadScript=i,r.offset=u,r.toggleClass=v,r.fadeOut=y,r.fadeIn=g,r.siblings=h,r.visible=b,r.ajax=w;var s=o(e(3)),a=o(e(2)),n=o(e(4));function o(e){return e&&e.__esModule?e:{default:e}}function i(n){return new Promise(function(e,t){var r=a.default.createElement("script");r.src=n,r.async=!0,r.onload=function(){r.remove(),e()},r.onerror=function(){r.remove(),t()},a.default.head.appendChild(r)})}function u(e){var t=e.getBoundingClientRect(),r=s.default.pageXOffset||a.default.documentElement.scrollLeft,n=s.default.pageYOffset||a.default.documentElement.scrollTop;return{top:t.top+n,left:t.left+r}}var l=void 0,d=void 0,f=void 0;"classList"in a.default.documentElement?(l=function(e,t){return void 0!==e.classList&&e.classList.contains(t)},d=function(e,t){return e.classList.add(t)},f=function(e,t){return e.classList.remove(t)}):(l=function(e,t){return new RegExp("\\b"+t+"\\b").test(e.className)},d=function(e,t){c(e,t)||(e.className+=" "+t)},f=function(e,t){e.className=e.className.replace(new RegExp("\\b"+t+"\\b","g"),"")});var c=r.hasClass=l,p=r.addClass=d,m=r.removeClass=f;function v(e,t){c(e,t)?m(e,t):p(e,t)}function y(a){var o=1<arguments.length&&void 0!==arguments[1]?arguments[1]:400,i=arguments[2];a.style.opacity||(a.style.opacity=1);var u=null;s.default.requestAnimationFrame(function e(t){var r=t-(u=u||t),n=parseFloat(1-r/o,2);a.style.opacity=n<0?0:n,o<r?i&&"function"==typeof i&&i():s.default.requestAnimationFrame(e)})}function g(a){var o=1<arguments.length&&void 0!==arguments[1]?arguments[1]:400,i=arguments[2];a.style.opacity||(a.style.opacity=0);var u=null;s.default.requestAnimationFrame(function e(t){var r=t-(u=u||t),n=parseFloat(r/o,2);a.style.opacity=1<n?1:n,o<r?i&&"function"==typeof i&&i():s.default.requestAnimationFrame(e)})}function h(e,t){var r=[];for(e=e.parentNode.firstChild;t&&!t(e)||r.push(e),e=e.nextSibling;);return r}function b(e){return void 0!==e.getClientRects&&"function"===e.getClientRects?!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length):!(!e.offsetWidth&&!e.offsetHeight)}function w(e,t,r,n){var a=s.default.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP"),o="application/x-www-form-urlencoded; charset=UTF-8",i=!1,u="*/".concat("*");switch(t){case"text":o="text/plain";break;case"json":o="application/json, text/javascript";break;case"html":o="text/html";break;case"xml":o="application/xml, text/xml"}"application/x-www-form-urlencoded"!==o&&(u=o+", */*; q=0.01"),a&&(a.open("GET",e,!0),a.setRequestHeader("Accept",u),a.onreadystatechange=function(){if(!i&&4===a.readyState)if(200===a.status){i=!0;var e=void 0;switch(t){case"json":e=JSON.parse(a.responseText);break;case"xml":e=a.responseXML;break;default:e=a.responseText}r(e)}else"function"==typeof n&&n(a.status)},a.send())}n.default.Utils=n.default.Utils||{},n.default.Utils.offset=u,n.default.Utils.hasClass=c,n.default.Utils.addClass=p,n.default.Utils.removeClass=m,n.default.Utils.toggleClass=v,n.default.Utils.fadeIn=g,n.default.Utils.fadeOut=y,n.default.Utils.siblings=h,n.default.Utils.visible=b,n.default.Utils.ajax=w,n.default.Utils.loadScript=i},{2:2,3:3,4:4}],8:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.escapeHTML=i,r.debounce=u,r.isObjectEmpty=s,r.splitEvents=l,r.createEvent=d,r.isNodeAfter=f,r.isString=c;var n,a=e(4),o=(n=a)&&n.__esModule?n:{default:n};function i(e){if("string"!=typeof e)throw new Error("Argument passed must be a string");var t={"&":"&","<":"<",">":">",'"':"""};return e.replace(/[&<>"]/g,function(e){return t[e]})}function u(n,a){var o=this,i=arguments,u=2<arguments.length&&void 0!==arguments[2]&&arguments[2];if("function"!=typeof n)throw new Error("First argument must be a function");if("number"!=typeof a)throw new Error("Second argument must be a numeric value");var s=void 0;return function(){var e=o,t=i,r=u&&!s;clearTimeout(s),s=setTimeout(function(){s=null,u||n.apply(e,t)},a),r&&n.apply(e,t)}}function s(e){return Object.getOwnPropertyNames(e).length<=0}function l(e,r){var n=/^((after|before)print|(before)?unload|hashchange|message|o(ff|n)line|page(hide|show)|popstate|resize|storage)\b/,a={d:[],w:[]};return(e||"").split(" ").forEach(function(e){var t=e+(r?"."+r:"");t.startsWith(".")?(a.d.push(t),a.w.push(t)):a[n.test(e)?"w":"d"].push(t)}),a.d=a.d.join(" "),a.w=a.w.join(" "),a}function d(e,t){if("string"!=typeof e)throw new Error("Event name must be a string");var r=e.match(/([a-z]+\.([a-z]+))/i),n={target:t};return null!==r&&(e=r[1],n.namespace=r[2]),new window.CustomEvent(e,{detail:n})}function f(e,t){return!!(e&&t&&2&e.compareDocumentPosition(t))}function c(e){return"string"==typeof e}o.default.Utils=o.default.Utils||{},o.default.Utils.escapeHTML=i,o.default.Utils.debounce=u,o.default.Utils.isObjectEmpty=s,o.default.Utils.splitEvents=l,o.default.Utils.createEvent=d,o.default.Utils.isNodeAfter=f,o.default.Utils.isString=c},{4:4}],9:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.typeChecks=void 0,r.absolutizeUrl=s,r.formatType=l,r.getMimeFromType=d,r.getTypeFromFile=f,r.getExtension=c,r.normalizeExtension=p;var n,a=e(4),o=(n=a)&&n.__esModule?n:{default:n},i=e(8);var u=r.typeChecks=[];function s(e){if("string"!=typeof e)throw new Error("`url` argument must be a string");var t=document.createElement("div");return t.innerHTML='<a href="'+(0,i.escapeHTML)(e)+'">x</a>',t.firstChild.href}function l(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:"";return e&&!t?f(e):t}function d(e){if("string"!=typeof e)throw new Error("`type` argument must be a string");return e&&-1<e.indexOf(";")?e.substr(0,e.indexOf(";")):e}function f(e){if("string"!=typeof e)throw new Error("`url` argument must be a string");for(var t=0,r=u.length;t<r;t++){var n=u[t](e);if(n)return n}var a=p(c(e)),o="video/mp4";return a&&(~["mp4","m4v","ogg","ogv","webm","flv","mpeg"].indexOf(a)?o="video/"+a:"mov"===a?o="video/quicktime":~["mp3","oga","wav","mid","midi"].indexOf(a)&&(o="audio/"+a)),o}function c(e){if("string"!=typeof e)throw new Error("`url` argument must be a string");var t=e.split("?")[0].split("\\").pop().split("/").pop();return~t.indexOf(".")?t.substring(t.lastIndexOf(".")+1):""}function p(e){if("string"!=typeof e)throw new Error("`extension` argument must be a string");switch(e){case"mp4":case"m4v":return"mp4";case"webm":case"webma":case"webmv":return"webm";case"ogg":case"oga":case"ogv":return"ogg";default:return e}}o.default.Utils=o.default.Utils||{},o.default.Utils.typeChecks=u,o.default.Utils.absolutizeUrl=s,o.default.Utils.formatType=l,o.default.Utils.getMimeFromType=d,o.default.Utils.getTypeFromFile=f,o.default.Utils.getExtension=c,o.default.Utils.normalizeExtension=p},{4:4,8:8}]},{},[6]); |
@@ -135,8 +135,7 @@ # API and Configuration | ||
useFakeFullscreen | boolean | `false` | Flag to bypass native capabilities on mobile devices and use the fake-fullscreen mode | ||
tracksAriaLive | boolean | `false` | By default, no WAI-ARIA live region - don't make a screen reader speak captions over an audio track. | ||
hideCaptionsButtonWhenEmpty | boolean | `true` | Option to remove the `[cc]` button when no `<track kind="subtitles">` are present | ||
captionTextPreprocessor | function | _not set_ | Option to preprocess the caption text before it is displayed. If set, it expects a function which takes in caption text and returns a preprocessed version thereof. If it is not set, the caption text is displayed as is. | ||
toggleCaptionsButtonWhenOnlyOne | boolean | `false` | If true and we only have one track, change captions to toggle button | ||
startLanguage | string | _(empty)_ | Automatically turn on a `<track>` element. Note: Will not work when toggleCaptionsButtonWhenOnlyOne is set to `true` | ||
slidesSelector | string | _(empty)_ | Selector for slides; could be any valid JavaScript selector (`#id`, `.class`, `img`, etc.) | ||
defaultTrackLine | number/boolean | -3 | Default cue line in which to display cues if the cue is set to "auto" (no line entry in VTT). Can be set to `false` to disable. | ||
autoplayCaptionLanguage | string | `null` | Automatically turn on a subtitles/captions of the corresponfing language; overrides "default" attribute on track element. | ||
chaptersLanguage | string | `null` | Set the language of the chapters track. If only one chapter track exists it will always be used. If multiple chapter tracks exist the player will try to find one using `chaptersLanguage` or the current player language. If none is found the first one defined will be used for the chapter display. | ||
hideScreenReaderTitle | boolean | false | Hide the video player screen reader title so it can be added by the website | ||
@@ -143,0 +142,0 @@ tracksText | string | `null` | Title for Closed Captioning button for WARIA purposes |
# Migration Guide | ||
## Migrating from `5.x` to `6.x` version | ||
Version 6.0.0 removed the custom subtitle parsing in favor of browser native support which has greatly improved over the | ||
last years. VTT subtitles can be used for styled subtitles (using the ::cue CSS selector) and positioning etc. For a | ||
list of currently supported features, please refer to https://developer.mozilla.org/en-US/docs/Web/API/WebVTT_API#browser_compatibility. | ||
* The support for "slides"-tracks was removed as it was non-functional in the last versions and is not natively supported. If you need this feature you can add a "metadata" track and add custom logic to display the data therein. | ||
* "tracksAriaLive", "captionTextPreprocessor", "slidesSelector" options are no longer used and can be removed | ||
* "startLanguage" option was renamed to "autoplayCaptionLanguage" | ||
## Migrating from `4.x` to `5.x` version | ||
@@ -4,0 +15,0 @@ |
Package.describe({ | ||
name: 'johndyer:mediaelement', | ||
summary: '*Official* MediaElement.js: <video> and <audio> made easy. One file. Any browser. Same UI.', | ||
version: '5.1.1', | ||
version: '6.0.0', | ||
git: 'https://github.com/mediaelement/mediaelement' | ||
@@ -6,0 +6,0 @@ }); |
{ | ||
"name": "mediaelement", | ||
"license": "MIT", | ||
"version": "5.1.1", | ||
"version": "6.0.0", | ||
"main": "full.js", | ||
@@ -6,0 +6,0 @@ "repository": { |
@@ -9,3 +9,3 @@ 'use strict'; | ||
// version number | ||
mejs.version = '5.1.1'; | ||
mejs.version = '6.0.0'; | ||
@@ -12,0 +12,0 @@ // Basic HTML5 settings |
@@ -8,5 +8,4 @@ 'use strict'; | ||
import MediaElementPlayer from '../player'; | ||
import {convertSMPTEtoSeconds} from '../utils/time'; | ||
import {isString, createEvent} from '../utils/general'; | ||
import {addClass, removeClass, hasClass, siblings, ajax, fadeIn, fadeOut, visible} from '../utils/dom'; | ||
import {addClass, removeClass, hasClass, siblings} from '../utils/dom'; | ||
import {generateControlButton} from '../utils/generate'; | ||
@@ -23,763 +22,743 @@ | ||
Object.assign(config, { | ||
/** | ||
* Default language to start media using ISO 639-2 Language Code List (en, es, it, etc.) | ||
* If there are multiple tracks for one language, the last track node found is activated | ||
* @see https://www.loc.gov/standards/iso639-2/php/code_list.php | ||
* @type {String} | ||
*/ | ||
startLanguage: '', | ||
/** | ||
* @type {?String} | ||
*/ | ||
tracksText: null, | ||
/** | ||
* @type {?String} | ||
*/ | ||
chaptersText: null, | ||
/** | ||
* Avoid to screen reader speak captions over an audio track. | ||
* | ||
* @type {Boolean} | ||
*/ | ||
tracksAriaLive: false, | ||
/** | ||
* Remove the [cc] button when no track nodes are present | ||
* @type {Boolean} | ||
*/ | ||
hideCaptionsButtonWhenEmpty: true, | ||
/** | ||
* Change captions to pop-up if true and only one track node is found | ||
* @type {Boolean} | ||
*/ | ||
toggleCaptionsButtonWhenOnlyOne: false, | ||
/** | ||
* @type {String} | ||
*/ | ||
slidesSelector: '' | ||
/** | ||
* Default language to start media using ISO 639-2 Language Code List (en, es, it, etc.) | ||
* If there are multiple tracks for one language, the last track node loaded is activated | ||
* @see https://www.loc.gov/standards/iso639-2/php/code_list.php | ||
* @type {?String} | ||
*/ | ||
autoplayCaptionLanguage: null, | ||
/** | ||
* Default cue line in which to display cues if the cue is set to "auto" (no line entry in VTT). The default of -3 is | ||
* positioned slightly above the player controls. | ||
* @type {?(Number|Boolean)} | ||
*/ | ||
defaultTrackLine: -3, | ||
/** | ||
* @type {?String} | ||
*/ | ||
tracksText: null, | ||
/** | ||
* @type {?String} | ||
*/ | ||
chaptersText: null, | ||
/** | ||
* Language to use if multiple chapter tracks are present. If not set, the first available chapter will be used. | ||
* ISO 639-2 Language Code (en, es, it, etc.) | ||
* @type {?String} | ||
*/ | ||
chaptersLanguage: null, | ||
/** | ||
* Remove the [cc] button when no track nodes are present | ||
* @type {Boolean} | ||
*/ | ||
hideCaptionsButtonWhenEmpty: true, | ||
/** | ||
* Change captions to pop-up if true and only one track node is found | ||
* @type {Boolean} | ||
*/ | ||
toggleCaptionsButtonWhenOnlyOne: false, | ||
}); | ||
Object.assign(MediaElementPlayer.prototype, { | ||
/** | ||
* @type {Boolean} | ||
*/ | ||
hasChapters: false, | ||
/** | ||
* @type {Boolean} | ||
*/ | ||
hasChapters: false, | ||
/** | ||
* Feature constructor. | ||
* | ||
* Always has to be prefixed with `build` and the name that will be used in MepDefaults.features list | ||
* @param {MediaElementPlayer} player | ||
* @param {HTMLElement} controls | ||
* @param {HTMLElement} layers | ||
* @param {HTMLElement} media | ||
*/ | ||
buildtracks (player, controls, layers, media) { | ||
/** | ||
* Feature constructor. | ||
* | ||
* Always has to be prefixed with `build` and the name that will be used in MepDefaults.features list | ||
* @param {MediaElementPlayer} player | ||
* @param {HTMLElement} controls | ||
*/ | ||
buildtracks (player, controls) { | ||
this.initTracks(player); | ||
this.findTracks(); | ||
if (!player.tracks.length && (!player.trackFiles || !player.trackFiles.length === 0)) { | ||
return; | ||
} | ||
if (!player.tracks.length && (!player.trackFiles || !player.trackFiles.length === 0)) { | ||
return; | ||
} | ||
const | ||
t = this, | ||
tracksTitle = isString(t.options.tracksText) ? t.options.tracksText : i18n.t('mejs.captions-subtitles'), | ||
chaptersTitle = isString(t.options.chaptersText) ? t.options.chaptersText : i18n.t('mejs.captions-chapters') | ||
; | ||
const | ||
t = this, | ||
attr = t.options.tracksAriaLive ? ' role="log" aria-live="assertive" aria-atomic="false"' : '', | ||
tracksTitle = isString(t.options.tracksText) ? t.options.tracksText : i18n.t('mejs.captions-subtitles'), | ||
chaptersTitle = isString(t.options.chaptersText) ? t.options.chaptersText : i18n.t('mejs.captions-chapters'), | ||
total = player.trackFiles === null ? player.tracks.length : player.trackFiles.length | ||
; | ||
// Hide all tracks initially (mode 'hidden' triggers loading) | ||
t.hideAllTracks(); | ||
// If browser will do native captions, prefer mejs captions, loop through tracks and hide | ||
if (t.domNode.textTracks) { | ||
for (let i = t.domNode.textTracks.length - 1; i >= 0; i--) { | ||
t.domNode.textTracks[i].mode = 'hidden'; | ||
} | ||
} | ||
t.clearTrackHtml(player); | ||
t.cleartracks(player); | ||
player.captionsButton = document.createElement('div'); | ||
player.captionsButton.className = `${t.options.classPrefix}button ${t.options.classPrefix}captions-button`; | ||
player.captionsButton.innerHTML = | ||
generateControlButton(t.id, tracksTitle, tracksTitle, `${t.media.options.iconSprite}`, ['icon-captions'], `${t.options.classPrefix}`) + | ||
`<div class="${t.options.classPrefix}captions-selector ${t.options.classPrefix}offscreen">` + | ||
`<ul class="${t.options.classPrefix}captions-selector-list">` + | ||
`<li class="${t.options.classPrefix}captions-selector-list-item">` + | ||
`<input type="radio" class="${t.options.classPrefix}captions-selector-input" ` + | ||
`name="${player.id}_captions" id="${player.id}_captions_none" ` + | ||
`value="none" checked disabled>` + | ||
`<label class="${t.options.classPrefix}captions-selector-label ` + | ||
`${t.options.classPrefix}captions-selected" ` + | ||
`for="${player.id}_captions_none">${i18n.t('mejs.none')}</label>` + | ||
`</li>` + | ||
`</ul>` + | ||
`</div>`; | ||
player.captions = document.createElement('div'); | ||
player.captions.className = `${t.options.classPrefix}captions-layer ${t.options.classPrefix}layer`; | ||
player.captions.innerHTML = `<div class="${t.options.classPrefix}captions-position ${t.options.classPrefix}captions-position-hover"${attr}>` + | ||
`<span class="${t.options.classPrefix}captions-text"></span>` + | ||
`</div>`; | ||
player.captions.style.display = 'none'; | ||
layers.insertBefore(player.captions, layers.firstChild); | ||
t.addControlElement(player.captionsButton, 'tracks'); | ||
player.captionsText = player.captions.querySelector(`.${t.options.classPrefix}captions-text`); | ||
player.captionsButton.querySelector(`.${t.options.classPrefix}captions-selector-input`).disabled = false; | ||
player.captionsButton = document.createElement('div'); | ||
player.captionsButton.className = `${t.options.classPrefix}button ${t.options.classPrefix}captions-button`; | ||
player.captionsButton.innerHTML = | ||
generateControlButton(t.id, tracksTitle, tracksTitle, `${t.media.options.iconSprite}`, ['icon-captions'], `${t.options.classPrefix}`) + | ||
`<div class="${t.options.classPrefix}captions-selector ${t.options.classPrefix}offscreen">` + | ||
`<ul class="${t.options.classPrefix}captions-selector-list">` + | ||
`<li class="${t.options.classPrefix}captions-selector-list-item">` + | ||
`<input type="radio" class="${t.options.classPrefix}captions-selector-input" ` + | ||
`name="${player.id}_captions" id="${player.id}_captions_none" ` + | ||
`value="none" checked disabled>` + | ||
`<label class="${t.options.classPrefix}captions-selector-label ` + | ||
`${t.options.classPrefix}captions-selected" ` + | ||
`for="${player.id}_captions_none">${i18n.t('mejs.none')}</label>` + | ||
`</li>` + | ||
`</ul>` + | ||
`</div>`; | ||
player.chaptersButton = document.createElement('div'); | ||
player.chaptersButton.className = `${t.options.classPrefix}button ${t.options.classPrefix}chapters-button`; | ||
player.chaptersButton.innerHTML = | ||
generateControlButton(t.id, chaptersTitle, chaptersTitle, `${t.media.options.iconSprite}`, ['icon-chapters'], `${t.options.classPrefix}`) + | ||
`<div class="${t.options.classPrefix}chapters-selector ${t.options.classPrefix}offscreen">` + | ||
`<ul class="${t.options.classPrefix}chapters-selector-list"></ul>` + | ||
`</div>`; | ||
t.addControlElement(player.captionsButton, 'tracks'); | ||
const subtitles = t.getSubtitles(); | ||
const chapters = t.getChapters(); | ||
player.captionsButton.querySelector(`.${t.options.classPrefix}captions-selector-input`).disabled = false; | ||
// add chapters button | ||
if (chapters.length > 0 && !controls.querySelector(`.${t.options.classPrefix}chapter-selector`)) { | ||
player.captionsButton.parentNode.insertBefore(player.chaptersButton, player.captionsButton); | ||
} | ||
player.chaptersButton = document.createElement('div'); | ||
player.chaptersButton.className = `${t.options.classPrefix}button ${t.options.classPrefix}chapters-button`; | ||
player.chaptersButton.innerHTML = | ||
generateControlButton(t.id, chaptersTitle, chaptersTitle, `${t.media.options.iconSprite}`, ['icon-chapters'], `${t.options.classPrefix}`) + | ||
`<div class="${t.options.classPrefix}chapters-selector ${t.options.classPrefix}offscreen">` + | ||
`<ul class="${t.options.classPrefix}chapters-selector-list"></ul>` + | ||
`</div>`; | ||
// add subtitles | ||
for (let i = 0; i < subtitles.length; i++) { | ||
player.addTrackButton(subtitles[i]); | ||
if (subtitles[i].isLoaded) { | ||
// subtitles can already be loaded by the browser before UI exists, so the UI could not be updated by the load | ||
// event. So we enable the button, if its state show it has been loaded. | ||
t.enableTrackButton(subtitles[i]); | ||
} | ||
} | ||
let subtitleCount = 0; | ||
player.trackToLoad = -1; | ||
player.selectedTrack = null; | ||
player.isLoadingTrack = false; | ||
for (let i = 0; i < total; i++) { | ||
const | ||
kind = player.tracks[i].kind, | ||
src = player.tracks[i].src | ||
; | ||
if (src.trim()) { | ||
if (kind === 'subtitles' || kind === 'captions') { | ||
subtitleCount++; | ||
} else if (kind === 'chapters' && !controls.querySelector(`.${t.options.classPrefix}chapter-selector`)) { | ||
player.captionsButton.parentNode.insertBefore(player.chaptersButton, player.captionsButton); | ||
} | ||
} | ||
} | ||
const | ||
inEvents = ['mouseenter', 'focusin'], | ||
outEvents = ['mouseleave', 'focusout'] | ||
; | ||
player.trackToLoad = -1; | ||
player.selectedTrack = null; | ||
player.isLoadingTrack = false; | ||
// if only one language then just make the button a toggle | ||
if (t.options.toggleCaptionsButtonWhenOnlyOne && subtitles.length === 1) { | ||
player.captionsButton.addEventListener('click', (e) => { | ||
let trackId = 'none'; | ||
if (player.selectedTrack === null) { | ||
trackId = player.getSubtitles()[0].trackId; | ||
} | ||
const keyboard = e.keyCode || e.which; | ||
player.setTrack(trackId, (typeof keyboard !== 'undefined')); | ||
}); | ||
} else { | ||
const | ||
labels = player.captionsButton.querySelectorAll(`.${t.options.classPrefix}captions-selector-label`), | ||
captions = player.captionsButton.querySelectorAll('input[type=radio]') | ||
; | ||
// add to list | ||
for (let i = 0; i < total; i++) { | ||
const kind = player.tracks[i].kind; | ||
if (player.tracks[i].src.trim() && (kind === 'subtitles' || kind === 'captions')) { | ||
player.addTrackButton(player.tracks[i].trackId, player.tracks[i].srclang, player.tracks[i].label); | ||
} | ||
} | ||
for (let i = 0; i < inEvents.length; i++) { | ||
player.captionsButton.addEventListener(inEvents[i], function () { | ||
removeClass(this.querySelector(`.${t.options.classPrefix}captions-selector`), `${t.options.classPrefix}offscreen`); | ||
}); | ||
} | ||
// start loading tracks | ||
player.loadNextTrack(); | ||
for (let i = 0; i < outEvents.length; i++) { | ||
player.captionsButton.addEventListener(outEvents[i], function () { | ||
addClass(this.querySelector(`.${t.options.classPrefix}captions-selector`), `${t.options.classPrefix}offscreen`); | ||
}); | ||
} | ||
const | ||
inEvents = ['mouseenter', 'focusin'], | ||
outEvents = ['mouseleave', 'focusout'] | ||
; | ||
for (let i = 0; i < captions.length; i++) { | ||
captions[i].addEventListener('click', function (e) { | ||
// value is trackId, same as the actual id, and we're using it here | ||
// because the "none" checkbox doesn't have a trackId | ||
// to use, but we want to know when "none" is clicked | ||
const keyboard = e.keyCode || e.which; | ||
if (!e.target.disabled) { | ||
player.setTrack(this.value, (typeof keyboard !== 'undefined')); | ||
} | ||
}); | ||
} | ||
// if only one language then just make the button a toggle | ||
if (t.options.toggleCaptionsButtonWhenOnlyOne && subtitleCount === 1) { | ||
player.captionsButton.addEventListener('click', (e) => { | ||
let trackId = 'none'; | ||
if (player.selectedTrack === null) { | ||
trackId = player.tracks[0].trackId; | ||
} | ||
const keyboard = e.keyCode || e.which; | ||
player.setTrack(trackId, (typeof keyboard !== 'undefined')); | ||
}); | ||
} else { | ||
const | ||
labels = player.captionsButton.querySelectorAll(`.${t.options.classPrefix}captions-selector-label`), | ||
captions = player.captionsButton.querySelectorAll('input[type=radio]') | ||
; | ||
for (let i = 0; i < labels.length; i++) { | ||
labels[i].addEventListener('click', function (e) { | ||
const | ||
radio = siblings(this, (el) => el.tagName === 'INPUT')[0], | ||
event = createEvent('click', radio) | ||
; | ||
radio.dispatchEvent(event); | ||
e.preventDefault(); | ||
}); | ||
} | ||
for (let i = 0, total = inEvents.length; i < total; i++) { | ||
player.captionsButton.addEventListener(inEvents[i], function () { | ||
removeClass(this.querySelector(`.${t.options.classPrefix}captions-selector`), `${t.options.classPrefix}offscreen`); | ||
}); | ||
} | ||
//Allow up/down arrow to change the selected radio without changing the volume. | ||
player.captionsButton.addEventListener('keydown', (e) => { | ||
e.stopPropagation(); | ||
}); | ||
} | ||
for (let i = 0, total = outEvents.length; i < total; i++) { | ||
player.captionsButton.addEventListener(outEvents[i], function () { | ||
addClass(this.querySelector(`.${t.options.classPrefix}captions-selector`), `${t.options.classPrefix}offscreen`); | ||
}); | ||
} | ||
for (let i = 0; i < inEvents.length; i++) { | ||
player.chaptersButton.addEventListener(inEvents[i], function () { | ||
if (this.querySelector(`.${t.options.classPrefix}chapters-selector-list`).children.length) { | ||
removeClass(this.querySelector(`.${t.options.classPrefix}chapters-selector`), `${t.options.classPrefix}offscreen`); | ||
} | ||
}); | ||
} | ||
for (let i = 0, total = captions.length; i < total; i++) { | ||
captions[i].addEventListener('click', function (e) { | ||
// value is trackId, same as the actual id, and we're using it here | ||
// because the "none" checkbox doesn't have a trackId | ||
// to use, but we want to know when "none" is clicked | ||
const keyboard = e.keyCode || e.which; | ||
player.setTrack(this.value, (typeof keyboard !== 'undefined')); | ||
}); | ||
} | ||
for (let i = 0; i < outEvents.length; i++) { | ||
player.chaptersButton.addEventListener(outEvents[i], function () { | ||
addClass(this.querySelector(`.${t.options.classPrefix}chapters-selector`), `${t.options.classPrefix}offscreen`); | ||
}); | ||
} | ||
for (let i = 0, total = labels.length; i < total; i++) { | ||
labels[i].addEventListener('click', function (e) { | ||
const | ||
radio = siblings(this, (el) => el.tagName === 'INPUT')[0], | ||
event = createEvent('click', radio) | ||
; | ||
radio.dispatchEvent(event); | ||
e.preventDefault(); | ||
}); | ||
} | ||
//Allow up/down arrow to change the selected radio without changing the volume. | ||
player.chaptersButton.addEventListener('keydown', (e) => { | ||
e.stopPropagation(); | ||
}); | ||
//Allow up/down arrow to change the selected radio without changing the volume. | ||
player.captionsButton.addEventListener('keydown', (e) => { | ||
e.stopPropagation(); | ||
}); | ||
} | ||
// trigger track load checks in case the browser loaded them before the UI was set up (can happen with "default") | ||
t.checkAllCaptionsLoadedOrError(); | ||
t.checkAllChaptersLoadedOrError(); | ||
}, | ||
for (let i = 0, total = inEvents.length; i < total; i++) { | ||
player.chaptersButton.addEventListener(inEvents[i], function () { | ||
if (this.querySelector(`.${t.options.classPrefix}chapters-selector-list`).children.length) { | ||
removeClass(this.querySelector(`.${t.options.classPrefix}chapters-selector`), `${t.options.classPrefix}offscreen`); | ||
} | ||
}); | ||
} | ||
/** | ||
* Feature destructor. | ||
* | ||
* Always has to be prefixed with `clean` and the name that was used in MepDefaults.features list | ||
* @param {MediaElementPlayer} player | ||
*/ | ||
clearTrackHtml (player) { | ||
if (player) { | ||
if (player.captionsButton) { | ||
player.captionsButton.remove(); | ||
} | ||
if (player.chaptersButton) { | ||
player.chaptersButton.remove(); | ||
} | ||
} | ||
}, | ||
for (let i = 0, total = outEvents.length; i < total; i++) { | ||
player.chaptersButton.addEventListener(outEvents[i], function () { | ||
addClass(this.querySelector(`.${t.options.classPrefix}chapters-selector`), `${t.options.classPrefix}offscreen`); | ||
}); | ||
} | ||
rebuildtracks () { | ||
const t = this; | ||
t.findTracks(); | ||
t.buildtracks(t, t.getElement(t.controls)); | ||
}, | ||
//Allow up/down arrow to change the selected radio without changing the volume. | ||
player.chaptersButton.addEventListener('keydown', (e) => { | ||
e.stopPropagation(); | ||
}); | ||
/** | ||
* Check for track files and setup event handlers and local track data. | ||
* @param {MediaElementPlayer} player | ||
*/ | ||
initTracks (player) { | ||
const | ||
t = this, | ||
trackFiles = t.trackFiles === null ? t.node.querySelectorAll('track') : t.trackFiles | ||
; | ||
// store for use by plugins | ||
t.tracks = []; | ||
if (!player.options.alwaysShowControls) { | ||
// move with controls | ||
player.getElement(player.container).addEventListener('controlsshown', () => { | ||
// push captions above controls | ||
addClass(player.getElement(player.container).querySelector(`.${t.options.classPrefix}captions-position`), `${t.options.classPrefix}captions-position-hover`); | ||
}); | ||
if (trackFiles) { | ||
player.trackFiles = trackFiles; | ||
for (let i = 0; i < trackFiles.length; i++) { | ||
const | ||
track = trackFiles[i], | ||
srclang = track.getAttribute('srclang').toLowerCase() || '', | ||
trackId = track.getAttribute('id') || `${t.id}_track_${i}_${track.getAttribute('kind')}_${srclang}` | ||
; | ||
track.setAttribute('id', trackId); | ||
player.getElement(player.container).addEventListener('controlshidden', () => { | ||
if (!media.paused) { | ||
// move back to normal place | ||
removeClass(player.getElement(player.container).querySelector(`.${t.options.classPrefix}captions-position`), `${t.options.classPrefix}captions-position-hover`); | ||
} | ||
}); | ||
} else { | ||
addClass(player.getElement(player.container).querySelector(`.${t.options.classPrefix}captions-position`), `${t.options.classPrefix}captions-position-hover`); | ||
} | ||
const trackData = { | ||
trackId: trackId, | ||
srclang: srclang, | ||
src: track.getAttribute('src'), | ||
kind: track.getAttribute('kind'), | ||
label: track.getAttribute('label') || '', | ||
entries: [], | ||
isDefault: track.hasAttribute('default'), | ||
isError: false, | ||
isLoaded: false | ||
}; | ||
t.tracks.push(trackData); | ||
media.addEventListener('timeupdate', () => { | ||
player.displayCaptions(); | ||
}); | ||
if (track.getAttribute('kind') === 'captions' || track.getAttribute('kind') === 'subtitles') { | ||
// caption / subtitle handling | ||
switch (track.readyState) { | ||
case 2: | ||
// already loaded | ||
t.handleCaptionsLoaded(track); | ||
break; | ||
case 3: | ||
// quit loading with error | ||
t.handleCaptionsError(track); | ||
break; | ||
default: | ||
// is going to be loaded | ||
track.addEventListener('load', (event) => { | ||
t.handleCaptionsLoaded(event.target); | ||
}); | ||
track.addEventListener('error', (event) => { | ||
t.handleCaptionsError(event.target); | ||
}); | ||
break; | ||
} | ||
} else if (track.getAttribute('kind') === 'chapters') { | ||
// chapter handling | ||
switch (track.readyState) { | ||
case 2: | ||
t.handleChaptersLoaded(track); | ||
break; | ||
case 3: | ||
t.handleChaptersError(track); | ||
break; | ||
default: | ||
track.addEventListener('load', (event) => { | ||
t.handleChaptersLoaded(event.target); | ||
}); | ||
track.addEventListener('error', (event) => { | ||
t.handleChaptersError(event.target); | ||
}); | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
if (player.options.slidesSelector !== '') { | ||
player.slidesContainer = document.querySelectorAll(player.options.slidesSelector); | ||
/** | ||
* Load handler for captions and subtitles. Change cue lines if set to auto. | ||
* @param {Element} target Video track element | ||
*/ | ||
handleCaptionsLoaded(target) { | ||
const | ||
textTracks = this.domNode.textTracks, | ||
playerTrack = this.getTrackById(target.getAttribute('id')); | ||
media.addEventListener('timeupdate', () => { | ||
player.displaySlides(); | ||
}); | ||
} | ||
}, | ||
// Set default cue line | ||
if (Number.isInteger(this.options.defaultTrackLine)) { | ||
for (let i = 0; i < textTracks.length; i++) { | ||
if (target.getAttribute('srclang') === textTracks[i].language | ||
&& target.getAttribute('kind') === textTracks[i].kind) { | ||
const cues = textTracks[i].cues; | ||
for (let c = 0; c < cues.length; c++) { | ||
if (cues[c].line === 'auto' || cues[c].line === undefined || cues[c].line === null) { | ||
cues[c].line = this.options.defaultTrackLine; | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
/** | ||
* Feature destructor. | ||
* | ||
* Always has to be prefixed with `clean` and the name that was used in MepDefaults.features list | ||
* @param {MediaElementPlayer} player | ||
*/ | ||
cleartracks (player) { | ||
if (player) { | ||
if (player.captions) { | ||
player.captions.remove(); | ||
} | ||
if (player.chapters) { | ||
player.chapters.remove(); | ||
} | ||
if (player.captionsText) { | ||
player.captionsText.remove(); | ||
} | ||
if (player.captionsButton) { | ||
player.captionsButton.remove(); | ||
} | ||
if (player.chaptersButton) { | ||
player.chaptersButton.remove(); | ||
} | ||
} | ||
}, | ||
// set state & active player button | ||
playerTrack.isLoaded = true; | ||
this.enableTrackButton(playerTrack); | ||
this.checkAllCaptionsLoadedOrError(); | ||
}, | ||
rebuildtracks () { | ||
const t = this; | ||
t.findTracks(); | ||
t.buildtracks(t, t.getElement(t.controls), t.getElement(t.layers), t.media); | ||
}, | ||
/** | ||
* Error handler for captions and subtitles. Removs the captions button for erroneous tracks. | ||
* @param {Element} target Video track element | ||
*/ | ||
handleCaptionsError(target) { | ||
const playerTrack = this.getTrackById(target.getAttribute('id')); | ||
findTracks () { | ||
const | ||
t = this, | ||
tracktags = t.trackFiles === null ? t.node.querySelectorAll('track') : t.trackFiles, | ||
total = tracktags.length | ||
; | ||
playerTrack.isError = true; | ||
this.removeTrackButton(playerTrack); | ||
this.checkAllCaptionsLoadedOrError(); | ||
}, | ||
// store for use by plugins | ||
t.tracks = []; | ||
for (let i = 0; i < total; i++) { | ||
const | ||
track = tracktags[i], | ||
srclang = track.getAttribute('srclang').toLowerCase() || '', | ||
trackId = `${t.id}_track_${i}_${track.getAttribute('kind')}_${srclang}` | ||
; | ||
t.tracks.push({ | ||
trackId: trackId, | ||
srclang: srclang, | ||
src: track.getAttribute('src'), | ||
kind: track.getAttribute('kind'), | ||
label: track.getAttribute('label') || '', | ||
entries: [], | ||
isLoaded: false | ||
}); | ||
} | ||
}, | ||
/** | ||
* Load handler for chapters tracks. | ||
* @param {Element} target Video track element | ||
*/ | ||
handleChaptersLoaded(target) { | ||
const playerTrack = this.getTrackById(target.getAttribute('id')); | ||
/** | ||
* | ||
* @param {String} trackId, or "none" to disable captions | ||
* @param {Boolean} setByKeyboard | ||
*/ | ||
setTrack (trackId, setByKeyboard) { | ||
this.hasChapters = true; | ||
playerTrack.isLoaded = true; | ||
this.checkAllChaptersLoadedOrError(); | ||
}, | ||
const | ||
t = this, | ||
radios = t.captionsButton.querySelectorAll('input[type="radio"]'), | ||
captions = t.captionsButton.querySelectorAll(`.${t.options.classPrefix}captions-selected`), | ||
track = t.captionsButton.querySelector(`input[value="${trackId}"]`) | ||
; | ||
/** | ||
* Error handler for chapters tracks. | ||
* @param {Element} target Video track element | ||
*/ | ||
handleChaptersError(target) { | ||
const playerTrack = this.getTrackById(target.getAttribute('id')); | ||
playerTrack.isError = true; | ||
this.checkAllChaptersLoadedOrError(); | ||
}, | ||
for (let i = 0, total = radios.length; i < total; i++) { | ||
radios[i].checked = false; | ||
} | ||
/** | ||
* Once all captions/subtitles are loaded, check if we need to autoplay one of them. | ||
*/ | ||
checkAllCaptionsLoadedOrError() { | ||
const subtitles = this.getSubtitles(); | ||
if (subtitles.length === subtitles.filter(({isLoaded, isError}) => isLoaded || isError).length) { | ||
// no captions/subtitles OR all captions/subtitles loaded or quit loading with error | ||
this.removeCaptionsIfEmpty(); | ||
this.checkForAutoPlay(); | ||
} | ||
}, | ||
for (let i = 0, total = captions.length; i < total; i++) { | ||
removeClass(captions[i], `${t.options.classPrefix}captions-selected`); | ||
} | ||
/** | ||
* Once all chapters are loaded, determine which chapter file should be displayed as the chapters menu. | ||
*/ | ||
checkAllChaptersLoadedOrError() { | ||
const chapters = this.getChapters(), | ||
readyChapters = chapters.filter(({isLoaded}) => isLoaded); | ||
if (chapters.length === chapters.filter(({isLoaded, isError}) => isLoaded || isError).length) { | ||
// no chapters OR all chapters loaded or quit loading with error | ||
if (readyChapters.length === 0) { | ||
// no chapters -> remove chapters button | ||
this.chaptersButton.remove(); | ||
} else { | ||
// try to find a chapter track in the language set in `options.chaptersLanguage` | ||
let langChapter = readyChapters.find(({srclang}) => srclang === this.options.chaptersLanguage); | ||
// if none was found try to find one using the current player language | ||
langChapter = langChapter || readyChapters.find(({srclang}) => srclang === i18n.lang); | ||
track.checked = true; | ||
const labels = siblings(track, (el) => hasClass(el, `${t.options.classPrefix}captions-selector-label`)); | ||
for (let i = 0, total = labels.length; i < total; i++) { | ||
addClass(labels[i], `${t.options.classPrefix}captions-selected`) | ||
} | ||
if (readyChapters.length === 1 || !langChapter) { | ||
// use first chapter track if only one exists or no chapter with the correct lanmguage was loaded | ||
this.drawChapters(readyChapters[0].trackId); | ||
} else { | ||
// use the chapter with the correct language | ||
this.drawChapters(langChapter.trackId); | ||
} | ||
} | ||
} | ||
}, | ||
if (trackId === 'none') { | ||
t.selectedTrack = null; | ||
removeClass(t.captionsButton, `${t.options.classPrefix}captions-enabled`); | ||
} else { | ||
for (let i = 0, total = t.tracks.length; i < total; i++) { | ||
const track = t.tracks[i]; | ||
if (track.trackId === trackId) { | ||
if (t.selectedTrack === null) { | ||
addClass(t.captionsButton, `${t.options.classPrefix}captions-enabled`); | ||
} | ||
t.selectedTrack = track; | ||
t.captions.setAttribute('lang', t.selectedTrack.srclang); | ||
t.displayCaptions(); | ||
break; | ||
} | ||
} | ||
} | ||
/** | ||
* | ||
* @param {String} trackId, or "none" to disable captions | ||
* @param {Boolean} setByKeyboard | ||
*/ | ||
setTrack (trackId, setByKeyboard) { | ||
const | ||
t = this, | ||
radios = t.captionsButton.querySelectorAll('input[type="radio"]'), | ||
captions = t.captionsButton.querySelectorAll(`.${t.options.classPrefix}captions-selected`), | ||
track = t.captionsButton.querySelector(`input[value="${trackId}"]`) | ||
; | ||
const event = createEvent('captionschange', t.media); | ||
event.detail.caption = t.selectedTrack; | ||
t.media.dispatchEvent(event); | ||
for (let i = 0; i < radios.length; i++) { | ||
radios[i].checked = false; | ||
} | ||
if (!setByKeyboard) { | ||
setTimeout(function() { | ||
t.getElement(t.container).focus(); | ||
}, 500); | ||
} | ||
}, | ||
for (let i = 0; i < captions.length; i++) { | ||
removeClass(captions[i], `${t.options.classPrefix}captions-selected`); | ||
} | ||
/** | ||
* | ||
*/ | ||
loadNextTrack () { | ||
const t = this; | ||
track.checked = true; | ||
const labels = siblings(track, (el) => hasClass(el, `${t.options.classPrefix}captions-selector-label`)); | ||
for (let i = 0; i < labels.length; i++) { | ||
addClass(labels[i], `${t.options.classPrefix}captions-selected`) | ||
} | ||
t.trackToLoad++; | ||
if (t.trackToLoad < t.tracks.length) { | ||
t.isLoadingTrack = true; | ||
t.loadTrack(t.trackToLoad); | ||
} else { | ||
// add done? | ||
t.isLoadingTrack = false; | ||
t.checkForTracks(); | ||
} | ||
}, | ||
if (trackId === 'none') { | ||
t.selectedTrack = null; | ||
removeClass(t.captionsButton, `${t.options.classPrefix}captions-enabled`); | ||
t.deactivateVideoTracks(); | ||
} else { | ||
const track = t.getTrackById(trackId); | ||
if (track) { | ||
if (t.selectedTrack === null) { | ||
addClass(t.captionsButton, `${t.options.classPrefix}captions-enabled`); | ||
} | ||
t.selectedTrack = track; | ||
t.activateVideoTrack(t.selectedTrack.srclang); | ||
} | ||
} | ||
/** | ||
* | ||
* @param index | ||
*/ | ||
loadTrack (index) { | ||
const | ||
t = this, | ||
track = t.tracks[index] | ||
; | ||
const event = createEvent('captionschange', t.media); | ||
event.detail.caption = t.selectedTrack; | ||
t.media.dispatchEvent(event); | ||
if (track !== undefined && (track.src !== undefined || track.src !== "")) { | ||
ajax(track.src, 'text', (d) => { | ||
track.entries = typeof d === 'string' && (/<tt\s+xml/ig).exec(d) ? | ||
mejs.TrackFormatParser.dfxp.parse(d) : mejs.TrackFormatParser.webvtt.parse(d); | ||
if (!setByKeyboard) { | ||
setTimeout(function() { | ||
t.getElement(t.container).focus(); | ||
}, 500); | ||
} | ||
}, | ||
track.isLoaded = true; | ||
t.enableTrackButton(track); | ||
t.loadNextTrack(); | ||
/** | ||
* Set mode for all tracks to 'hidden' (causes player to load them). | ||
*/ | ||
hideAllTracks() { | ||
if (this.domNode.textTracks) { | ||
// parse through TextTrackList (not an Array) | ||
for (let i = 0; i < this.domNode.textTracks.length; i++) { | ||
this.domNode.textTracks[i].mode = 'hidden'; | ||
} | ||
} | ||
}, | ||
if (track.kind === 'slides') { | ||
t.setupSlides(track); | ||
} | ||
// Load by default the first track with `chapters` kind | ||
else if (track.kind === 'chapters' && !t.hasChapters) { | ||
t.drawChapters(track); | ||
t.hasChapters = true; | ||
} | ||
}, () => { | ||
t.removeTrackButton(track.trackId); | ||
t.loadNextTrack(); | ||
}); | ||
} | ||
}, | ||
/** | ||
* Hide all subtitles/captions. | ||
*/ | ||
deactivateVideoTracks() { | ||
if (this.domNode.textTracks) { | ||
// parse through TextTrackList (not an Array) | ||
for (let i = 0; i < this.domNode.textTracks.length; i++) { | ||
const track = this.domNode.textTracks[i]; | ||
if (track.kind === 'subtitles' || track.kind === 'captions') { | ||
track.mode = 'hidden'; | ||
} | ||
} | ||
} | ||
}, | ||
/** | ||
* | ||
* @param {String} track - The language code | ||
*/ | ||
enableTrackButton (track) { | ||
const | ||
t = this, | ||
lang = track.srclang, | ||
target = document.getElementById(`${track.trackId}`) | ||
; | ||
/** | ||
* Display a specific language and hide all other subtitles/captions. | ||
* @param {string} srclang Language code of the subtitles to display | ||
*/ | ||
activateVideoTrack(srclang) { | ||
// parse through TextTrackList (not an Array) | ||
for (let i = 0; i < this.domNode.textTracks.length; i++) { | ||
const track = this.domNode.textTracks[i]; | ||
// For the 'subtitles-off' button, the first condition will never match so all will subtitles be turned off | ||
if (track.kind === 'subtitles' || track.kind === 'captions') { | ||
if (track.language === srclang) { | ||
track.mode = 'showing'; | ||
} else { | ||
track.mode = 'hidden'; | ||
} | ||
} | ||
} | ||
}, | ||
if (!target) { | ||
return; | ||
} | ||
/** | ||
* Check if we need to start playing any subtitle track. | ||
*/ | ||
checkForAutoPlay() { | ||
// select track to automatically play; prefer autoplayCaptionLanguage to default | ||
const | ||
readySubtitles = this.getSubtitles().filter(({isError}) => !isError), | ||
autoplayTrack = | ||
readySubtitles.find(({srclang}) => this.options.autoplayCaptionLanguage === srclang) || | ||
readySubtitles.find(({isDefault}) => isDefault); | ||
let label = track.label; | ||
if (autoplayTrack) { | ||
if (this.options.toggleCaptionsButtonWhenOnlyOne && readySubtitles.length === 1 && this.captionsButton) { | ||
this.captionsButton.dispatchEvent(createEvent('click', this.captionsButton)); | ||
} else { | ||
const target = document.getElementById(`${autoplayTrack.trackId}-btn`) | ||
if (target) { | ||
target.checked = true; | ||
target.dispatchEvent(createEvent('click', target)); | ||
} | ||
} | ||
} | ||
}, | ||
if (label === '') { | ||
label = i18n.t(mejs.language.codes[lang]) || lang; | ||
} | ||
target.disabled = false; | ||
const targetSiblings = siblings(target, (el) => hasClass(el, `${t.options.classPrefix}captions-selector-label`)); | ||
for (let i = 0, total = targetSiblings.length; i < total; i++) { | ||
targetSiblings[i].innerHTML = label; | ||
} | ||
/** | ||
* Enable the input for the caption/subtitle and remove the "loading" notification from the label. | ||
* @param {object} track | ||
*/ | ||
enableTrackButton (track) { | ||
const | ||
t = this, | ||
lang = track.srclang, | ||
target = document.getElementById(`${track.trackId}-btn`) | ||
; | ||
if (!target) { | ||
return; | ||
} | ||
// auto select | ||
if (t.options.startLanguage === lang) { | ||
target.checked = true; | ||
const event = createEvent('click', target); | ||
target.dispatchEvent(event); | ||
} | ||
}, | ||
let label = track.label; | ||
/** | ||
* | ||
* @param {String} trackId | ||
*/ | ||
removeTrackButton (trackId) { | ||
const element = document.getElementById(`${trackId}`); | ||
if (element) { | ||
const button = element.closest('li'); | ||
if (button) { | ||
button.remove(); | ||
} | ||
} | ||
}, | ||
if (label === '') { | ||
label = i18n.t(mejs.language.codes[lang]) || lang; | ||
} | ||
target.disabled = false; | ||
const targetSiblings = siblings(target, (el) => hasClass(el, `${t.options.classPrefix}captions-selector-label`)); | ||
for (let i = 0; i < targetSiblings.length; i++) { | ||
targetSiblings[i].innerHTML = label; | ||
} | ||
}, | ||
/** | ||
* | ||
* @param {String} trackId | ||
* @param {String} lang - The language code | ||
* @param {String} label | ||
*/ | ||
addTrackButton (trackId, lang, label) { | ||
const t = this; | ||
if (label === '') { | ||
label = i18n.t(mejs.language.codes[lang]) || lang; | ||
} | ||
/** | ||
* Removes a track button. | ||
* @param {object} track | ||
*/ | ||
removeTrackButton (track) { | ||
const element = document.getElementById(`${track.trackId}-btn`); | ||
if (element) { | ||
const button = element.closest('li'); | ||
if (button) { | ||
button.remove(); | ||
} | ||
} | ||
}, | ||
// trackId is used in the value, too, because the "none" | ||
// caption option doesn't have a trackId but we need to be able | ||
// to set it, too | ||
t.captionsButton.querySelector('ul').innerHTML += `<li class="${t.options.classPrefix}captions-selector-list-item">` + | ||
`<input type="radio" class="${t.options.classPrefix}captions-selector-input" ` + | ||
`name="${t.id}_captions" id="${trackId}" value="${trackId}" disabled>` + | ||
`<label class="${t.options.classPrefix}captions-selector-label"` + | ||
`for="${trackId}">${label} (loading)</label>` + | ||
`</li>`; | ||
}, | ||
/** | ||
* Adds a new track button. | ||
* @param {object} track | ||
*/ | ||
addTrackButton (track) { | ||
const | ||
t = this, | ||
label = track.label || i18n.t(mejs.language.codes[track.srclang]) || track.srclang; | ||
/** | ||
* | ||
*/ | ||
checkForTracks () { | ||
const t = this; | ||
// trackId is used in the value, too, because the "none" | ||
// caption option doesn't have a trackId but we need to be able | ||
// to set it, too | ||
t.captionsButton.querySelector('ul').innerHTML += `<li class="${t.options.classPrefix}captions-selector-list-item">` + | ||
`<input type="radio" class="${t.options.classPrefix}captions-selector-input" ` + | ||
`name="${t.id}_captions" id="${track.trackId}-btn" value="${track.trackId}" disabled>` + | ||
`<label class="${t.options.classPrefix}captions-selector-label"` + | ||
`for="${track.trackId}">${label} (loading)</label>` + | ||
`</li>`; | ||
}, | ||
let hasSubtitles = false; | ||
/** | ||
* If no captions exist, remove the button. | ||
*/ | ||
removeCaptionsIfEmpty() { | ||
if (this.captionsButton && this.options.hideCaptionsButtonWhenEmpty) { | ||
const subtitleCount = this.getSubtitles().filter(({isError}) => !isError).length; | ||
this.captionsButton.style.display = subtitleCount > 0 ? '' : 'none'; | ||
this.setControlsSize(); | ||
} | ||
}, | ||
// check if any subtitles | ||
if (t.options.hideCaptionsButtonWhenEmpty) { | ||
for (let i = 0, total = t.tracks.length; i < total; i++) { | ||
const kind = t.tracks[i].kind; | ||
if ((kind === 'subtitles' || kind === 'captions') && t.tracks[i].isLoaded) { | ||
hasSubtitles = true; | ||
break; | ||
} | ||
} | ||
/** | ||
* Draw the chapters menu. | ||
*/ | ||
drawChapters (chapterTrackId) { | ||
const | ||
t = this, | ||
chapter = this.domNode.textTracks.getTrackById(chapterTrackId), | ||
numberOfChapters = chapter.cues.length | ||
; | ||
t.captionsButton.style.display = hasSubtitles ? '' : 'none'; | ||
t.setControlsSize(); | ||
} | ||
}, | ||
if (!numberOfChapters) { | ||
return; | ||
} | ||
/** | ||
* | ||
*/ | ||
displayCaptions () { | ||
if (this.tracks === undefined) { | ||
return; | ||
} | ||
t.chaptersButton.querySelector('ul').innerHTML = ''; | ||
const | ||
t = this, | ||
track = t.selectedTrack, | ||
sanitize = (html) => { | ||
const div = document.createElement('div'); | ||
div.innerHTML = html; | ||
for (let i = 0; i < numberOfChapters; i++) { | ||
t.chaptersButton.querySelector('ul').innerHTML += `<li class="${t.options.classPrefix}chapters-selector-list-item" ` + | ||
`role="menuitemcheckbox" aria-live="polite" aria-disabled="false" aria-checked="false">` + | ||
`<input type="radio" class="${t.options.classPrefix}captions-selector-input" ` + | ||
`name="${t.id}_chapters" id="${t.id}_chapters_${i}" value="${chapter.cues[i].startTime}" disabled>` + | ||
`<label class="${t.options.classPrefix}chapters-selector-label"`+ | ||
`for="${t.id}_chapters_${i}">${chapter.cues[i].text}</label>` + | ||
`</li>`; | ||
} | ||
// Remove all `<script>` tags first | ||
const scripts = div.getElementsByTagName('script'); | ||
let i = scripts.length; | ||
while (i--) { | ||
scripts[i].remove(); | ||
} | ||
const | ||
radios = t.chaptersButton.querySelectorAll('input[type="radio"]'), | ||
labels = t.chaptersButton.querySelectorAll(`.${t.options.classPrefix}chapters-selector-label`) | ||
; | ||
// Loop the elements and remove anything that contains value="javascript:" or an `on*` attribute | ||
// (`onerror`, `onclick`, etc.) | ||
const allElements = div.getElementsByTagName('*'); | ||
for (let i = 0, n = allElements.length; i < n; i++) { | ||
const | ||
attributesObj = allElements[i].attributes, | ||
attributes = Array.prototype.slice.call(attributesObj) | ||
; | ||
for (let i = 0; i < radios.length; i++) { | ||
radios[i].disabled = false; | ||
radios[i].checked = false; | ||
radios[i].addEventListener('click', function (e) { | ||
const | ||
self = this, | ||
listItems = t.chaptersButton.querySelectorAll('li'), | ||
label = siblings(self, (el) => hasClass(el, `${t.options.classPrefix}chapters-selector-label`))[0] | ||
; | ||
for (let j = 0, total = attributes.length; j < total; j++) { | ||
if (attributes[j].name.startsWith('on') || attributes[j].value.startsWith('javascript')) { | ||
allElements[i].remove(); | ||
} else if (attributes[j].name === 'style') { | ||
allElements[i].removeAttribute(attributes[j].name); | ||
} | ||
} | ||
self.checked = true; | ||
self.parentNode.setAttribute('aria-checked', true); | ||
addClass(label, `${t.options.classPrefix}chapters-selected`); | ||
removeClass(t.chaptersButton.querySelector(`.${t.options.classPrefix}chapters-selected`), `${t.options.classPrefix}chapters-selected`); | ||
} | ||
return div.innerHTML; | ||
} | ||
; | ||
for (let i = 0; i < listItems.length; i++) { | ||
listItems[i].setAttribute('aria-checked', false); | ||
} | ||
if (track !== null && track.isLoaded) { | ||
let i = t.searchTrackPosition(track.entries, t.media.currentTime); | ||
if (i > -1) { | ||
// Set the line before the timecode as a class so the cue can be targeted if needed | ||
var text = track.entries[i].text; | ||
if (typeof t.options.captionTextPreprocessor === 'function') | ||
text = t.options.captionTextPreprocessor(text); | ||
t.captionsText.innerHTML = sanitize(text); | ||
t.captionsText.className = `${t.options.classPrefix}captions-text ${(track.entries[i].identifier || '')}`; | ||
t.captions.style.display = ''; | ||
t.captions.style.height = '0px'; | ||
return; // exit out if one is visible; | ||
} | ||
t.captions.style.display = 'none'; | ||
} else { | ||
t.captions.style.display = 'none'; | ||
} | ||
}, | ||
const keyboard = e.keyCode || e.which; | ||
if (typeof keyboard === 'undefined') { | ||
setTimeout(function() { | ||
t.getElement(t.container).focus(); | ||
}, 500); | ||
} | ||
/** | ||
* | ||
* @param {HTMLElement} track | ||
*/ | ||
setupSlides (track) { | ||
const t = this; | ||
t.slides = track; | ||
t.slides.entries.imgs = [t.slides.entries.length]; | ||
t.showSlide(0); | ||
}, | ||
t.media.setCurrentTime(parseFloat(self.value)); | ||
if (t.media.paused) { | ||
t.media.play(); | ||
} | ||
}); | ||
} | ||
/** | ||
* | ||
* @param {Number} index | ||
*/ | ||
showSlide (index) { | ||
const t = this; | ||
for (let i = 0; i < labels.length; i++) { | ||
labels[i].addEventListener('click', function (e) { | ||
const | ||
radio = siblings(this, (el) => el.tagName === 'INPUT')[0], | ||
event = createEvent('click', radio) | ||
; | ||
radio.dispatchEvent(event); | ||
e.preventDefault(); | ||
}); | ||
} | ||
}, | ||
if (t.tracks === undefined || t.slidesContainer === undefined) { | ||
return; | ||
} | ||
/** | ||
* Get a track object using its id. | ||
* @param {string} trackId | ||
* @returns {object|undefined} The track object with the given id or undefined if it doesn't exist. | ||
*/ | ||
getTrackById(trackId) { | ||
return this.tracks.find(track => track.trackId === trackId); | ||
}, | ||
const url = t.slides.entries[index].text; | ||
/** | ||
* Fetch all chapter tracks. | ||
* @returns {object[]} Array containing all track of type "chapters" | ||
*/ | ||
getChapters() { | ||
return this.tracks.filter(({kind}) => kind === 'chapters'); | ||
}, | ||
let img = t.slides.entries[index].imgs; | ||
/** | ||
* Fetch all subtitle/captions tracks. | ||
* @returns {object[]} Array containing all track of type "subtitles"/"captions". | ||
*/ | ||
getSubtitles() { | ||
return this.tracks.filter(({kind}) => kind === 'subtitles' || kind === 'captions'); | ||
}, | ||
if (img === undefined || img.fadeIn === undefined) { | ||
const image = document.createElement('img'); | ||
image.src = url; | ||
image.addEventListener('load', () => { | ||
const | ||
self = this, | ||
visible = siblings(self, (el) => visible(el)) | ||
; | ||
self.style.display = 'none'; | ||
t.slidesContainer.innerHTML += self.innerHTML; | ||
fadeIn(t.slidesContainer.querySelector(image)); | ||
for (let i = 0, total = visible.length; i < total; i++) { | ||
fadeOut(visible[i], 400); | ||
} | ||
/** | ||
* Perform binary search to look for proper track index | ||
* | ||
* @param {Object[]} tracks | ||
* @param {Number} currentTime | ||
* @return {Number} | ||
*/ | ||
searchTrackPosition (tracks, currentTime) { | ||
let | ||
lo = 0, | ||
hi = tracks.length - 1, | ||
mid, | ||
start, | ||
stop | ||
; | ||
}); | ||
t.slides.entries[index].imgs = img = image; | ||
while (lo <= hi) { | ||
mid = ((lo + hi) >> 1); | ||
start = tracks[mid].start; | ||
stop = tracks[mid].stop; | ||
} else if (!visible(img)) { | ||
const visible = siblings(self, (el) => visible(el)); | ||
fadeIn(t.slidesContainer.querySelector(img)); | ||
for (let i = 0, total = visible.length; i < total; i++) { | ||
fadeOut(visible[i]); | ||
} | ||
} | ||
if (currentTime >= start && currentTime < stop) { | ||
return mid; | ||
} else if (start < currentTime) { | ||
lo = mid + 1; | ||
} else if (start > currentTime) { | ||
hi = mid - 1; | ||
} | ||
} | ||
}, | ||
/** | ||
* | ||
*/ | ||
displaySlides () { | ||
const t = this; | ||
if (this.slides === undefined) { | ||
return; | ||
} | ||
const | ||
slides = t.slides, | ||
i = t.searchTrackPosition(slides.entries, t.media.currentTime) | ||
; | ||
if (i > -1) { | ||
t.showSlide(i); | ||
} | ||
}, | ||
/** | ||
* | ||
* @param {Object} chapters | ||
*/ | ||
drawChapters (chapters) { | ||
const | ||
t = this, | ||
total = chapters.entries.length | ||
; | ||
if (!total) { | ||
return; | ||
} | ||
t.chaptersButton.querySelector('ul').innerHTML = ''; | ||
for (let i = 0; i < total; i++) { | ||
t.chaptersButton.querySelector('ul').innerHTML += `<li class="${t.options.classPrefix}chapters-selector-list-item" ` + | ||
`role="menuitemcheckbox" aria-live="polite" aria-disabled="false" aria-checked="false">` + | ||
`<input type="radio" class="${t.options.classPrefix}captions-selector-input" ` + | ||
`name="${t.id}_chapters" id="${t.id}_chapters_${i}" value="${chapters.entries[i].start}" disabled>` + | ||
`<label class="${t.options.classPrefix}chapters-selector-label"`+ | ||
`for="${t.id}_chapters_${i}">${chapters.entries[i].text}</label>` + | ||
`</li>`; | ||
} | ||
const | ||
radios = t.chaptersButton.querySelectorAll('input[type="radio"]'), | ||
labels = t.chaptersButton.querySelectorAll(`.${t.options.classPrefix}chapters-selector-label`) | ||
; | ||
for (let i = 0, total = radios.length; i < total; i++) { | ||
radios[i].disabled = false; | ||
radios[i].checked = false; | ||
radios[i].addEventListener('click', function (e) { | ||
const | ||
self = this, | ||
listItems = t.chaptersButton.querySelectorAll('li'), | ||
label = siblings(self, (el) => hasClass(el, `${t.options.classPrefix}chapters-selector-label`))[0] | ||
; | ||
self.checked = true; | ||
self.parentNode.setAttribute('aria-checked', true); | ||
addClass(label, `${t.options.classPrefix}chapters-selected`); | ||
removeClass(t.chaptersButton.querySelector(`.${t.options.classPrefix}chapters-selected`), `${t.options.classPrefix}chapters-selected`); | ||
for (let i = 0, total = listItems.length; i < total; i++) { | ||
listItems[i].setAttribute('aria-checked', false); | ||
} | ||
const keyboard = e.keyCode || e.which; | ||
if (typeof keyboard === 'undefined') { | ||
setTimeout(function() { | ||
t.getElement(t.container).focus(); | ||
}, 500); | ||
} | ||
t.media.setCurrentTime(parseFloat(self.value)); | ||
if (t.media.paused) { | ||
t.media.play(); | ||
} | ||
}); | ||
} | ||
for (let i = 0, total = labels.length; i < total; i++) { | ||
labels[i].addEventListener('click', function (e) { | ||
const | ||
radio = siblings(this, (el) => el.tagName === 'INPUT')[0], | ||
event = createEvent('click', radio) | ||
; | ||
radio.dispatchEvent(event); | ||
e.preventDefault(); | ||
}); | ||
} | ||
}, | ||
/** | ||
* Perform binary search to look for proper track index | ||
* | ||
* @param {Object[]} tracks | ||
* @param {Number} currentTime | ||
* @return {Number} | ||
*/ | ||
searchTrackPosition (tracks, currentTime) { | ||
let | ||
lo = 0, | ||
hi = tracks.length - 1, | ||
mid, | ||
start, | ||
stop | ||
; | ||
while (lo <= hi) { | ||
mid = ((lo + hi) >> 1); | ||
start = tracks[mid].start; | ||
stop = tracks[mid].stop; | ||
if (currentTime >= start && currentTime < stop) { | ||
return mid; | ||
} else if (start < currentTime) { | ||
lo = mid + 1; | ||
} else if (start > currentTime) { | ||
hi = mid - 1; | ||
} | ||
} | ||
return -1; | ||
} | ||
return -1; | ||
} | ||
}); | ||
@@ -793,201 +772,59 @@ | ||
mejs.language = { | ||
codes: { | ||
af: 'mejs.afrikaans', | ||
sq: 'mejs.albanian', | ||
ar: 'mejs.arabic', | ||
be: 'mejs.belarusian', | ||
bg: 'mejs.bulgarian', | ||
ca: 'mejs.catalan', | ||
zh: 'mejs.chinese', | ||
'zh-cn': 'mejs.chinese-simplified', | ||
'zh-tw': 'mejs.chines-traditional', | ||
hr: 'mejs.croatian', | ||
cs: 'mejs.czech', | ||
da: 'mejs.danish', | ||
nl: 'mejs.dutch', | ||
en: 'mejs.english', | ||
et: 'mejs.estonian', | ||
fl: 'mejs.filipino', | ||
fi: 'mejs.finnish', | ||
fr: 'mejs.french', | ||
gl: 'mejs.galician', | ||
de: 'mejs.german', | ||
el: 'mejs.greek', | ||
ht: 'mejs.haitian-creole', | ||
iw: 'mejs.hebrew', | ||
hi: 'mejs.hindi', | ||
hu: 'mejs.hungarian', | ||
is: 'mejs.icelandic', | ||
id: 'mejs.indonesian', | ||
ga: 'mejs.irish', | ||
it: 'mejs.italian', | ||
ja: 'mejs.japanese', | ||
ko: 'mejs.korean', | ||
lv: 'mejs.latvian', | ||
lt: 'mejs.lithuanian', | ||
mk: 'mejs.macedonian', | ||
ms: 'mejs.malay', | ||
mt: 'mejs.maltese', | ||
no: 'mejs.norwegian', | ||
fa: 'mejs.persian', | ||
pl: 'mejs.polish', | ||
pt: 'mejs.portuguese', | ||
ro: 'mejs.romanian', | ||
ru: 'mejs.russian', | ||
sr: 'mejs.serbian', | ||
sk: 'mejs.slovak', | ||
sl: 'mejs.slovenian', | ||
es: 'mejs.spanish', | ||
sw: 'mejs.swahili', | ||
sv: 'mejs.swedish', | ||
tl: 'mejs.tagalog', | ||
th: 'mejs.thai', | ||
tr: 'mejs.turkish', | ||
uk: 'mejs.ukrainian', | ||
vi: 'mejs.vietnamese', | ||
cy: 'mejs.welsh', | ||
yi: 'mejs.yiddish' | ||
} | ||
codes: { | ||
af: 'mejs.afrikaans', | ||
sq: 'mejs.albanian', | ||
ar: 'mejs.arabic', | ||
be: 'mejs.belarusian', | ||
bg: 'mejs.bulgarian', | ||
ca: 'mejs.catalan', | ||
zh: 'mejs.chinese', | ||
'zh-cn': 'mejs.chinese-simplified', | ||
'zh-tw': 'mejs.chines-traditional', | ||
hr: 'mejs.croatian', | ||
cs: 'mejs.czech', | ||
da: 'mejs.danish', | ||
nl: 'mejs.dutch', | ||
en: 'mejs.english', | ||
et: 'mejs.estonian', | ||
fl: 'mejs.filipino', | ||
fi: 'mejs.finnish', | ||
fr: 'mejs.french', | ||
gl: 'mejs.galician', | ||
de: 'mejs.german', | ||
el: 'mejs.greek', | ||
ht: 'mejs.haitian-creole', | ||
iw: 'mejs.hebrew', | ||
hi: 'mejs.hindi', | ||
hu: 'mejs.hungarian', | ||
is: 'mejs.icelandic', | ||
id: 'mejs.indonesian', | ||
ga: 'mejs.irish', | ||
it: 'mejs.italian', | ||
ja: 'mejs.japanese', | ||
ko: 'mejs.korean', | ||
lv: 'mejs.latvian', | ||
lt: 'mejs.lithuanian', | ||
mk: 'mejs.macedonian', | ||
ms: 'mejs.malay', | ||
mt: 'mejs.maltese', | ||
no: 'mejs.norwegian', | ||
fa: 'mejs.persian', | ||
pl: 'mejs.polish', | ||
pt: 'mejs.portuguese', | ||
ro: 'mejs.romanian', | ||
ru: 'mejs.russian', | ||
sr: 'mejs.serbian', | ||
sk: 'mejs.slovak', | ||
sl: 'mejs.slovenian', | ||
es: 'mejs.spanish', | ||
sw: 'mejs.swahili', | ||
sv: 'mejs.swedish', | ||
tl: 'mejs.tagalog', | ||
th: 'mejs.thai', | ||
tr: 'mejs.turkish', | ||
uk: 'mejs.ukrainian', | ||
vi: 'mejs.vietnamese', | ||
cy: 'mejs.welsh', | ||
yi: 'mejs.yiddish' | ||
} | ||
}; | ||
/* | ||
Parses WebVTT format which should be formatted as | ||
================================ | ||
WEBVTT | ||
1 | ||
00:00:01,1 --> 00:00:05,000 | ||
A line of text | ||
2 | ||
00:01:15,1 --> 00:02:05,000 | ||
A second line of text | ||
=============================== | ||
Adapted from: http://www.delphiki.com/html5/playr | ||
*/ | ||
mejs.TrackFormatParser = { | ||
webvtt: { | ||
/** | ||
* @type {String} | ||
*/ | ||
pattern: /^((?:[0-9]{1,2}:)?[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ((?:[0-9]{1,2}:)?[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/, | ||
/** | ||
* | ||
* @param {String} trackText | ||
* @returns {{text: Array, times: Array}} | ||
*/ | ||
parse (trackText) { | ||
const | ||
lines = trackText.split(/\r?\n/), | ||
entries = [] | ||
; | ||
let | ||
timecode, | ||
text, | ||
identifier | ||
; | ||
for (let i = 0, total = lines.length; i < total; i++) { | ||
timecode = this.pattern.exec(lines[i]); | ||
if (timecode && i < lines.length) { | ||
if ((i - 1) >= 0 && lines[i - 1] !== '') { | ||
identifier = lines[i - 1]; | ||
} | ||
i++; | ||
// grab all the (possibly multi-line) text that follows | ||
text = lines[i]; | ||
i++; | ||
while (lines[i] !== '' && i < lines.length) { | ||
text = `${text}\n${lines[i]}`; | ||
i++; | ||
} | ||
text = text === null ? '' : text.trim().replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig, "<a href='$1' target='_blank'>$1</a>"); | ||
entries.push({ | ||
identifier: identifier, | ||
start: (convertSMPTEtoSeconds(timecode[1]) === 0) ? 0.200 : convertSMPTEtoSeconds(timecode[1]), | ||
stop: convertSMPTEtoSeconds(timecode[3]), | ||
text: text, | ||
settings: timecode[5] | ||
}); | ||
} | ||
identifier = ''; | ||
} | ||
return entries; | ||
} | ||
}, | ||
// Thanks to Justin Capella: https://github.com/johndyer/mediaelement/pull/420 | ||
dfxp: { | ||
/** | ||
* | ||
* @param {String} trackText | ||
* @returns {{text: Array, times: Array}} | ||
*/ | ||
parse (trackText) { | ||
const trackElem = document.adoptNode(new DOMParser().parseFromString(trackText, 'application/xml').documentElement), | ||
container = trackElem.querySelector('div'), | ||
lines = container.querySelectorAll('p'), | ||
styleNode = document.getElementById(container.getAttribute('style')), | ||
entries = [] | ||
; | ||
let styles; | ||
if (styleNode) { | ||
styleNode.removeAttribute('id'); | ||
const attributes = styleNode.attributes; | ||
if (attributes.length) { | ||
styles = {}; | ||
for (let i = 0, total = attributes.length; i < total; i++) { | ||
styles[attributes[i].name.split(":")[1]] = attributes[i].value; | ||
} | ||
} | ||
} | ||
for (let i = 0, total = lines.length; i < total; i++) { | ||
let | ||
style, | ||
_temp = { | ||
start: null, | ||
stop: null, | ||
style: null, | ||
text: null | ||
} | ||
; | ||
if (lines[i].getAttribute('begin')) { | ||
_temp.start = convertSMPTEtoSeconds(lines[i].getAttribute('begin')); | ||
} | ||
if (!_temp.start && lines[i - 1].getAttribute('end')) { | ||
_temp.start = convertSMPTEtoSeconds(lines[i - 1].getAttribute('end')); | ||
} | ||
if (lines[i].getAttribute('end')) { | ||
_temp.stop = convertSMPTEtoSeconds(lines[i].getAttribute('end')); | ||
} | ||
if (!_temp.stop && lines[i + 1].getAttribute('begin')) { | ||
_temp.stop = convertSMPTEtoSeconds(lines[i + 1].getAttribute('begin')); | ||
} | ||
if (styles) { | ||
style = ''; | ||
for (let _style in styles) { | ||
style += `${_style}: ${styles[_style] };`; | ||
} | ||
} | ||
if (style) { | ||
_temp.style = style; | ||
} | ||
if (_temp.start === 0) { | ||
_temp.start = 0.200; | ||
} | ||
_temp.text = lines[i].innerHTML.trim().replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_| !:, .; ]*[-A-Z0-9+&@#\/%=~_|])/ig, "<a href='$1' target='_blank'>$1</a>"); | ||
entries.push(_temp); | ||
} | ||
return entries; | ||
} | ||
} | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
238
32512
3446323