WordPress.org

Make WordPress Core

Ticket #24015: 24015.2.diff

File 24015.2.diff, 246.2 KB (added by wonderboymusic, 5 years ago)
  • wp-includes/js/mediaelement/mediaelement-and-player.js

    diff --git wp-includes/js/mediaelement/mediaelement-and-player.js wp-includes/js/mediaelement/mediaelement-and-player.js
    index bb49d60..048c8f0 100644
     
    1010* Copyright 2010-2012, John Dyer (http://j.hn)
    1111* License: MIT
    1212*
    13 */
    14 // Namespace
    15 var mejs = mejs || {};
    16 
    17 // version number
    18 mejs.version = '2.11.0';
    19 
    20 // player number (for missing, same id attr)
    21 mejs.meIndex = 0;
    22 
    23 // media types accepted by plugins
    24 mejs.plugins = {
    25         silverlight: [
    26                 {version: [3,0], types: ['video/mp4','video/m4v','video/mov','video/wmv','audio/wma','audio/m4a','audio/mp3','audio/wav','audio/mpeg']}
    27         ],
    28         flash: [
    29                 {version: [9,0,124], types: ['video/mp4','video/m4v','video/mov','video/flv','video/rtmp','video/x-flv','audio/flv','audio/x-flv','audio/mp3','audio/m4a','audio/mpeg', 'video/youtube', 'video/x-youtube']}
    30                 //,{version: [12,0], types: ['video/webm']} // for future reference (hopefully!)
    31         ],
    32         youtube: [
    33                 {version: null, types: ['video/youtube', 'video/x-youtube', 'audio/youtube', 'audio/x-youtube']}
    34         ],
    35         vimeo: [
    36                 {version: null, types: ['video/vimeo', 'video/x-vimeo']}
    37         ]
    38 };
    39 
    40 
    41 /*
    42 Utility methods
    43 */
    44 mejs.Utility = {
    45         encodeUrl: function(url) {
    46                 return encodeURIComponent(url); //.replace(/\?/gi,'%3F').replace(/=/gi,'%3D').replace(/&/gi,'%26');
    47         },
    48         escapeHTML: function(s) {
    49                 return s.toString().split('&').join('&amp;').split('<').join('&lt;').split('"').join('&quot;');
    50         },
    51         absolutizeUrl: function(url) {
    52                 var el = document.createElement('div');
    53                 el.innerHTML = '<a href="' + this.escapeHTML(url) + '">x</a>';
    54                 return el.firstChild.href;
    55         },
    56         getScriptPath: function(scriptNames) {
    57                 var
    58                         i = 0,
    59                         j,
    60                         path = '',
    61                         name = '',
    62                         script,
    63                         scripts = document.getElementsByTagName('script'),
    64                         il = scripts.length,
    65                         jl = scriptNames.length;
    66 
    67                 for (; i < il; i++) {
    68                         script = scripts[i].src;
    69                         for (j = 0; j < jl; j++) {
    70                                 name = scriptNames[j];
    71                                 if (script.indexOf(name) > -1) {
    72                                         path = script.substring(0, script.indexOf(name));
    73                                         break;
    74                                 }
    75                         }
    76                         if (path !== '') {
    77                                 break;
    78                         }
    79                 }
    80                 return path;
    81         },
    82         secondsToTimeCode: function(time, forceHours, showFrameCount, fps) {
    83                 //add framecount
    84                 if (typeof showFrameCount == 'undefined') {
    85                     showFrameCount=false;
    86                 } else if(typeof fps == 'undefined') {
    87                     fps = 25;
    88                 }
    89 
    90                 var hours = Math.floor(time / 3600) % 24,
    91                         minutes = Math.floor(time / 60) % 60,
    92                         seconds = Math.floor(time % 60),
    93                         frames = Math.floor(((time % 1)*fps).toFixed(3)),
    94                         result =
    95                                         ( (forceHours || hours > 0) ? (hours < 10 ? '0' + hours : hours) + ':' : '')
    96                                                 + (minutes < 10 ? '0' + minutes : minutes) + ':'
    97                                                 + (seconds < 10 ? '0' + seconds : seconds)
    98                                                 + ((showFrameCount) ? ':' + (frames < 10 ? '0' + frames : frames) : '');
    99 
    100                 return result;
    101         },
    102 
    103         timeCodeToSeconds: function(hh_mm_ss_ff, forceHours, showFrameCount, fps){
    104                 if (typeof showFrameCount == 'undefined') {
    105                     showFrameCount=false;
    106                 } else if(typeof fps == 'undefined') {
    107                     fps = 25;
    108                 }
    109 
    110                 var tc_array = hh_mm_ss_ff.split(":"),
    111                         tc_hh = parseInt(tc_array[0], 10),
    112                         tc_mm = parseInt(tc_array[1], 10),
    113                         tc_ss = parseInt(tc_array[2], 10),
    114                         tc_ff = 0,
    115                         tc_in_seconds = 0;
    116 
    117                 if (showFrameCount) {
    118                     tc_ff = parseInt(tc_array[3])/fps;
    119                 }
    120 
    121                 tc_in_seconds = ( tc_hh * 3600 ) + ( tc_mm * 60 ) + tc_ss + tc_ff;
    122 
    123                 return tc_in_seconds;
    124         },
    125 
    126 
    127         convertSMPTEtoSeconds: function (SMPTE) {
    128                 if (typeof SMPTE != 'string')
    129                         return false;
    130 
    131                 SMPTE = SMPTE.replace(',', '.');
    132 
    133                 var secs = 0,
    134                         decimalLen = (SMPTE.indexOf('.') != -1) ? SMPTE.split('.')[1].length : 0,
    135                         multiplier = 1;
    136 
    137                 SMPTE = SMPTE.split(':').reverse();
    138 
    139                 for (var i = 0; i < SMPTE.length; i++) {
    140                         multiplier = 1;
    141                         if (i > 0) {
    142                                 multiplier = Math.pow(60, i);
    143                         }
    144                         secs += Number(SMPTE[i]) * multiplier;
    145                 }
    146                 return Number(secs.toFixed(decimalLen));
    147         },
    148 
    149         /* borrowed from SWFObject: http://code.google.com/p/swfobject/source/browse/trunk/swfobject/src/swfobject.js#474 */
    150         removeSwf: function(id) {
    151                 var obj = document.getElementById(id);
    152                 if (obj && /object|embed/i.test(obj.nodeName)) {
    153                         if (mejs.MediaFeatures.isIE) {
    154                                 obj.style.display = "none";
    155                                 (function(){
    156                                         if (obj.readyState == 4) {
    157                                                 mejs.Utility.removeObjectInIE(id);
    158                                         } else {
    159                                                 setTimeout(arguments.callee, 10);
    160                                         }
    161                                 })();
    162                         } else {
    163                                 obj.parentNode.removeChild(obj);
    164                         }
    165                 }
    166         },
    167         removeObjectInIE: function(id) {
    168                 var obj = document.getElementById(id);
    169                 if (obj) {
    170                         for (var i in obj) {
    171                                 if (typeof obj[i] == "function") {
    172                                         obj[i] = null;
    173                                 }
    174                         }
    175                         obj.parentNode.removeChild(obj);
    176                 }
    177         }
    178 };
    179 
    180 
    181 // Core detector, plugins are added below
    182 mejs.PluginDetector = {
    183 
    184         // main public function to test a plug version number PluginDetector.hasPluginVersion('flash',[9,0,125]);
    185         hasPluginVersion: function(plugin, v) {
    186                 var pv = this.plugins[plugin];
    187                 v[1] = v[1] || 0;
    188                 v[2] = v[2] || 0;
    189                 return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
    190         },
    191 
    192         // cached values
    193         nav: window.navigator,
    194         ua: window.navigator.userAgent.toLowerCase(),
    195 
    196         // stored version numbers
    197         plugins: [],
    198 
    199         // runs detectPlugin() and stores the version number
    200         addPlugin: function(p, pluginName, mimeType, activeX, axDetect) {
    201                 this.plugins[p] = this.detectPlugin(pluginName, mimeType, activeX, axDetect);
    202         },
    203 
    204         // get the version number from the mimetype (all but IE) or ActiveX (IE)
    205         detectPlugin: function(pluginName, mimeType, activeX, axDetect) {
    206 
    207                 var version = [0,0,0],
    208                         description,
    209                         i,
    210                         ax;
    211 
    212                 // Firefox, Webkit, Opera
    213                 if (typeof(this.nav.plugins) != 'undefined' && typeof this.nav.plugins[pluginName] == 'object') {
    214                         description = this.nav.plugins[pluginName].description;
    215                         if (description && !(typeof this.nav.mimeTypes != 'undefined' && this.nav.mimeTypes[mimeType] && !this.nav.mimeTypes[mimeType].enabledPlugin)) {
    216                                 version = description.replace(pluginName, '').replace(/^\s+/,'').replace(/\sr/gi,'.').split('.');
    217                                 for (i=0; i<version.length; i++) {
    218                                         version[i] = parseInt(version[i].match(/\d+/), 10);
    219                                 }
    220                         }
    221                 // Internet Explorer / ActiveX
    222                 } else if (typeof(window.ActiveXObject) != 'undefined') {
    223                         try {
    224                                 ax = new ActiveXObject(activeX);
    225                                 if (ax) {
    226                                         version = axDetect(ax);
    227                                 }
    228                         }
    229                         catch (e) { }
    230                 }
    231                 return version;
    232         }
    233 };
    234 
    235 // Add Flash detection
    236 mejs.PluginDetector.addPlugin('flash','Shockwave Flash','application/x-shockwave-flash','ShockwaveFlash.ShockwaveFlash', function(ax) {
    237         // adapted from SWFObject
    238         var version = [],
    239                 d = ax.GetVariable("$version");
    240         if (d) {
    241                 d = d.split(" ")[1].split(",");
    242                 version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
    243         }
    244         return version;
    245 });
    246 
    247 // Add Silverlight detection
    248 mejs.PluginDetector.addPlugin('silverlight','Silverlight Plug-In','application/x-silverlight-2','AgControl.AgControl', function (ax) {
    249         // Silverlight cannot report its version number to IE
    250         // but it does have a isVersionSupported function, so we have to loop through it to get a version number.
    251         // adapted from http://www.silverlightversion.com/
    252         var v = [0,0,0,0],
    253                 loopMatch = function(ax, v, i, n) {
    254                         while(ax.isVersionSupported(v[0]+ "."+ v[1] + "." + v[2] + "." + v[3])){
    255                                 v[i]+=n;
    256                         }
    257                         v[i] -= n;
    258                 };
    259         loopMatch(ax, v, 0, 1);
    260         loopMatch(ax, v, 1, 1);
    261         loopMatch(ax, v, 2, 10000); // the third place in the version number is usually 5 digits (4.0.xxxxx)
    262         loopMatch(ax, v, 2, 1000);
    263         loopMatch(ax, v, 2, 100);
    264         loopMatch(ax, v, 2, 10);
    265         loopMatch(ax, v, 2, 1);
    266         loopMatch(ax, v, 3, 1);
    267 
    268         return v;
    269 });
    270 // add adobe acrobat
    271 /*
    272 PluginDetector.addPlugin('acrobat','Adobe Acrobat','application/pdf','AcroPDF.PDF', function (ax) {
    273         var version = [],
    274                 d = ax.GetVersions().split(',')[0].split('=')[1].split('.');
    275 
    276         if (d) {
    277                 version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
    278         }
    279         return version;
    280 });
    281 */
    282 // necessary detection (fixes for <IE9)
    283 mejs.MediaFeatures = {
    284         init: function() {
    285                 var
    286                         t = this,
    287                         d = document,
    288                         nav = mejs.PluginDetector.nav,
    289                         ua = mejs.PluginDetector.ua.toLowerCase(),
    290                         i,
    291                         v,
    292                         html5Elements = ['source','track','audio','video'];
    293 
    294                 // detect browsers (only the ones that have some kind of quirk we need to work around)
    295                 t.isiPad = (ua.match(/ipad/i) !== null);
    296                 t.isiPhone = (ua.match(/iphone/i) !== null);
    297                 t.isiOS = t.isiPhone || t.isiPad;
    298                 t.isAndroid = (ua.match(/android/i) !== null);
    299                 t.isBustedAndroid = (ua.match(/android 2\.[12]/) !== null);
    300                 t.isIE = (nav.appName.toLowerCase().indexOf("microsoft") != -1);
    301                 t.isChrome = (ua.match(/chrome/gi) !== null);
    302                 t.isFirefox = (ua.match(/firefox/gi) !== null);
    303                 t.isWebkit = (ua.match(/webkit/gi) !== null);
    304                 t.isGecko = (ua.match(/gecko/gi) !== null) && !t.isWebkit;
    305                 t.isOpera = (ua.match(/opera/gi) !== null);
    306                 t.hasTouch = ('ontouchstart' in window);
    307 
    308                 // borrowed from Modernizr
    309                 t.svg = !! document.createElementNS &&
    310                                 !! document.createElementNS('http://www.w3.org/2000/svg','svg').createSVGRect;
    311 
    312                 // create HTML5 media elements for IE before 9, get a <video> element for fullscreen detection
    313                 for (i=0; i<html5Elements.length; i++) {
    314                         v = document.createElement(html5Elements[i]);
    315                 }
    316 
    317                 t.supportsMediaTag = (typeof v.canPlayType !== 'undefined' || t.isBustedAndroid);
    318 
    319                 // detect native JavaScript fullscreen (Safari/Firefox only, Chrome still fails)
    320 
    321                 // iOS
    322                 t.hasSemiNativeFullScreen = (typeof v.webkitEnterFullscreen !== 'undefined');
    323 
    324                 // Webkit/firefox
    325                 t.hasWebkitNativeFullScreen = (typeof v.webkitRequestFullScreen !== 'undefined');
    326                 t.hasMozNativeFullScreen = (typeof v.mozRequestFullScreen !== 'undefined');
    327 
    328                 t.hasTrueNativeFullScreen = (t.hasWebkitNativeFullScreen || t.hasMozNativeFullScreen);
    329                 t.nativeFullScreenEnabled = t.hasTrueNativeFullScreen;
    330                 if (t.hasMozNativeFullScreen) {
    331                         t.nativeFullScreenEnabled = v.mozFullScreenEnabled;
    332                 }
    333 
    334 
    335                 if (this.isChrome) {
    336                         t.hasSemiNativeFullScreen = false;
    337                 }
    338 
    339                 if (t.hasTrueNativeFullScreen) {
    340                         t.fullScreenEventName = (t.hasWebkitNativeFullScreen) ? 'webkitfullscreenchange' : 'mozfullscreenchange';
    341 
    342 
    343                         t.isFullScreen = function() {
    344                                 if (v.mozRequestFullScreen) {
    345                                         return d.mozFullScreen;
    346                                 } else if (v.webkitRequestFullScreen) {
    347                                         return d.webkitIsFullScreen;
    348                                 }
    349                         }
    350 
    351                         t.requestFullScreen = function(el) {
    352 
    353                                 if (t.hasWebkitNativeFullScreen) {
    354                                         el.webkitRequestFullScreen();
    355                                 } else if (t.hasMozNativeFullScreen) {
    356                                         el.mozRequestFullScreen();
    357                                 }
    358                         }
    359 
    360                         t.cancelFullScreen = function() {
    361                                 if (t.hasWebkitNativeFullScreen) {
    362                                         document.webkitCancelFullScreen();
    363                                 } else if (t.hasMozNativeFullScreen) {
    364                                         document.mozCancelFullScreen();
    365                                 }
    366                         }
    367 
    368                 }
    369 
    370 
    371                 // OS X 10.5 can't do this even if it says it can :(
    372                 if (t.hasSemiNativeFullScreen && ua.match(/mac os x 10_5/i)) {
    373                         t.hasNativeFullScreen = false;
    374                         t.hasSemiNativeFullScreen = false;
    375                 }
    376 
    377         }
    378 };
    379 mejs.MediaFeatures.init();
    380 
    381 /*
    382 extension methods to <video> or <audio> object to bring it into parity with PluginMediaElement (see below)
    383 */
    384 mejs.HtmlMediaElement = {
    385         pluginType: 'native',
    386         isFullScreen: false,
    387 
    388         setCurrentTime: function (time) {
    389                 this.currentTime = time;
    390         },
    391 
    392         setMuted: function (muted) {
    393                 this.muted = muted;
    394         },
    395 
    396         setVolume: function (volume) {
    397                 this.volume = volume;
    398         },
    399 
    400         // for parity with the plugin versions
    401         stop: function () {
    402                 this.pause();
    403         },
    404 
    405         // This can be a url string
    406         // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
    407         setSrc: function (url) {
    408 
    409                 // Fix for IE9 which can't set .src when there are <source> elements. Awesome, right?
    410                 var
    411                         existingSources = this.getElementsByTagName('source');
    412                 while (existingSources.length > 0){
    413                         this.removeChild(existingSources[0]);
    414                 }
    415 
    416                 if (typeof url == 'string') {
    417                         this.src = url;
    418                 } else {
    419                         var i, media;
    420 
    421                         for (i=0; i<url.length; i++) {
    422                                 media = url[i];
    423                                 if (this.canPlayType(media.type)) {
    424                                         this.src = media.src;
    425                                         break;
    426                                 }
    427                         }
    428                 }
    429         },
    430 
    431         setVideoSize: function (width, height) {
    432                 this.width = width;
    433                 this.height = height;
    434         }
    435 };
    436 
    437 /*
    438 Mimics the <video/audio> element by calling Flash's External Interface or Silverlights [ScriptableMember]
    439 */
    440 mejs.PluginMediaElement = function (pluginid, pluginType, mediaUrl) {
    441         this.id = pluginid;
    442         this.pluginType = pluginType;
    443         this.src = mediaUrl;
    444         this.events = {};
    445         this.attributes = {};
    446 };
    447 
    448 // JavaScript values and ExternalInterface methods that match HTML5 video properties methods
    449 // http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/fl/video/FLVPlayback.html
    450 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
    451 mejs.PluginMediaElement.prototype = {
    452 
    453         // special
    454         pluginElement: null,
    455         pluginType: '',
    456         isFullScreen: false,
    457 
    458         // not implemented :(
    459         playbackRate: -1,
    460         defaultPlaybackRate: -1,
    461         seekable: [],
    462         played: [],
    463 
    464         // HTML5 read-only properties
    465         paused: true,
    466         ended: false,
    467         seeking: false,
    468         duration: 0,
    469         error: null,
    470         tagName: '',
    471 
    472         // HTML5 get/set properties, but only set (updated by event handlers)
    473         muted: false,
    474         volume: 1,
    475         currentTime: 0,
    476 
    477         // HTML5 methods
    478         play: function () {
    479                 if (this.pluginApi != null) {
    480                         if (this.pluginType == 'youtube') {
    481                                 this.pluginApi.playVideo();
    482                         } else {
    483                                 this.pluginApi.playMedia();
    484                         }
    485                         this.paused = false;
    486                 }
    487         },
    488         load: function () {
    489                 if (this.pluginApi != null) {
    490                         if (this.pluginType == 'youtube') {
    491                         } else {
    492                                 this.pluginApi.loadMedia();
    493                         }
    494 
    495                         this.paused = false;
    496                 }
    497         },
    498         pause: function () {
    499                 if (this.pluginApi != null) {
    500                         if (this.pluginType == 'youtube') {
    501                                 this.pluginApi.pauseVideo();
    502                         } else {
    503                                 this.pluginApi.pauseMedia();
    504                         }
    505 
    506 
    507                         this.paused = true;
    508                 }
    509         },
    510         stop: function () {
    511                 if (this.pluginApi != null) {
    512                         if (this.pluginType == 'youtube') {
    513                                 this.pluginApi.stopVideo();
    514                         } else {
    515                                 this.pluginApi.stopMedia();
    516                         }
    517                         this.paused = true;
    518                 }
    519         },
    520         canPlayType: function(type) {
    521                 var i,
    522                         j,
    523                         pluginInfo,
    524                         pluginVersions = mejs.plugins[this.pluginType];
    525 
    526                 for (i=0; i<pluginVersions.length; i++) {
    527                         pluginInfo = pluginVersions[i];
    528 
    529                         // test if user has the correct plugin version
    530                         if (mejs.PluginDetector.hasPluginVersion(this.pluginType, pluginInfo.version)) {
    531 
    532                                 // test for plugin playback types
    533                                 for (j=0; j<pluginInfo.types.length; j++) {
    534                                         // find plugin that can play the type
    535                                         if (type == pluginInfo.types[j]) {
    536                                                 return 'probably';
    537                                         }
    538                                 }
    539                         }
    540                 }
    541 
    542                 return '';
    543         },
    544 
    545         positionFullscreenButton: function(x,y,visibleAndAbove) {
    546                 if (this.pluginApi != null && this.pluginApi.positionFullscreenButton) {
    547                         this.pluginApi.positionFullscreenButton(x,y,visibleAndAbove);
    548                 }
    549         },
    550 
    551         hideFullscreenButton: function() {
    552                 if (this.pluginApi != null && this.pluginApi.hideFullscreenButton) {
    553                         this.pluginApi.hideFullscreenButton();
    554                 }
    555         },
    556 
    557 
    558         // custom methods since not all JavaScript implementations support get/set
    559 
    560         // This can be a url string
    561         // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
    562         setSrc: function (url) {
    563                 if (typeof url == 'string') {
    564                         this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(url));
    565                         this.src = mejs.Utility.absolutizeUrl(url);
    566                 } else {
    567                         var i, media;
    568 
    569                         for (i=0; i<url.length; i++) {
    570                                 media = url[i];
    571                                 if (this.canPlayType(media.type)) {
    572                                         this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(media.src));
    573                                         this.src = mejs.Utility.absolutizeUrl(url);
    574                                         break;
    575                                 }
    576                         }
    577                 }
    578 
    579         },
    580         setCurrentTime: function (time) {
    581                 if (this.pluginApi != null) {
    582                         if (this.pluginType == 'youtube') {
    583                                 this.pluginApi.seekTo(time);
    584                         } else {
    585                                 this.pluginApi.setCurrentTime(time);
    586                         }
    587 
    588 
    589 
    590                         this.currentTime = time;
    591                 }
    592         },
    593         setVolume: function (volume) {
    594                 if (this.pluginApi != null) {
    595                         // same on YouTube and MEjs
    596                         if (this.pluginType == 'youtube') {
    597                                 this.pluginApi.setVolume(volume * 100);
    598                         } else {
    599                                 this.pluginApi.setVolume(volume);
    600                         }
    601                         this.volume = volume;
    602                 }
    603         },
    604         setMuted: function (muted) {
    605                 if (this.pluginApi != null) {
    606                         if (this.pluginType == 'youtube') {
    607                                 if (muted) {
    608                                         this.pluginApi.mute();
    609                                 } else {
    610                                         this.pluginApi.unMute();
    611                                 }
    612                                 this.muted = muted;
    613                                 this.dispatchEvent('volumechange');
    614                         } else {
    615                                 this.pluginApi.setMuted(muted);
    616                         }
    617                         this.muted = muted;
    618                 }
    619         },
    620 
    621         // additional non-HTML5 methods
    622         setVideoSize: function (width, height) {
    623 
    624                 //if (this.pluginType == 'flash' || this.pluginType == 'silverlight') {
    625                         if ( this.pluginElement.style) {
    626                                 this.pluginElement.style.width = width + 'px';
    627                                 this.pluginElement.style.height = height + 'px';
    628                         }
    629                         if (this.pluginApi != null && this.pluginApi.setVideoSize) {
    630                                 this.pluginApi.setVideoSize(width, height);
    631                         }
    632                 //}
    633         },
    634 
    635         setFullscreen: function (fullscreen) {
    636                 if (this.pluginApi != null && this.pluginApi.setFullscreen) {
    637                         this.pluginApi.setFullscreen(fullscreen);
    638                 }
    639         },
    640 
    641         enterFullScreen: function() {
    642                 if (this.pluginApi != null && this.pluginApi.setFullscreen) {
    643                         this.setFullscreen(true);
    644                 }
    645 
    646         },
    647 
    648         exitFullScreen: function() {
    649                 if (this.pluginApi != null && this.pluginApi.setFullscreen) {
    650                         this.setFullscreen(false);
    651                 }
    652         },
    653 
    654         // start: fake events
    655         addEventListener: function (eventName, callback, bubble) {
    656                 this.events[eventName] = this.events[eventName] || [];
    657                 this.events[eventName].push(callback);
    658         },
    659         removeEventListener: function (eventName, callback) {
    660                 if (!eventName) { this.events = {}; return true; }
    661                 var callbacks = this.events[eventName];
    662                 if (!callbacks) return true;
    663                 if (!callback) { this.events[eventName] = []; return true; }
    664                 for (i = 0; i < callbacks.length; i++) {
    665                         if (callbacks[i] === callback) {
    666                                 this.events[eventName].splice(i, 1);
    667                                 return true;
    668                         }
    669                 }
    670                 return false;
    671         },
    672         dispatchEvent: function (eventName) {
    673                 var i,
    674                         args,
    675                         callbacks = this.events[eventName];
    676 
    677                 if (callbacks) {
    678                         args = Array.prototype.slice.call(arguments, 1);
    679                         for (i = 0; i < callbacks.length; i++) {
    680                                 callbacks[i].apply(null, args);
    681                         }
    682                 }
    683         },
    684         // end: fake events
    685 
    686         // fake DOM attribute methods
    687         hasAttribute: function(name){
    688                 return (name in this.attributes);
    689         },
    690         removeAttribute: function(name){
    691                 delete this.attributes[name];
    692         },
    693         getAttribute: function(name){
    694                 if (this.hasAttribute(name)) {
    695                         return this.attributes[name];
    696                 }
    697                 return '';
    698         },
    699         setAttribute: function(name, value){
    700                 this.attributes[name] = value;
    701         },
    702 
    703         remove: function() {
    704                 mejs.Utility.removeSwf(this.pluginElement.id);
    705                 mejs.MediaPluginBridge.unregisterPluginElement(this.pluginElement.id);
    706         }
    707 };
    708 
    709 // Handles calls from Flash/Silverlight and reports them as native <video/audio> events and properties
    710 mejs.MediaPluginBridge = {
    711 
    712         pluginMediaElements:{},
    713         htmlMediaElements:{},
    714 
    715         registerPluginElement: function (id, pluginMediaElement, htmlMediaElement) {
    716                 this.pluginMediaElements[id] = pluginMediaElement;
    717                 this.htmlMediaElements[id] = htmlMediaElement;
    718         },
    719 
    720         unregisterPluginElement: function (id) {
    721                 delete this.pluginMediaElements[id];
    722                 delete this.htmlMediaElements[id];
    723         },
    724 
    725         // when Flash/Silverlight is ready, it calls out to this method
    726         initPlugin: function (id) {
    727 
    728                 var pluginMediaElement = this.pluginMediaElements[id],
    729                         htmlMediaElement = this.htmlMediaElements[id];
    730 
    731                 if (pluginMediaElement) {
    732                         // find the javascript bridge
    733                         switch (pluginMediaElement.pluginType) {
    734                                 case "flash":
    735                                         pluginMediaElement.pluginElement = pluginMediaElement.pluginApi = document.getElementById(id);
    736                                         break;
    737                                 case "silverlight":
    738                                         pluginMediaElement.pluginElement = document.getElementById(pluginMediaElement.id);
    739                                         pluginMediaElement.pluginApi = pluginMediaElement.pluginElement.Content.MediaElementJS;
    740                                         break;
    741                         }
    742 
    743                         if (pluginMediaElement.pluginApi != null && pluginMediaElement.success) {
    744                                 pluginMediaElement.success(pluginMediaElement, htmlMediaElement);
    745                         }
    746                 }
    747         },
    748 
    749         // receives events from Flash/Silverlight and sends them out as HTML5 media events
    750         // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
    751         fireEvent: function (id, eventName, values) {
    752 
    753                 var
    754                         e,
    755                         i,
    756                         bufferedTime,
    757                         pluginMediaElement = this.pluginMediaElements[id];
    758 
    759                 // fake event object to mimic real HTML media event.
    760                 e = {
    761                         type: eventName,
    762                         target: pluginMediaElement
    763                 };
    764 
    765                 // attach all values to element and event object
    766                 for (i in values) {
    767                         pluginMediaElement[i] = values[i];
    768                         e[i] = values[i];
    769                 }
    770 
    771                 // fake the newer W3C buffered TimeRange (loaded and total have been removed)
    772                 bufferedTime = values.bufferedTime || 0;
    773 
    774                 e.target.buffered = e.buffered = {
    775                         start: function(index) {
    776                                 return 0;
    777                         },
    778                         end: function (index) {
    779                                 return bufferedTime;
    780                         },
    781                         length: 1
    782                 };
    783 
    784                 pluginMediaElement.dispatchEvent(e.type, e);
    785         }
    786 };
    787 
    788 /*
    789 Default options
    790 */
    791 mejs.MediaElementDefaults = {
    792         // allows testing on HTML5, flash, silverlight
    793         // auto: attempts to detect what the browser can do
    794         // auto_plugin: prefer plugins and then attempt native HTML5
    795         // native: forces HTML5 playback
    796         // shim: disallows HTML5, will attempt either Flash or Silverlight
    797         // none: forces fallback view
    798         mode: 'auto',
    799         // remove or reorder to change plugin priority and availability
    800         plugins: ['flash','silverlight','youtube','vimeo'],
    801         // shows debug errors on screen
    802         enablePluginDebug: false,
    803         // overrides the type specified, useful for dynamic instantiation
    804         type: '',
    805         // path to Flash and Silverlight plugins
    806         pluginPath: mejs.Utility.getScriptPath(['mediaelement.js','mediaelement.min.js','mediaelement-and-player.js','mediaelement-and-player.min.js']),
    807         // name of flash file
    808         flashName: 'flashmediaelement.swf',
    809         // streamer for RTMP streaming
    810         flashStreamer: '',
    811         // turns on the smoothing filter in Flash
    812         enablePluginSmoothing: false,
    813         // name of silverlight file
    814         silverlightName: 'silverlightmediaelement.xap',
    815         // default if the <video width> is not specified
    816         defaultVideoWidth: 480,
    817         // default if the <video height> is not specified
    818         defaultVideoHeight: 270,
    819         // overrides <video width>
    820         pluginWidth: -1,
    821         // overrides <video height>
    822         pluginHeight: -1,
    823         // additional plugin variables in 'key=value' form
    824         pluginVars: [],
    825         // rate in milliseconds for Flash and Silverlight to fire the timeupdate event
    826         // larger number is less accurate, but less strain on plugin->JavaScript bridge
    827         timerRate: 250,
    828         // initial volume for player
    829         startVolume: 0.8,
    830         success: function () { },
    831         error: function () { }
    832 };
    833 
    834 /*
    835 Determines if a browser supports the <video> or <audio> element
    836 and returns either the native element or a Flash/Silverlight version that
    837 mimics HTML5 MediaElement
    838 */
    839 mejs.MediaElement = function (el, o) {
    840         return mejs.HtmlMediaElementShim.create(el,o);
    841 };
    842 
    843 mejs.HtmlMediaElementShim = {
    844 
    845         create: function(el, o) {
    846                 var
    847                         options = mejs.MediaElementDefaults,
    848                         htmlMediaElement = (typeof(el) == 'string') ? document.getElementById(el) : el,
    849                         tagName = htmlMediaElement.tagName.toLowerCase(),
    850                         isMediaTag = (tagName === 'audio' || tagName === 'video'),
    851                         src = (isMediaTag) ? htmlMediaElement.getAttribute('src') : htmlMediaElement.getAttribute('href'),
    852                         poster = htmlMediaElement.getAttribute('poster'),
    853                         autoplay =  htmlMediaElement.getAttribute('autoplay'),
    854                         preload =  htmlMediaElement.getAttribute('preload'),
    855                         controls =  htmlMediaElement.getAttribute('controls'),
    856                         playback,
    857                         prop;
    858 
    859                 // extend options
    860                 for (prop in o) {
    861                         options[prop] = o[prop];
    862                 }
    863 
    864                 // clean up attributes
    865                 src =           (typeof src == 'undefined'      || src === null || src == '') ? null : src;
    866                 poster =        (typeof poster == 'undefined'   || poster === null) ? '' : poster;
    867                 preload =       (typeof preload == 'undefined'  || preload === null || preload === 'false') ? 'none' : preload;
    868                 autoplay =      !(typeof autoplay == 'undefined' || autoplay === null || autoplay === 'false');
    869                 controls =      !(typeof controls == 'undefined' || controls === null || controls === 'false');
    870 
    871                 // test for HTML5 and plugin capabilities
    872                 playback = this.determinePlayback(htmlMediaElement, options, mejs.MediaFeatures.supportsMediaTag, isMediaTag, src);
    873                 playback.url = (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : '';
    874 
    875                 if (playback.method == 'native') {
    876                         // second fix for android
    877                         if (mejs.MediaFeatures.isBustedAndroid) {
    878                                 htmlMediaElement.src = playback.url;
    879                                 htmlMediaElement.addEventListener('click', function() {
    880                                         htmlMediaElement.play();
    881                                 }, false);
    882                         }
    883 
    884                         // add methods to native HTMLMediaElement
    885                         return this.updateNative(playback, options, autoplay, preload);
    886                 } else if (playback.method !== '') {
    887                         // create plugin to mimic HTMLMediaElement
    888 
    889                         return this.createPlugin( playback,  options, poster, autoplay, preload, controls);
    890                 } else {
    891                         // boo, no HTML5, no Flash, no Silverlight.
    892                         this.createErrorMessage( playback, options, poster );
    893 
    894                         return this;
    895                 }
    896         },
    897 
    898         determinePlayback: function(htmlMediaElement, options, supportsMediaTag, isMediaTag, src) {
    899                 var
    900                         mediaFiles = [],
    901                         i,
    902                         j,
    903                         k,
    904                         l,
    905                         n,
    906                         type,
    907                         result = { method: '', url: '', htmlMediaElement: htmlMediaElement, isVideo: (htmlMediaElement.tagName.toLowerCase() != 'audio')},
    908                         pluginName,
    909                         pluginVersions,
    910                         pluginInfo,
    911                         dummy,
    912                         media;
    913 
    914                 // STEP 1: Get URL and type from <video src> or <source src>
    915 
    916                 // supplied type overrides <video type> and <source type>
    917                 if (typeof options.type != 'undefined' && options.type !== '') {
    918 
    919                         // accept either string or array of types
    920                         if (typeof options.type == 'string') {
    921                                 mediaFiles.push({type:options.type, url:src});
    922                         } else {
    923 
    924                                 for (i=0; i<options.type.length; i++) {
    925                                         mediaFiles.push({type:options.type[i], url:src});
    926                                 }
    927                         }
    928 
    929                 // test for src attribute first
    930                 } else if (src !== null) {
    931                         type = this.formatType(src, htmlMediaElement.getAttribute('type'));
    932                         mediaFiles.push({type:type, url:src});
    933 
    934                 // then test for <source> elements
    935                 } else {
    936                         // test <source> types to see if they are usable
    937                         for (i = 0; i < htmlMediaElement.childNodes.length; i++) {
    938                                 n = htmlMediaElement.childNodes[i];
    939                                 if (n.nodeType == 1 && n.tagName.toLowerCase() == 'source') {
    940                                         src = n.getAttribute('src');
    941                                         type = this.formatType(src, n.getAttribute('type'));
    942                                         media = n.getAttribute('media');
    943 
    944                                         if (!media || !window.matchMedia || (window.matchMedia && window.matchMedia(media).matches)) {
    945                                                 mediaFiles.push({type:type, url:src});
    946                                         }
    947                                 }
    948                         }
    949                 }
    950 
    951                 // in the case of dynamicly created players
    952                 // check for audio types
    953                 if (!isMediaTag && mediaFiles.length > 0 && mediaFiles[0].url !== null && this.getTypeFromFile(mediaFiles[0].url).indexOf('audio') > -1) {
    954                         result.isVideo = false;
    955                 }
    956 
    957 
    958                 // STEP 2: Test for playback method
    959 
    960                 // special case for Android which sadly doesn't implement the canPlayType function (always returns '')
    961                 if (mejs.MediaFeatures.isBustedAndroid) {
    962                         htmlMediaElement.canPlayType = function(type) {
    963                                 return (type.match(/video\/(mp4|m4v)/gi) !== null) ? 'maybe' : '';
    964                         };
    965                 }
    966 
    967 
    968                 // test for native playback first
    969                 if (supportsMediaTag && (options.mode === 'auto' || options.mode === 'auto_plugin' || options.mode === 'native')) {
    970 
    971                         if (!isMediaTag) {
    972 
    973                                 // create a real HTML5 Media Element
    974                                 dummy = document.createElement( result.isVideo ? 'video' : 'audio');
    975                                 htmlMediaElement.parentNode.insertBefore(dummy, htmlMediaElement);
    976                                 htmlMediaElement.style.display = 'none';
    977 
    978                                 // use this one from now on
    979                                 result.htmlMediaElement = htmlMediaElement = dummy;
    980                         }
    981 
    982                         for (i=0; i<mediaFiles.length; i++) {
    983                                 // normal check
    984                                 if (htmlMediaElement.canPlayType(mediaFiles[i].type).replace(/no/, '') !== ''
    985                                         // special case for Mac/Safari 5.0.3 which answers '' to canPlayType('audio/mp3') but 'maybe' to canPlayType('audio/mpeg')
    986                                         || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/,'mpeg')).replace(/no/, '') !== '') {
    987                                         result.method = 'native';
    988                                         result.url = mediaFiles[i].url;
    989                                         break;
    990                                 }
    991                         }
    992 
    993                         if (result.method === 'native') {
    994                                 if (result.url !== null) {
    995                                         htmlMediaElement.src = result.url;
    996                                 }
    997 
    998                                 // if `auto_plugin` mode, then cache the native result but try plugins.
    999                                 if (options.mode !== 'auto_plugin') {
    1000                                         return result;
    1001                                 }
    1002                         }
    1003                 }
    1004 
    1005                 // if native playback didn't work, then test plugins
    1006                 if (options.mode === 'auto' || options.mode === 'auto_plugin' || options.mode === 'shim') {
    1007                         for (i=0; i<mediaFiles.length; i++) {
    1008                                 type = mediaFiles[i].type;
    1009 
    1010                                 // test all plugins in order of preference [silverlight, flash]
    1011                                 for (j=0; j<options.plugins.length; j++) {
    1012 
    1013                                         pluginName = options.plugins[j];
    1014 
    1015                                         // test version of plugin (for future features)
    1016                                         pluginVersions = mejs.plugins[pluginName];
    1017 
    1018                                         for (k=0; k<pluginVersions.length; k++) {
    1019                                                 pluginInfo = pluginVersions[k];
    1020 
    1021                                                 // test if user has the correct plugin version
    1022 
    1023                                                 // for youtube/vimeo
    1024                                                 if (pluginInfo.version == null ||
    1025 
    1026                                                         mejs.PluginDetector.hasPluginVersion(pluginName, pluginInfo.version)) {
    1027 
    1028                                                         // test for plugin playback types
    1029                                                         for (l=0; l<pluginInfo.types.length; l++) {
    1030                                                                 // find plugin that can play the type
    1031                                                                 if (type == pluginInfo.types[l]) {
    1032                                                                         result.method = pluginName;
    1033                                                                         result.url = mediaFiles[i].url;
    1034                                                                         return result;
    1035                                                                 }
    1036                                                         }
    1037                                                 }
    1038                                         }
    1039                                 }
    1040                         }
    1041                 }
    1042 
    1043                 // at this point, being in 'auto_plugin' mode implies that we tried plugins but failed.
    1044                 // if we have native support then return that.
    1045                 if (options.mode === 'auto_plugin' && result.method === 'native') {
    1046                         return result;
    1047                 }
    1048 
    1049                 // what if there's nothing to play? just grab the first available
    1050                 if (result.method === '' && mediaFiles.length > 0) {
    1051                         result.url = mediaFiles[0].url;
    1052                 }
    1053 
    1054                 return result;
    1055         },
    1056 
    1057         formatType: function(url, type) {
    1058                 var ext;
    1059 
    1060                 // if no type is supplied, fake it with the extension
    1061                 if (url && !type) {
    1062                         return this.getTypeFromFile(url);
    1063                 } else {
    1064                         // only return the mime part of the type in case the attribute contains the codec
    1065                         // see http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-source-element
    1066                         // `video/mp4; codecs="avc1.42E01E, mp4a.40.2"` becomes `video/mp4`
    1067 
    1068                         if (type && ~type.indexOf(';')) {
    1069                                 return type.substr(0, type.indexOf(';'));
    1070                         } else {
    1071                                 return type;
    1072                         }
    1073                 }
    1074         },
    1075 
    1076         getTypeFromFile: function(url) {
    1077                 url = url.split('?')[0];
    1078                 var ext = url.substring(url.lastIndexOf('.') + 1);
    1079                 return (/(mp4|m4v|ogg|ogv|webm|webmv|flv|wmv|mpeg|mov)/gi.test(ext) ? 'video' : 'audio') + '/' + this.getTypeFromExtension(ext);
    1080         },
    1081 
    1082         getTypeFromExtension: function(ext) {
    1083 
    1084                 switch (ext) {
    1085                         case 'mp4':
    1086                         case 'm4v':
    1087                                 return 'mp4';
    1088                         case 'webm':
    1089                         case 'webma':
    1090                         case 'webmv':
    1091                                 return 'webm';
    1092                         case 'ogg':
    1093                         case 'oga':
    1094                         case 'ogv':
    1095                                 return 'ogg';
    1096                         default:
    1097                                 return ext;
    1098                 }
    1099         },
    1100 
    1101         createErrorMessage: function(playback, options, poster) {
    1102                 var
    1103                         htmlMediaElement = playback.htmlMediaElement,
    1104                         errorContainer = document.createElement('div');
    1105 
    1106                 errorContainer.className = 'me-cannotplay';
    1107 
    1108                 try {
    1109                         errorContainer.style.width = htmlMediaElement.width + 'px';
    1110                         errorContainer.style.height = htmlMediaElement.height + 'px';
    1111                 } catch (e) {}
    1112 
    1113                 errorContainer.innerHTML = (poster !== '') ?
    1114                         '<a href="' + playback.url + '"><img src="' + poster + '" width="100%" height="100%" /></a>' :
    1115                         '<a href="' + playback.url + '"><span>' + mejs.i18n.t('Download File') + '</span></a>';
    1116 
    1117                 htmlMediaElement.parentNode.insertBefore(errorContainer, htmlMediaElement);
    1118                 htmlMediaElement.style.display = 'none';
    1119 
    1120                 options.error(htmlMediaElement);
    1121         },
    1122 
    1123         createPlugin:function(playback, options, poster, autoplay, preload, controls) {
    1124                 var
    1125                         htmlMediaElement = playback.htmlMediaElement,
    1126                         width = 1,
    1127                         height = 1,
    1128                         pluginid = 'me_' + playback.method + '_' + (mejs.meIndex++),
    1129                         pluginMediaElement = new mejs.PluginMediaElement(pluginid, playback.method, playback.url),
    1130                         container = document.createElement('div'),
    1131                         specialIEContainer,
    1132                         node,
    1133                         initVars;
    1134 
    1135                 // copy tagName from html media element
    1136                 pluginMediaElement.tagName = htmlMediaElement.tagName
    1137 
    1138                 // copy attributes from html media element to plugin media element
    1139                 for (var i = 0; i < htmlMediaElement.attributes.length; i++) {
    1140                         var attribute = htmlMediaElement.attributes[i];
    1141                         if (attribute.specified == true) {
    1142                                 pluginMediaElement.setAttribute(attribute.name, attribute.value);
    1143                         }
    1144                 }
    1145 
    1146                 // check for placement inside a <p> tag (sometimes WYSIWYG editors do this)
    1147                 node = htmlMediaElement.parentNode;
    1148                 while (node !== null && node.tagName.toLowerCase() != 'body') {
    1149                         if (node.parentNode.tagName.toLowerCase() == 'p') {
    1150                                 node.parentNode.parentNode.insertBefore(node, node.parentNode);
    1151                                 break;
    1152                         }
    1153                         node = node.parentNode;
    1154                 }
    1155 
    1156                 if (playback.isVideo) {
    1157                         width = (options.videoWidth > 0) ? options.videoWidth : (htmlMediaElement.getAttribute('width') !== null) ? htmlMediaElement.getAttribute('width') : options.defaultVideoWidth;
    1158                         height = (options.videoHeight > 0) ? options.videoHeight : (htmlMediaElement.getAttribute('height') !== null) ? htmlMediaElement.getAttribute('height') : options.defaultVideoHeight;
    1159 
    1160                         // in case of '%' make sure it's encoded
    1161                         width = mejs.Utility.encodeUrl(width);
    1162                         height = mejs.Utility.encodeUrl(height);
    1163 
    1164                 } else {
    1165                         if (options.enablePluginDebug) {
    1166                                 width = 320;
    1167                                 height = 240;
    1168                         }
    1169                 }
    1170 
    1171                 // register plugin
    1172                 pluginMediaElement.success = options.success;
    1173                 mejs.MediaPluginBridge.registerPluginElement(pluginid, pluginMediaElement, htmlMediaElement);
    1174 
    1175                 // add container (must be added to DOM before inserting HTML for IE)
    1176                 container.className = 'me-plugin';
    1177                 container.id = pluginid + '_container';
    1178 
    1179                 if (playback.isVideo) {
    1180                                 htmlMediaElement.parentNode.insertBefore(container, htmlMediaElement);
    1181                 } else {
    1182                                 document.body.insertBefore(container, document.body.childNodes[0]);
    1183                 }
    1184 
    1185                 // flash/silverlight vars
    1186                 initVars = [
    1187                         'id=' + pluginid,
    1188                         'isvideo=' + ((playback.isVideo) ? "true" : "false"),
    1189                         'autoplay=' + ((autoplay) ? "true" : "false"),
    1190                         'preload=' + preload,
    1191                         'width=' + width,
    1192                         'startvolume=' + options.startVolume,
    1193                         'timerrate=' + options.timerRate,
    1194                         'flashstreamer=' + options.flashStreamer,
    1195                         'height=' + height];
    1196 
    1197                 if (playback.url !== null) {
    1198                         if (playback.method == 'flash') {
    1199                                 initVars.push('file=' + mejs.Utility.encodeUrl(playback.url));
    1200                         } else {
    1201                                 initVars.push('file=' + playback.url);
    1202                         }
    1203                 }
    1204                 if (options.enablePluginDebug) {
    1205                         initVars.push('debug=true');
    1206                 }
    1207                 if (options.enablePluginSmoothing) {
    1208                         initVars.push('smoothing=true');
    1209                 }
    1210                 if (controls) {
    1211                         initVars.push('controls=true'); // shows controls in the plugin if desired
    1212                 }
    1213                 if (options.pluginVars) {
    1214                         initVars = initVars.concat(options.pluginVars);
    1215                 }
    1216 
    1217                 switch (playback.method) {
    1218                         case 'silverlight':
    1219                                 container.innerHTML =
    1220 '<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '" class="mejs-shim">' +
    1221 '<param name="initParams" value="' + initVars.join(',') + '" />' +
    1222 '<param name="windowless" value="true" />' +
    1223 '<param name="background" value="black" />' +
    1224 '<param name="minRuntimeVersion" value="3.0.0.0" />' +
    1225 '<param name="autoUpgrade" value="true" />' +
    1226 '<param name="source" value="' + options.pluginPath + options.silverlightName + '" />' +
    1227 '</object>';
    1228                                         break;
    1229 
    1230                         case 'flash':
    1231 
    1232                                 if (mejs.MediaFeatures.isIE) {
    1233                                         specialIEContainer = document.createElement('div');
    1234                                         container.appendChild(specialIEContainer);
    1235                                         specialIEContainer.outerHTML =
    1236 '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
    1237 'id="' + pluginid + '" width="' + width + '" height="' + height + '" class="mejs-shim">' +
    1238 '<param name="movie" value="' + options.pluginPath + options.flashName + '?x=' + (new Date()) + '" />' +
    1239 '<param name="flashvars" value="' + initVars.join('&amp;') + '" />' +
    1240 '<param name="quality" value="high" />' +
    1241 '<param name="bgcolor" value="#000000" />' +
    1242 '<param name="wmode" value="transparent" />' +
    1243 '<param name="allowScriptAccess" value="always" />' +
    1244 '<param name="allowFullScreen" value="true" />' +
    1245 '</object>';
    1246 
    1247                                 } else {
    1248 
    1249                                         container.innerHTML =
    1250 '<embed id="' + pluginid + '" name="' + pluginid + '" ' +
    1251 'play="true" ' +
    1252 'loop="false" ' +
    1253 'quality="high" ' +
    1254 'bgcolor="#000000" ' +
    1255 'wmode="transparent" ' +
    1256 'allowScriptAccess="always" ' +
    1257 'allowFullScreen="true" ' +
    1258 'type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" ' +
    1259 'src="' + options.pluginPath + options.flashName + '" ' +
    1260 'flashvars="' + initVars.join('&') + '" ' +
    1261 'width="' + width + '" ' +
    1262 'height="' + height + '" ' +
    1263 'class="mejs-shim"></embed>';
    1264                                 }
    1265                                 break;
    1266 
    1267                         case 'youtube':
    1268 
    1269 
    1270                                 var
    1271                                         videoId = playback.url.substr(playback.url.lastIndexOf('=')+1);
    1272                                         youtubeSettings = {
    1273                                                 container: container,
    1274                                                 containerId: container.id,
    1275                                                 pluginMediaElement: pluginMediaElement,
    1276                                                 pluginId: pluginid,
    1277                                                 videoId: videoId,
    1278                                                 height: height,
    1279                                                 width: width
    1280                                         };
    1281 
    1282                                 if (mejs.PluginDetector.hasPluginVersion('flash', [10,0,0]) ) {
    1283                                         mejs.YouTubeApi.createFlash(youtubeSettings);
    1284                                 } else {
    1285                                         mejs.YouTubeApi.enqueueIframe(youtubeSettings);
    1286                                 }
    1287 
    1288                                 break;
    1289 
    1290                         // DEMO Code. Does NOT work.
    1291                         case 'vimeo':
    1292                                 //console.log('vimeoid');
    1293 
    1294                                 pluginMediaElement.vimeoid = playback.url.substr(playback.url.lastIndexOf('/')+1);
    1295 
    1296                                 container.innerHTML ='<iframe src="http://player.vimeo.com/video/' + pluginMediaElement.vimeoid + '?portrait=0&byline=0&title=0" width="' + width +'" height="' + height +'" frameborder="0" class="mejs-shim"></iframe>';
    1297 
    1298                                 /*
    1299                                 container.innerHTML =
    1300                                         '<object width="' + width + '" height="' + height + '" class="mejs-shim">' +
    1301                                                 '<param name="allowfullscreen" value="true" />' +
    1302                                                 '<param name="allowscriptaccess" value="always" />' +
    1303                                                 '<param name="flashvars" value="api=1" />' +
    1304                                                 '<param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=' + pluginMediaElement.vimeoid  + '&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" />' +
    1305                                                 '<embed src="//vimeo.com/moogaloop.swf?api=1&amp;clip_id=' + pluginMediaElement.vimeoid + '&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="' + width + '" height="' + height + '" class="mejs-shim"></embed>' +
    1306                                         '</object>';
    1307                                         */
    1308 
    1309                                 break;
    1310                 }
    1311                 // hide original element
    1312                 htmlMediaElement.style.display = 'none';
    1313 
    1314                 // FYI: options.success will be fired by the MediaPluginBridge
    1315 
    1316                 return pluginMediaElement;
    1317         },
    1318 
    1319         updateNative: function(playback, options, autoplay, preload) {
    1320 
    1321                 var htmlMediaElement = playback.htmlMediaElement,
    1322                         m;
    1323 
    1324 
    1325                 // add methods to video object to bring it into parity with Flash Object
    1326                 for (m in mejs.HtmlMediaElement) {
    1327                         htmlMediaElement[m] = mejs.HtmlMediaElement[m];
    1328                 }
    1329 
    1330                 /*
    1331                 Chrome now supports preload="none"
    1332                 if (mejs.MediaFeatures.isChrome) {
    1333 
    1334                         // special case to enforce preload attribute (Chrome doesn't respect this)
    1335                         if (preload === 'none' && !autoplay) {
    1336 
    1337                                 // forces the browser to stop loading (note: fails in IE9)
    1338                                 htmlMediaElement.src = '';
    1339                                 htmlMediaElement.load();
    1340                                 htmlMediaElement.canceledPreload = true;
    1341 
    1342                                 htmlMediaElement.addEventListener('play',function() {
    1343                                         if (htmlMediaElement.canceledPreload) {
    1344                                                 htmlMediaElement.src = playback.url;
    1345                                                 htmlMediaElement.load();
    1346                                                 htmlMediaElement.play();
    1347                                                 htmlMediaElement.canceledPreload = false;
    1348                                         }
    1349                                 }, false);
    1350                         // for some reason Chrome forgets how to autoplay sometimes.
    1351                         } else if (autoplay) {
    1352                                 htmlMediaElement.load();
    1353                                 htmlMediaElement.play();
    1354                         }
    1355                 }
    1356                 */
    1357 
    1358                 // fire success code
    1359                 options.success(htmlMediaElement, htmlMediaElement);
    1360 
    1361                 return htmlMediaElement;
    1362         }
    1363 };
    1364 
    1365 /*
    1366  - test on IE (object vs. embed)
    1367  - determine when to use iframe (Firefox, Safari, Mobile) vs. Flash (Chrome, IE)
    1368  - fullscreen?
    1369 */
    1370 
    1371 // YouTube Flash and Iframe API
    1372 mejs.YouTubeApi = {
    1373         isIframeStarted: false,
    1374         isIframeLoaded: false,
    1375         loadIframeApi: function() {
    1376                 if (!this.isIframeStarted) {
    1377                         var tag = document.createElement('script');
    1378                         tag.src = "http://www.youtube.com/player_api";
    1379                         var firstScriptTag = document.getElementsByTagName('script')[0];
    1380                         firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
    1381                         this.isIframeStarted = true;
    1382                 }
    1383         },
    1384         iframeQueue: [],
    1385         enqueueIframe: function(yt) {
    1386 
    1387                 if (this.isLoaded) {
    1388                         this.createIframe(yt);
    1389                 } else {
    1390                         this.loadIframeApi();
    1391                         this.iframeQueue.push(yt);
    1392                 }
    1393         },
    1394         createIframe: function(settings) {
    1395 
    1396                 var
    1397                 pluginMediaElement = settings.pluginMediaElement,
    1398                 player = new YT.Player(settings.containerId, {
    1399                         height: settings.height,
    1400                         width: settings.width,
    1401                         videoId: settings.videoId,
    1402                         playerVars: {controls:0},
    1403                         events: {
    1404                                 'onReady': function() {
    1405 
    1406                                         // hook up iframe object to MEjs
    1407                                         settings.pluginMediaElement.pluginApi = player;
    1408 
    1409                                         // init mejs
    1410                                         mejs.MediaPluginBridge.initPlugin(settings.pluginId);
    1411 
    1412                                         // create timer
    1413                                         setInterval(function() {
    1414                                                 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
    1415                                         }, 250);
    1416                                 },
    1417                                 'onStateChange': function(e) {
    1418 
    1419                                         mejs.YouTubeApi.handleStateChange(e.data, player, pluginMediaElement);
    1420 
    1421                                 }
    1422                         }
    1423                 });
    1424         },
    1425 
    1426         createEvent: function (player, pluginMediaElement, eventName) {
    1427                 var obj = {
    1428                         type: eventName,
    1429                         target: pluginMediaElement
    1430                 };
    1431 
    1432                 if (player && player.getDuration) {
    1433 
    1434                         // time
    1435                         pluginMediaElement.currentTime = obj.currentTime = player.getCurrentTime();
    1436                         pluginMediaElement.duration = obj.duration = player.getDuration();
    1437 
    1438                         // state
    1439                         obj.paused = pluginMediaElement.paused;
    1440                         obj.ended = pluginMediaElement.ended;
    1441 
    1442                         // sound
    1443                         obj.muted = player.isMuted();
    1444                         obj.volume = player.getVolume() / 100;
    1445 
    1446                         // progress
    1447                         obj.bytesTotal = player.getVideoBytesTotal();
    1448                         obj.bufferedBytes = player.getVideoBytesLoaded();
    1449 
    1450                         // fake the W3C buffered TimeRange
    1451                         var bufferedTime = obj.bufferedBytes / obj.bytesTotal * obj.duration;
    1452 
    1453                         obj.target.buffered = obj.buffered = {
    1454                                 start: function(index) {
    1455                                         return 0;
    1456                                 },
    1457                                 end: function (index) {
    1458                                         return bufferedTime;
    1459                                 },
    1460                                 length: 1
    1461                         };
    1462 
    1463                 }
    1464 
    1465                 // send event up the chain
    1466                 pluginMediaElement.dispatchEvent(obj.type, obj);
    1467         },
    1468 
    1469         iFrameReady: function() {
    1470 
    1471                 this.isLoaded = true;
    1472                 this.isIframeLoaded = true;
    1473 
    1474                 while (this.iframeQueue.length > 0) {
    1475                         var settings = this.iframeQueue.pop();
    1476                         this.createIframe(settings);
    1477                 }
    1478         },
    1479 
    1480         // FLASH!
    1481         flashPlayers: {},
    1482         createFlash: function(settings) {
    1483 
    1484                 this.flashPlayers[settings.pluginId] = settings;
    1485 
    1486                 /*
    1487                 settings.container.innerHTML =
    1488                         '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="//www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId  + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0" ' +
    1489                                 'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; " class="mejs-shim">' +
    1490                                 '<param name="allowScriptAccess" value="always">' +
    1491                                 '<param name="wmode" value="transparent">' +
    1492                         '</object>';
    1493                 */
    1494 
    1495                 var specialIEContainer,
    1496                         youtubeUrl = 'http://www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId  + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0';
    1497 
    1498                 if (mejs.MediaFeatures.isIE) {
    1499 
    1500                         specialIEContainer = document.createElement('div');
    1501                         settings.container.appendChild(specialIEContainer);
    1502                         specialIEContainer.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
    1503 'id="' + settings.pluginId + '" width="' + settings.width + '" height="' + settings.height + '" class="mejs-shim">' +
    1504         '<param name="movie" value="' + youtubeUrl + '" />' +
    1505         '<param name="wmode" value="transparent" />' +
    1506         '<param name="allowScriptAccess" value="always" />' +
    1507         '<param name="allowFullScreen" value="true" />' +
    1508 '</object>';
    1509                 } else {
    1510                 settings.container.innerHTML =
    1511                         '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="' + youtubeUrl + '" ' +
    1512                                 'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; " class="mejs-shim">' +
    1513                                 '<param name="allowScriptAccess" value="always">' +
    1514                                 '<param name="wmode" value="transparent">' +
    1515                         '</object>';
    1516                 }
    1517 
    1518         },
    1519 
    1520         flashReady: function(id) {
    1521                 var
    1522                         settings = this.flashPlayers[id],
    1523                         player = document.getElementById(id),
    1524                         pluginMediaElement = settings.pluginMediaElement;
    1525 
    1526                 // hook up and return to MediaELementPlayer.success
    1527                 pluginMediaElement.pluginApi =
    1528                 pluginMediaElement.pluginElement = player;
    1529                 mejs.MediaPluginBridge.initPlugin(id);
    1530 
    1531                 // load the youtube video
    1532                 player.cueVideoById(settings.videoId);
    1533 
    1534                 var callbackName = settings.containerId + '_callback';
    1535 
    1536                 window[callbackName] = function(e) {
    1537                         mejs.YouTubeApi.handleStateChange(e, player, pluginMediaElement);
    1538                 }
    1539 
    1540                 player.addEventListener('onStateChange', callbackName);
    1541 
    1542                 setInterval(function() {
    1543                         mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
    1544                 }, 250);
    1545         },
    1546 
    1547         handleStateChange: function(youTubeState, player, pluginMediaElement) {
    1548                 switch (youTubeState) {
    1549                         case -1: // not started
    1550                                 pluginMediaElement.paused = true;
    1551                                 pluginMediaElement.ended = true;
    1552                                 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'loadedmetadata');
    1553                                 //createYouTubeEvent(player, pluginMediaElement, 'loadeddata');
    1554                                 break;
    1555                         case 0:
    1556                                 pluginMediaElement.paused = false;
    1557                                 pluginMediaElement.ended = true;
    1558                                 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'ended');
    1559                                 break;
    1560                         case 1:
    1561                                 pluginMediaElement.paused = false;
    1562                                 pluginMediaElement.ended = false;
    1563                                 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'play');
    1564                                 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'playing');
    1565                                 break;
    1566                         case 2:
    1567                                 pluginMediaElement.paused = true;
    1568                                 pluginMediaElement.ended = false;
    1569                                 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'pause');
    1570                                 break;
    1571                         case 3: // buffering
    1572                                 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'progress');
    1573                                 break;
    1574                         case 5:
    1575                                 // cued?
    1576                                 break;
    1577 
    1578                 }
    1579 
    1580         }
    1581 }
    1582 // IFRAME
    1583 function onYouTubePlayerAPIReady() {
    1584         mejs.YouTubeApi.iFrameReady();
    1585 }
    1586 // FLASH
    1587 function onYouTubePlayerReady(id) {
    1588         mejs.YouTubeApi.flashReady(id);
    1589 }
    1590 
    1591 window.mejs = mejs;
    1592 window.MediaElement = mejs.MediaElement;
     13*/var mejs=mejs||{};mejs.version="2.11.1";mejs.meIndex=0;
     14mejs.plugins={silverlight:[{version:[3,0],types:["video/mp4","video/m4v","video/mov","video/wmv","audio/wma","audio/m4a","audio/mp3","audio/wav","audio/mpeg"]}],flash:[{version:[9,0,124],types:["video/mp4","video/m4v","video/mov","video/flv","video/rtmp","video/x-flv","audio/flv","audio/x-flv","audio/mp3","audio/m4a","audio/mpeg","video/youtube","video/x-youtube"]}],youtube:[{version:null,types:["video/youtube","video/x-youtube","audio/youtube","audio/x-youtube"]}],vimeo:[{version:null,types:["video/vimeo",
     15"video/x-vimeo"]}]};
     16mejs.Utility={encodeUrl:function(a){return encodeURIComponent(a)},escapeHTML:function(a){return a.toString().split("&").join("&amp;").split("<").join("&lt;").split('"').join("&quot;")},absolutizeUrl:function(a){var b=document.createElement("div");b.innerHTML='<a href="'+this.escapeHTML(a)+'">x</a>';return b.firstChild.href},getScriptPath:function(a){for(var b=0,c,d="",e="",g,f,h=document.getElementsByTagName("script"),l=h.length,j=a.length;b<l;b++){f=h[b].src;for(c=0;c<j;c++){e=a[c];g=f.indexOf(e);
     17if(g>-1&&g==f.length-e.length){d=f.substring(0,g);break}}if(d!=="")break}return d},secondsToTimeCode:function(a,b,c,d){if(typeof c=="undefined")c=false;else if(typeof d=="undefined")d=25;var e=Math.floor(a/3600)%24,g=Math.floor(a/60)%60,f=Math.floor(a%60);a=Math.floor((a%1*d).toFixed(3));return(b||e>0?(e<10?"0"+e:e)+":":"")+(g<10?"0"+g:g)+":"+(f<10?"0"+f:f)+(c?":"+(a<10?"0"+a:a):"")},timeCodeToSeconds:function(a,b,c,d){if(typeof c=="undefined")c=false;else if(typeof d=="undefined")d=25;a=a.split(":");
     18b=parseInt(a[0],10);var e=parseInt(a[1],10),g=parseInt(a[2],10),f=0,h=0;if(c)f=parseInt(a[3])/d;return h=b*3600+e*60+g+f},convertSMPTEtoSeconds:function(a){if(typeof a!="string")return false;a=a.replace(",",".");var b=0,c=a.indexOf(".")!=-1?a.split(".")[1].length:0,d=1;a=a.split(":").reverse();for(var e=0;e<a.length;e++){d=1;if(e>0)d=Math.pow(60,e);b+=Number(a[e])*d}return Number(b.toFixed(c))},removeSwf:function(a){var b=document.getElementById(a);if(b&&/object|embed/i.test(b.nodeName))if(mejs.MediaFeatures.isIE){b.style.display=
     19"none";(function(){b.readyState==4?mejs.Utility.removeObjectInIE(a):setTimeout(arguments.callee,10)})()}else b.parentNode.removeChild(b)},removeObjectInIE:function(a){if(a=document.getElementById(a)){for(var b in a)if(typeof a[b]=="function")a[b]=null;a.parentNode.removeChild(a)}}};
     20mejs.PluginDetector={hasPluginVersion:function(a,b){var c=this.plugins[a];b[1]=b[1]||0;b[2]=b[2]||0;return c[0]>b[0]||c[0]==b[0]&&c[1]>b[1]||c[0]==b[0]&&c[1]==b[1]&&c[2]>=b[2]?true:false},nav:window.navigator,ua:window.navigator.userAgent.toLowerCase(),plugins:[],addPlugin:function(a,b,c,d,e){this.plugins[a]=this.detectPlugin(b,c,d,e)},detectPlugin:function(a,b,c,d){var e=[0,0,0],g;if(typeof this.nav.plugins!="undefined"&&typeof this.nav.plugins[a]=="object"){if((c=this.nav.plugins[a].description)&&
     21!(typeof this.nav.mimeTypes!="undefined"&&this.nav.mimeTypes[b]&&!this.nav.mimeTypes[b].enabledPlugin)){e=c.replace(a,"").replace(/^\s+/,"").replace(/\sr/gi,".").split(".");for(a=0;a<e.length;a++)e[a]=parseInt(e[a].match(/\d+/),10)}}else if(typeof window.ActiveXObject!="undefined")try{if(g=new ActiveXObject(c))e=d(g)}catch(f){}return e}};
     22mejs.PluginDetector.addPlugin("flash","Shockwave Flash","application/x-shockwave-flash","ShockwaveFlash.ShockwaveFlash",function(a){var b=[];if(a=a.GetVariable("$version")){a=a.split(" ")[1].split(",");b=[parseInt(a[0],10),parseInt(a[1],10),parseInt(a[2],10)]}return b});
     23mejs.PluginDetector.addPlugin("silverlight","Silverlight Plug-In","application/x-silverlight-2","AgControl.AgControl",function(a){var b=[0,0,0,0],c=function(d,e,g,f){for(;d.isVersionSupported(e[0]+"."+e[1]+"."+e[2]+"."+e[3]);)e[g]+=f;e[g]-=f};c(a,b,0,1);c(a,b,1,1);c(a,b,2,1E4);c(a,b,2,1E3);c(a,b,2,100);c(a,b,2,10);c(a,b,2,1);c(a,b,3,1);return b});
     24mejs.MediaFeatures={init:function(){var a=this,b=document,c=mejs.PluginDetector.nav,d=mejs.PluginDetector.ua.toLowerCase(),e,g=["source","track","audio","video"];a.isiPad=d.match(/ipad/i)!==null;a.isiPhone=d.match(/iphone/i)!==null;a.isiOS=a.isiPhone||a.isiPad;a.isAndroid=d.match(/android/i)!==null;a.isBustedAndroid=d.match(/android 2\.[12]/)!==null;a.isIE=c.appName.toLowerCase().indexOf("microsoft")!=-1;a.isChrome=d.match(/chrome/gi)!==null;a.isFirefox=d.match(/firefox/gi)!==null;a.isWebkit=d.match(/webkit/gi)!==
     25null;a.isGecko=d.match(/gecko/gi)!==null&&!a.isWebkit;a.isOpera=d.match(/opera/gi)!==null;a.hasTouch="ontouchstart"in window;a.svg=!!document.createElementNS&&!!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect;for(c=0;c<g.length;c++)e=document.createElement(g[c]);a.supportsMediaTag=typeof e.canPlayType!=="undefined"||a.isBustedAndroid;a.hasSemiNativeFullScreen=typeof e.webkitEnterFullscreen!=="undefined";a.hasWebkitNativeFullScreen=typeof e.webkitRequestFullScreen!=="undefined";
     26a.hasMozNativeFullScreen=typeof e.mozRequestFullScreen!=="undefined";a.hasTrueNativeFullScreen=a.hasWebkitNativeFullScreen||a.hasMozNativeFullScreen;a.nativeFullScreenEnabled=a.hasTrueNativeFullScreen;if(a.hasMozNativeFullScreen)a.nativeFullScreenEnabled=e.mozFullScreenEnabled;if(this.isChrome)a.hasSemiNativeFullScreen=false;if(a.hasTrueNativeFullScreen){a.fullScreenEventName=a.hasWebkitNativeFullScreen?"webkitfullscreenchange":"mozfullscreenchange";a.isFullScreen=function(){if(e.mozRequestFullScreen)return b.mozFullScreen;
     27else if(e.webkitRequestFullScreen)return b.webkitIsFullScreen};a.requestFullScreen=function(f){if(a.hasWebkitNativeFullScreen)f.webkitRequestFullScreen();else a.hasMozNativeFullScreen&&f.mozRequestFullScreen()};a.cancelFullScreen=function(){if(a.hasWebkitNativeFullScreen)document.webkitCancelFullScreen();else a.hasMozNativeFullScreen&&document.mozCancelFullScreen()}}if(a.hasSemiNativeFullScreen&&d.match(/mac os x 10_5/i)){a.hasNativeFullScreen=false;a.hasSemiNativeFullScreen=false}}};mejs.MediaFeatures.init();
     28mejs.HtmlMediaElement={pluginType:"native",isFullScreen:false,setCurrentTime:function(a){this.currentTime=a},setMuted:function(a){this.muted=a},setVolume:function(a){this.volume=a},stop:function(){this.pause()},setSrc:function(a){for(var b=this.getElementsByTagName("source");b.length>0;)this.removeChild(b[0]);if(typeof a=="string")this.src=a;else{var c;for(b=0;b<a.length;b++){c=a[b];if(this.canPlayType(c.type)){this.src=c.src;break}}}},setVideoSize:function(a,b){this.width=a;this.height=b}};
     29mejs.PluginMediaElement=function(a,b,c){this.id=a;this.pluginType=b;this.src=c;this.events={};this.attributes={}};
     30mejs.PluginMediaElement.prototype={pluginElement:null,pluginType:"",isFullScreen:false,playbackRate:-1,defaultPlaybackRate:-1,seekable:[],played:[],paused:true,ended:false,seeking:false,duration:0,error:null,tagName:"",muted:false,volume:1,currentTime:0,play:function(){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.playVideo():this.pluginApi.playMedia();this.paused=false}},load:function(){if(this.pluginApi!=null){this.pluginType!="youtube"&&this.pluginApi.loadMedia();this.paused=
     31false}},pause:function(){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.pauseVideo():this.pluginApi.pauseMedia();this.paused=true}},stop:function(){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.stopVideo():this.pluginApi.stopMedia();this.paused=true}},canPlayType:function(a){var b,c,d,e=mejs.plugins[this.pluginType];for(b=0;b<e.length;b++){d=e[b];if(mejs.PluginDetector.hasPluginVersion(this.pluginType,d.version))for(c=0;c<d.types.length;c++)if(a==d.types[c])return"probably"}return""},
     32positionFullscreenButton:function(a,b,c){this.pluginApi!=null&&this.pluginApi.positionFullscreenButton&&this.pluginApi.positionFullscreenButton(a,b,c)},hideFullscreenButton:function(){this.pluginApi!=null&&this.pluginApi.hideFullscreenButton&&this.pluginApi.hideFullscreenButton()},setSrc:function(a){if(typeof a=="string"){this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(a));this.src=mejs.Utility.absolutizeUrl(a)}else{var b,c;for(b=0;b<a.length;b++){c=a[b];if(this.canPlayType(c.type)){this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(c.src));
     33this.src=mejs.Utility.absolutizeUrl(a);break}}}},setCurrentTime:function(a){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.seekTo(a):this.pluginApi.setCurrentTime(a);this.currentTime=a}},setVolume:function(a){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.setVolume(a*100):this.pluginApi.setVolume(a);this.volume=a}},setMuted:function(a){if(this.pluginApi!=null){if(this.pluginType=="youtube"){a?this.pluginApi.mute():this.pluginApi.unMute();this.muted=a;this.dispatchEvent("volumechange")}else this.pluginApi.setMuted(a);
     34this.muted=a}},setVideoSize:function(a,b){if(this.pluginElement.style){this.pluginElement.style.width=a+"px";this.pluginElement.style.height=b+"px"}this.pluginApi!=null&&this.pluginApi.setVideoSize&&this.pluginApi.setVideoSize(a,b)},setFullscreen:function(a){this.pluginApi!=null&&this.pluginApi.setFullscreen&&this.pluginApi.setFullscreen(a)},enterFullScreen:function(){this.pluginApi!=null&&this.pluginApi.setFullscreen&&this.setFullscreen(true)},exitFullScreen:function(){this.pluginApi!=null&&this.pluginApi.setFullscreen&&
     35this.setFullscreen(false)},addEventListener:function(a,b){this.events[a]=this.events[a]||[];this.events[a].push(b)},removeEventListener:function(a,b){if(!a){this.events={};return true}var c=this.events[a];if(!c)return true;if(!b){this.events[a]=[];return true}for(i=0;i<c.length;i++)if(c[i]===b){this.events[a].splice(i,1);return true}return false},dispatchEvent:function(a){var b,c,d=this.events[a];if(d){c=Array.prototype.slice.call(arguments,1);for(b=0;b<d.length;b++)d[b].apply(null,c)}},hasAttribute:function(a){return a in
     36this.attributes},removeAttribute:function(a){delete this.attributes[a]},getAttribute:function(a){if(this.hasAttribute(a))return this.attributes[a];return""},setAttribute:function(a,b){this.attributes[a]=b},remove:function(){mejs.Utility.removeSwf(this.pluginElement.id);mejs.MediaPluginBridge.unregisterPluginElement(this.pluginElement.id)}};
     37mejs.MediaPluginBridge={pluginMediaElements:{},htmlMediaElements:{},registerPluginElement:function(a,b,c){this.pluginMediaElements[a]=b;this.htmlMediaElements[a]=c},unregisterPluginElement:function(a){delete this.pluginMediaElements[a];delete this.htmlMediaElements[a]},initPlugin:function(a){var b=this.pluginMediaElements[a],c=this.htmlMediaElements[a];if(b){switch(b.pluginType){case "flash":b.pluginElement=b.pluginApi=document.getElementById(a);break;case "silverlight":b.pluginElement=document.getElementById(b.id);
     38b.pluginApi=b.pluginElement.Content.MediaElementJS}b.pluginApi!=null&&b.success&&b.success(b,c)}},fireEvent:function(a,b,c){var d,e;a=this.pluginMediaElements[a];b={type:b,target:a};for(d in c){a[d]=c[d];b[d]=c[d]}e=c.bufferedTime||0;b.target.buffered=b.buffered={start:function(){return 0},end:function(){return e},length:1};a.dispatchEvent(b.type,b)}};
     39mejs.MediaElementDefaults={mode:"auto",plugins:["flash","silverlight","youtube","vimeo"],enablePluginDebug:false,type:"",pluginPath:mejs.Utility.getScriptPath(["mediaelement.js","mediaelement.min.js","mediaelement-and-player.js","mediaelement-and-player.min.js"]),flashName:"flashmediaelement.swf",flashStreamer:"",enablePluginSmoothing:false,enablePseudoStreaming:false,pseudoStreamingStartQueryParam:"start",silverlightName:"silverlightmediaelement.xap",defaultVideoWidth:480,defaultVideoHeight:270,
     40pluginWidth:-1,pluginHeight:-1,pluginVars:[],timerRate:250,startVolume:0.8,success:function(){},error:function(){}};mejs.MediaElement=function(a,b){return mejs.HtmlMediaElementShim.create(a,b)};
     41mejs.HtmlMediaElementShim={create:function(a,b){var c=mejs.MediaElementDefaults,d=typeof a=="string"?document.getElementById(a):a,e=d.tagName.toLowerCase(),g=e==="audio"||e==="video",f=g?d.getAttribute("src"):d.getAttribute("href");e=d.getAttribute("poster");var h=d.getAttribute("autoplay"),l=d.getAttribute("preload"),j=d.getAttribute("controls"),k;for(k in b)c[k]=b[k];f=typeof f=="undefined"||f===null||f==""?null:f;e=typeof e=="undefined"||e===null?"":e;l=typeof l=="undefined"||l===null||l==="false"?
     42"none":l;h=!(typeof h=="undefined"||h===null||h==="false");j=!(typeof j=="undefined"||j===null||j==="false");k=this.determinePlayback(d,c,mejs.MediaFeatures.supportsMediaTag,g,f);k.url=k.url!==null?mejs.Utility.absolutizeUrl(k.url):"";if(k.method=="native"){if(mejs.MediaFeatures.isBustedAndroid){d.src=k.url;d.addEventListener("click",function(){d.play()},false)}return this.updateNative(k,c,h,l)}else if(k.method!=="")return this.createPlugin(k,c,e,h,l,j);else{this.createErrorMessage(k,c,e);return this}},
     43determinePlayback:function(a,b,c,d,e){var g=[],f,h,l,j={method:"",url:"",htmlMediaElement:a,isVideo:a.tagName.toLowerCase()!="audio"},k;if(typeof b.type!="undefined"&&b.type!=="")if(typeof b.type=="string")g.push({type:b.type,url:e});else for(f=0;f<b.type.length;f++)g.push({type:b.type[f],url:e});else if(e!==null){l=this.formatType(e,a.getAttribute("type"));g.push({type:l,url:e})}else for(f=0;f<a.childNodes.length;f++){h=a.childNodes[f];if(h.nodeType==1&&h.tagName.toLowerCase()=="source"){e=h.getAttribute("src");
     44l=this.formatType(e,h.getAttribute("type"));h=h.getAttribute("media");if(!h||!window.matchMedia||window.matchMedia&&window.matchMedia(h).matches)g.push({type:l,url:e})}}if(!d&&g.length>0&&g[0].url!==null&&this.getTypeFromFile(g[0].url).indexOf("audio")>-1)j.isVideo=false;if(mejs.MediaFeatures.isBustedAndroid)a.canPlayType=function(m){return m.match(/video\/(mp4|m4v)/gi)!==null?"maybe":""};if(c&&(b.mode==="auto"||b.mode==="auto_plugin"||b.mode==="native")){if(!d){f=document.createElement(j.isVideo?
     45"video":"audio");a.parentNode.insertBefore(f,a);a.style.display="none";j.htmlMediaElement=a=f}for(f=0;f<g.length;f++)if(a.canPlayType(g[f].type).replace(/no/,"")!==""||a.canPlayType(g[f].type.replace(/mp3/,"mpeg")).replace(/no/,"")!==""){j.method="native";j.url=g[f].url;break}if(j.method==="native"){if(j.url!==null)a.src=j.url;if(b.mode!=="auto_plugin")return j}}if(b.mode==="auto"||b.mode==="auto_plugin"||b.mode==="shim")for(f=0;f<g.length;f++){l=g[f].type;for(a=0;a<b.plugins.length;a++){e=b.plugins[a];
     46h=mejs.plugins[e];for(c=0;c<h.length;c++){k=h[c];if(k.version==null||mejs.PluginDetector.hasPluginVersion(e,k.version))for(d=0;d<k.types.length;d++)if(l==k.types[d]){j.method=e;j.url=g[f].url;return j}}}}if(b.mode==="auto_plugin"&&j.method==="native")return j;if(j.method===""&&g.length>0)j.url=g[0].url;return j},formatType:function(a,b){return a&&!b?this.getTypeFromFile(a):b&&~b.indexOf(";")?b.substr(0,b.indexOf(";")):b},getTypeFromFile:function(a){a=a.split("?")[0];a=a.substring(a.lastIndexOf(".")+
     471).toLowerCase();return(/(mp4|m4v|ogg|ogv|webm|webmv|flv|wmv|mpeg|mov)/gi.test(a)?"video":"audio")+"/"+this.getTypeFromExtension(a)},getTypeFromExtension:function(a){switch(a){case "mp4":case "m4v":return"mp4";case "webm":case "webma":case "webmv":return"webm";case "ogg":case "oga":case "ogv":return"ogg";default:return a}},createErrorMessage:function(a,b,c){var d=a.htmlMediaElement,e=document.createElement("div");e.className="me-cannotplay";try{e.style.width=d.width+"px";e.style.height=d.height+"px"}catch(g){}e.innerHTML=
     48c!==""?'<a href="'+a.url+'"><img src="'+c+'" width="100%" height="100%" /></a>':'<a href="'+a.url+'"><span>'+mejs.i18n.t("Download File")+"</span></a>";d.parentNode.insertBefore(e,d);d.style.display="none";b.error(d)},createPlugin:function(a,b,c,d,e,g){c=a.htmlMediaElement;var f=1,h=1,l="me_"+a.method+"_"+mejs.meIndex++,j=new mejs.PluginMediaElement(l,a.method,a.url),k=document.createElement("div"),m;j.tagName=c.tagName;for(m=0;m<c.attributes.length;m++){var n=c.attributes[m];n.specified==true&&j.setAttribute(n.name,
     49n.value)}for(m=c.parentNode;m!==null&&m.tagName.toLowerCase()!="body";){if(m.parentNode.tagName.toLowerCase()=="p"){m.parentNode.parentNode.insertBefore(m,m.parentNode);break}m=m.parentNode}if(a.isVideo){f=b.videoWidth>0?b.videoWidth:c.getAttribute("width")!==null?c.getAttribute("width"):b.defaultVideoWidth;h=b.videoHeight>0?b.videoHeight:c.getAttribute("height")!==null?c.getAttribute("height"):b.defaultVideoHeight;f=mejs.Utility.encodeUrl(f);h=mejs.Utility.encodeUrl(h)}else if(b.enablePluginDebug){f=
     50320;h=240}j.success=b.success;mejs.MediaPluginBridge.registerPluginElement(l,j,c);k.className="me-plugin";k.id=l+"_container";a.isVideo?c.parentNode.insertBefore(k,c):document.body.insertBefore(k,document.body.childNodes[0]);d=["id="+l,"isvideo="+(a.isVideo?"true":"false"),"autoplay="+(d?"true":"false"),"preload="+e,"width="+f,"startvolume="+b.startVolume,"timerrate="+b.timerRate,"flashstreamer="+b.flashStreamer,"height="+h,"pseudostreamstart="+b.pseudoStreamingStartQueryParam];if(a.url!==null)a.method==
     51"flash"?d.push("file="+mejs.Utility.encodeUrl(a.url)):d.push("file="+a.url);b.enablePluginDebug&&d.push("debug=true");b.enablePluginSmoothing&&d.push("smoothing=true");b.enablePseudoStreaming&&d.push("pseudostreaming=true");g&&d.push("controls=true");if(b.pluginVars)d=d.concat(b.pluginVars);switch(a.method){case "silverlight":k.innerHTML='<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="'+l+'" name="'+l+'" width="'+f+'" height="'+h+'" class="mejs-shim"><param name="initParams" value="'+
     52d.join(",")+'" /><param name="windowless" value="true" /><param name="background" value="black" /><param name="minRuntimeVersion" value="3.0.0.0" /><param name="autoUpgrade" value="true" /><param name="source" value="'+b.pluginPath+b.silverlightName+'" /></object>';break;case "flash":if(mejs.MediaFeatures.isIE){a=document.createElement("div");k.appendChild(a);a.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" id="'+
     53l+'" width="'+f+'" height="'+h+'" class="mejs-shim"><param name="movie" value="'+b.pluginPath+b.flashName+"?x="+new Date+'" /><param name="flashvars" value="'+d.join("&amp;")+'" /><param name="quality" value="high" /><param name="bgcolor" value="#000000" /><param name="wmode" value="transparent" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /></object>'}else k.innerHTML='<embed id="'+l+'" name="'+l+'" play="true" loop="false" quality="high" bgcolor="#000000" wmode="transparent" allowScriptAccess="always" allowFullScreen="true" type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" src="'+
     54b.pluginPath+b.flashName+'" flashvars="'+d.join("&")+'" width="'+f+'" height="'+h+'" class="mejs-shim"></embed>';break;case "youtube":b=a.url.substr(a.url.lastIndexOf("=")+1);youtubeSettings={container:k,containerId:k.id,pluginMediaElement:j,pluginId:l,videoId:b,height:h,width:f};mejs.PluginDetector.hasPluginVersion("flash",[10,0,0])?mejs.YouTubeApi.createFlash(youtubeSettings):mejs.YouTubeApi.enqueueIframe(youtubeSettings);break;case "vimeo":j.vimeoid=a.url.substr(a.url.lastIndexOf("/")+1);k.innerHTML=
     55'<iframe src="http://player.vimeo.com/video/'+j.vimeoid+'?portrait=0&byline=0&title=0" width="'+f+'" height="'+h+'" frameborder="0" class="mejs-shim"></iframe>'}c.style.display="none";return j},updateNative:function(a,b){var c=a.htmlMediaElement,d;for(d in mejs.HtmlMediaElement)c[d]=mejs.HtmlMediaElement[d];b.success(c,c);return c}};
     56mejs.YouTubeApi={isIframeStarted:false,isIframeLoaded:false,loadIframeApi:function(){if(!this.isIframeStarted){var a=document.createElement("script");a.src="http://www.youtube.com/player_api";var b=document.getElementsByTagName("script")[0];b.parentNode.insertBefore(a,b);this.isIframeStarted=true}},iframeQueue:[],enqueueIframe:function(a){if(this.isLoaded)this.createIframe(a);else{this.loadIframeApi();this.iframeQueue.push(a)}},createIframe:function(a){var b=a.pluginMediaElement,c=new YT.Player(a.containerId,
     57{height:a.height,width:a.width,videoId:a.videoId,playerVars:{controls:0},events:{onReady:function(){a.pluginMediaElement.pluginApi=c;mejs.MediaPluginBridge.initPlugin(a.pluginId);setInterval(function(){mejs.YouTubeApi.createEvent(c,b,"timeupdate")},250)},onStateChange:function(d){mejs.YouTubeApi.handleStateChange(d.data,c,b)}}})},createEvent:function(a,b,c){c={type:c,target:b};if(a&&a.getDuration){b.currentTime=c.currentTime=a.getCurrentTime();b.duration=c.duration=a.getDuration();c.paused=b.paused;
     58c.ended=b.ended;c.muted=a.isMuted();c.volume=a.getVolume()/100;c.bytesTotal=a.getVideoBytesTotal();c.bufferedBytes=a.getVideoBytesLoaded();var d=c.bufferedBytes/c.bytesTotal*c.duration;c.target.buffered=c.buffered={start:function(){return 0},end:function(){return d},length:1}}b.dispatchEvent(c.type,c)},iFrameReady:function(){for(this.isIframeLoaded=this.isLoaded=true;this.iframeQueue.length>0;)this.createIframe(this.iframeQueue.pop())},flashPlayers:{},createFlash:function(a){this.flashPlayers[a.pluginId]=
     59a;var b,c="http://www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid="+a.pluginId+"&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0";if(mejs.MediaFeatures.isIE){b=document.createElement("div");a.container.appendChild(b);b.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" id="'+a.pluginId+'" width="'+a.width+'" height="'+a.height+'" class="mejs-shim"><param name="movie" value="'+
     60c+'" /><param name="wmode" value="transparent" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /></object>'}else a.container.innerHTML='<object type="application/x-shockwave-flash" id="'+a.pluginId+'" data="'+c+'" width="'+a.width+'" height="'+a.height+'" style="visibility: visible; " class="mejs-shim"><param name="allowScriptAccess" value="always"><param name="wmode" value="transparent"></object>'},flashReady:function(a){var b=this.flashPlayers[a],c=
     61document.getElementById(a),d=b.pluginMediaElement;d.pluginApi=d.pluginElement=c;mejs.MediaPluginBridge.initPlugin(a);c.cueVideoById(b.videoId);a=b.containerId+"_callback";window[a]=function(e){mejs.YouTubeApi.handleStateChange(e,c,d)};c.addEventListener("onStateChange",a);setInterval(function(){mejs.YouTubeApi.createEvent(c,d,"timeupdate")},250)},handleStateChange:function(a,b,c){switch(a){case -1:c.paused=true;c.ended=true;mejs.YouTubeApi.createEvent(b,c,"loadedmetadata");break;case 0:c.paused=false;
     62c.ended=true;mejs.YouTubeApi.createEvent(b,c,"ended");break;case 1:c.paused=false;c.ended=false;mejs.YouTubeApi.createEvent(b,c,"play");mejs.YouTubeApi.createEvent(b,c,"playing");break;case 2:c.paused=true;c.ended=false;mejs.YouTubeApi.createEvent(b,c,"pause");break;case 3:mejs.YouTubeApi.createEvent(b,c,"progress")}}};function onYouTubePlayerAPIReady(){mejs.YouTubeApi.iFrameReady()}function onYouTubePlayerReady(a){mejs.YouTubeApi.flashReady(a)}window.mejs=mejs;window.MediaElement=mejs.MediaElement;
     63(function(a,b){var c={locale:{strings:{}},methods:{}};c.locale.getLanguage=function(){return{language:navigator.language}};c.locale.INIT_LANGUAGE=c.locale.getLanguage();c.methods.checkPlain=function(d){var e,g,f={"&":"&amp;",'"':"&quot;","<":"&lt;",">":"&gt;"};d=String(d);for(e in f)if(f.hasOwnProperty(e)){g=RegExp(e,"g");d=d.replace(g,f[e])}return d};c.methods.formatString=function(d,e){for(var g in e){switch(g.charAt(0)){case "@":e[g]=c.methods.checkPlain(e[g]);break;case "!":break;default:e[g]=
     64'<em class="placeholder">'+c.methods.checkPlain(e[g])+"</em>"}d=d.replace(g,e[g])}return d};c.methods.t=function(d,e,g){if(c.locale.strings&&c.locale.strings[g.context]&&c.locale.strings[g.context][d])d=c.locale.strings[g.context][d];if(e)d=c.methods.formatString(d,e);return d};c.t=function(d,e,g){if(typeof d==="string"&&d.length>0){var f=c.locale.getLanguage();g=g||{context:f.language};return c.methods.t(d,e,g)}else throw{name:"InvalidArgumentException",message:"First argument is either not a string or empty."};
     65};b.i18n=c})(document,mejs);(function(a){a.de={Fullscreen:"Vollbild","Go Fullscreen":"Vollbild an","Turn off Fullscreen":"Vollbild aus",Close:"Schlie\u00dfen"}})(mejs.i18n.locale.strings);(function(a){a.zh={Fullscreen:"\u5168\u87a2\u5e55","Go Fullscreen":"\u5168\u5c4f\u6a21\u5f0f","Turn off Fullscreen":"\u9000\u51fa\u5168\u5c4f\u6a21\u5f0f",Close:"\u95dc\u9589"}})(mejs.i18n.locale.strings);
    159366
    159467/*!
    1595  * Adds Internationalization and localization to objects.
    1596  *
    1597  * What is the concept beyond i18n?
    1598  *   http://en.wikipedia.org/wiki/Internationalization_and_localization
    1599  *
    1600  *
    1601  * This file both i18n methods and locale which is used to translate
    1602  * strings into other languages.
    1603  *
    1604  * Default translations are not available, you have to add them
    1605  * through locale objects which are named exactly as the langcode
    1606  * they stand for. The default language is always english (en).
     68 * MediaElementPlayer
     69 * http://mediaelementjs.com/
    160770 *
     71 * Creates a controller bar for HTML5 <video> add <audio> tags
     72 * using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
    160873 *
    1609  * Wrapper built to be able to attach the i18n object to
    1610  * other objects without changing more than one line.
     74 * Copyright 2010-2012, John Dyer (http://j.hn/)
     75 * License: MIT
    161176 *
    1612  *
    1613  * LICENSE:
    1614  *
    1615  *   The i18n file uses methods from the Drupal project (drupal.js):
    1616  *     - i18n.methods.t() (modified)
    1617  *     - i18n.methods.checkPlain() (full copy)
    1618  *     - i18n.methods.formatString() (full copy)
    1619  *
    1620  *   The Drupal project is (like mediaelementjs) licensed under GPLv2.
    1621  *    - http://drupal.org/licensing/faq/#q1
    1622  *    - https://github.com/johndyer/mediaelement
    1623  *    - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
    1624  *
    1625  *
    1626  * @author
    1627  *   Tim Latz (latz.tim@gmail.com)
    1628  *
    1629  * @see
    1630  *   me-i18n-locale.js
    1631  *
    1632  * @params
    1633  *  - $       - zepto || jQuery  ..
    1634  *  - context - document, iframe ..
    1635  *  - exports - CommonJS, window ..
    1636  *
    1637  */
    1638 ;(function($, context, exports, undefined) {
    1639     "use strict";
    1640     var i18n = {
    1641         "locale": {
    1642             "strings" : {}
    1643         },
    1644         "methods" : {}
    1645     };
    1646 // start i18n
    1647 
    1648 
    1649     /**
    1650      * Get the current browser's language
    1651      *
    1652      * @see: i18n.methods.t()
    1653      */
    1654     i18n.locale.getLanguage = function () {
    1655         return {
    1656             "language" : navigator.language
    1657         };
    1658     };
    1659 
    1660     /**
    1661      * Store the language the locale object was initialized with
    1662      */
    1663     i18n.locale.INIT_LANGUAGE = i18n.locale.getLanguage();
    1664 
    1665 
    1666     /**
    1667      * Encode special characters in a plain-text string for display as HTML.
    1668      */
    1669     i18n.methods.checkPlain = function (str) {
    1670         var character, regex,
    1671         replace = {
    1672             '&': '&amp;',
    1673             '"': '&quot;',
    1674             '<': '&lt;',
    1675             '>': '&gt;'
    1676         };
    1677         str = String(str);
    1678         for (character in replace) {
    1679             if (replace.hasOwnProperty(character)) {
    1680                 regex = new RegExp(character, 'g');
    1681                 str = str.replace(regex, replace[character]);
    1682             }
    1683         }
    1684         return str;
    1685     };
    1686 
    1687     /**
    1688      * Replace placeholders with sanitized values in a string.
    1689      *
    1690      * @param str
    1691      *   A string with placeholders.
    1692      * @param args
    1693      *   An object of replacements pairs to make. Incidences of any key in this
    1694      *   array are replaced with the corresponding value. Based on the first
    1695      *   character of the key, the value is escaped and/or themed:
    1696      *    - !variable: inserted as is
    1697      *    - @variable: escape plain text to HTML (i18n.methods.checkPlain)
    1698      *    - %variable: escape text and theme as a placeholder for user-submitted
    1699      *      content (checkPlain + <em class="placeholder" > )
    1700      *
    1701      * @see i18n.methods.t()
    1702      */
    1703     i18n.methods.formatString = function(str, args) {
    1704         // Transform arguments before inserting them.
    1705         for (var key in args) {
    1706             switch (key.charAt(0)) {
    1707                 // Escaped only.
    1708                 case '@':
    1709                     args[key] = i18n.methods.checkPlain(args[key]);
    1710                     break;
    1711                 // Pass-through.
    1712                 case '!':
    1713                     break;
    1714                 // Escaped and placeholder.
    1715                 case '%':
    1716                 default:
    1717                     args[key] = '<em class="placeholder">' + i18n.methods.checkPlain(args[key]) + '</em>';
    1718                     break;
    1719             }
    1720             str = str.replace(key, args[key]);
    1721         }
    1722         return str;
    1723     };
    1724 
    1725     /**
    1726      * Translate strings to the page language or a given language.
    1727      *
    1728      * See the documentation of the server-side t() function for further details.
    1729      *
    1730      * @param str
    1731      *   A string containing the English string to translate.
    1732      * @param args
    1733      *   An object of replacements pairs to make after translation. Incidences
    1734      *   of any key in this array are replaced with the corresponding value.
    1735      *   See i18n.methods.formatString().
    1736      *
    1737      * @param options
    1738      *   - 'context' (defaults to the default context): The context the source string
    1739      *     belongs to.
    1740      *
    1741      * @return
    1742      *   The translated string.
    1743      */
    1744     i18n.methods.t = function (str, args, options) {
    1745 
    1746         // Fetch the localized version of the string.
    1747         if (i18n.locale.strings && i18n.locale.strings[options.context] && i18n.locale.strings[options.context][str]) {
    1748             str = i18n.locale.strings[options.context][str];
    1749         }
    1750 
    1751         if (args) {
    1752             str = i18n.methods.formatString(str, args);
    1753         }
    1754         return str;
    1755     };
    1756 
    1757 
    1758     /**
    1759      * Wrapper for i18n.methods.t()
    1760      *
    1761      * @see i18n.methods.t()
    1762      * @throws InvalidArgumentException
    1763      */
    1764     i18n.t = function(str, args, options) {
    1765 
    1766         if (typeof str === 'string' && str.length > 0) {
    1767 
    1768             // check every time due languge can change for
    1769             // different reasons (translation, lang switcher ..)
    1770             var lang = i18n.locale.getLanguage();
    1771 
    1772             options = options || {
    1773                 "context" : lang.language
    1774             };
    1775 
    1776             return i18n.methods.t(str, args, options);
    1777         }
    1778         else {
    1779             throw {
    1780                 "name" : 'InvalidArgumentException',
    1781                 "message" : 'First argument is either not a string or empty.'
    1782             }
    1783         }
    1784     };
    1785 
    1786 // end i18n
    1787     exports.i18n = i18n;
    1788 }(jQuery, document, mejs));
    1789 /*!
    1790  * This is a i18n.locale language object.
    1791  *
    1792  *<de> German translation by Tim Latz, latz.tim@gmail.com
    1793  *
    1794  * @author
    1795  *   Tim Latz (latz.tim@gmail.com)
    1796  *
    1797  * @see
    1798  *   me-i18n.js
    1799  *
    1800  * @params
    1801  *  - exports - CommonJS, window ..
    1802  */
    1803 ;(function(exports, undefined) {
    1804 
    1805     "use strict";
    1806 
    1807     exports.de = {
    1808         "Fullscreen" : "Vollbild",
    1809         "Go Fullscreen" : "Vollbild an",
    1810         "Turn off Fullscreen" : "Vollbild aus",
    1811         "Close" : "Schließen"
    1812     };
    1813 
    1814 }(mejs.i18n.locale.strings));
    1815 
    1816 /*!
    1817  * MediaElementPlayer
    1818  * http://mediaelementjs.com/
    1819  *
    1820  * Creates a controller bar for HTML5 <video> add <audio> tags
    1821  * using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
    1822  *
    1823  * Copyright 2010-2012, John Dyer (http://j.hn/)
    1824  * License: MIT
    1825  *
    1826  */
    1827 if (typeof jQuery != 'undefined') {
    1828         mejs.$ = jQuery;
    1829 } else if (typeof ender != 'undefined') {
    1830         mejs.$ = ender;
    1831 }
    1832 (function ($) {
    1833 
    1834         // default player values
    1835         mejs.MepDefaults = {
    1836                 // url to poster (to fix iOS 3.x)
    1837                 poster: '',
    1838                 // default if the <video width> is not specified
    1839                 defaultVideoWidth: 480,
    1840                 // default if the <video height> is not specified
    1841                 defaultVideoHeight: 270,
    1842                 // if set, overrides <video width>
    1843                 videoWidth: -1,
    1844                 // if set, overrides <video height>
    1845                 videoHeight: -1,
    1846                 // default if the user doesn't specify
    1847                 defaultAudioWidth: 400,
    1848                 // default if the user doesn't specify
    1849                 defaultAudioHeight: 30,
    1850 
    1851                 // default amount to move back when back key is pressed
    1852                 defaultSeekBackwardInterval: function(media) {
    1853                         return (media.duration * 0.05);
    1854                 },
    1855                 // default amount to move forward when forward key is pressed
    1856                 defaultSeekForwardInterval: function(media) {
    1857                         return (media.duration * 0.05);
    1858                 },
    1859 
    1860                 // width of audio player
    1861                 audioWidth: -1,
    1862                 // height of audio player
    1863                 audioHeight: -1,
    1864                 // initial volume when the player starts (overrided by user cookie)
    1865                 startVolume: 0.8,
    1866                 // useful for <audio> player loops
    1867                 loop: false,
    1868                 // rewind to beginning when media ends
    1869                 autoRewind: true,
    1870                 // resize to media dimensions
    1871                 enableAutosize: true,
    1872                 // forces the hour marker (##:00:00)
    1873                 alwaysShowHours: false,
    1874 
    1875                 // show framecount in timecode (##:00:00:00)
    1876                 showTimecodeFrameCount: false,
    1877                 // used when showTimecodeFrameCount is set to true
    1878                 framesPerSecond: 25,
    1879 
    1880                 // automatically calculate the width of the progress bar based on the sizes of other elements
    1881                 autosizeProgress : true,
    1882                 // Hide controls when playing and mouse is not over the video
    1883                 alwaysShowControls: false,
    1884                 // Display the video control
    1885                 hideVideoControlsOnLoad: false,
    1886         // Enable click video element to toggle play/pause
    1887         clickToPlayPause: true,
    1888                 // force iPad's native controls
    1889                 iPadUseNativeControls: false,
    1890                 // force iPhone's native controls
    1891                 iPhoneUseNativeControls: false,
    1892                 // force Android's native controls
    1893                 AndroidUseNativeControls: false,
    1894                 // features to show
    1895                 features: ['playpause','current','progress','duration','tracks','volume','fullscreen'],
    1896                 // only for dynamic
    1897                 isVideo: true,
    1898 
    1899                 // turns keyboard support on and off for this instance
    1900                 enableKeyboard: true,
    1901 
    1902                 // whenthis player starts, it will pause other players
    1903                 pauseOtherPlayers: true,
    1904 
    1905                 // array of keyboard actions such as play pause
    1906                 keyActions: [
    1907                                 {
    1908                                                 keys: [
    1909                                                                 32, // SPACE
    1910                                                                 179 // GOOGLE play/pause button
    1911                                                           ],
    1912                                                 action: function(player, media) {
    1913                                                                 if (media.paused || media.ended) {
    1914                                                                                 media.play();
    1915                                                                 } else {
    1916                                                                                 media.pause();
    1917                                                                 }
    1918                                                 }
    1919                                 },
    1920                                 {
    1921                                                 keys: [38], // UP
    1922                                                 action: function(player, media) {
    1923                                                                 var newVolume = Math.min(media.volume + 0.1, 1);
    1924                                                                 media.setVolume(newVolume);
    1925                                                 }
    1926                                 },
    1927                                 {
    1928                                                 keys: [40], // DOWN
    1929                                                 action: function(player, media) {
    1930                                                                 var newVolume = Math.max(media.volume - 0.1, 0);
    1931                                                                 media.setVolume(newVolume);
    1932                                                 }
    1933                                 },
    1934                                 {
    1935                                                 keys: [
    1936                                                                 37, // LEFT
    1937                                                                 227 // Google TV rewind
    1938                                                 ],
    1939                                                 action: function(player, media) {
    1940                                                                 if (!isNaN(media.duration) && media.duration > 0) {
    1941                                                                                 if (player.isVideo) {
    1942                                                                                                 player.showControls();
    1943                                                                                                 player.startControlsTimer();
    1944                                                                                 }
    1945 
    1946                                                                                 // 5%
    1947                                                                                 var newTime = Math.max(media.currentTime - player.options.defaultSeekBackwardInterval(media), 0);
    1948                                                                                 media.setCurrentTime(newTime);
    1949                                                                 }
    1950                                                 }
    1951                                 },
    1952                                 {
    1953                                                 keys: [
    1954                                                                 39, // RIGHT
    1955                                                                 228 // Google TV forward
    1956                                                 ],
    1957                                                 action: function(player, media) {
    1958                                                                 if (!isNaN(media.duration) && media.duration > 0) {
    1959                                                                                 if (player.isVideo) {
    1960                                                                                                 player.showControls();
    1961                                                                                                 player.startControlsTimer();
    1962                                                                                 }
    1963 
    1964                                                                                 // 5%
    1965                                                                                 var newTime = Math.min(media.currentTime + player.options.defaultSeekForwardInterval(media), media.duration);
    1966                                                                                 media.setCurrentTime(newTime);
    1967                                                                 }
    1968                                                 }
    1969                                 },
    1970                                 {
    1971                                                 keys: [70], // f
    1972                                                 action: function(player, media) {
    1973                                                                 if (typeof player.enterFullScreen != 'undefined') {
    1974                                                                                 if (player.isFullScreen) {
    1975                                                                                                 player.exitFullScreen();
    1976                                                                                 } else {
    1977                                                                                                 player.enterFullScreen();
    1978                                                                                 }
    1979                                                                 }
    1980                                                 }
    1981                                 }
    1982                 ]
    1983         };
    1984 
    1985         mejs.mepIndex = 0;
    1986 
    1987         mejs.players = {};
    1988 
    1989         // wraps a MediaElement object in player controls
    1990         mejs.MediaElementPlayer = function(node, o) {
    1991                 // enforce object, even without "new" (via John Resig)
    1992                 if ( !(this instanceof mejs.MediaElementPlayer) ) {
    1993                         return new mejs.MediaElementPlayer(node, o);
    1994                 }
    1995 
    1996                 var t = this;
    1997 
    1998                 // these will be reset after the MediaElement.success fires
    1999                 t.$media = t.$node = $(node);
    2000                 t.node = t.media = t.$media[0];
    2001 
    2002                 // check for existing player
    2003                 if (typeof t.node.player != 'undefined') {
    2004                         return t.node.player;
    2005                 } else {
    2006                         // attach player to DOM node for reference
    2007                         t.node.player = t;
    2008                 }
    2009 
    2010 
    2011                 // try to get options from data-mejsoptions
    2012                 if (typeof o == 'undefined') {
    2013                         o = t.$node.data('mejsoptions');
    2014                 }
    2015 
    2016                 // extend default options
    2017                 t.options = $.extend({},mejs.MepDefaults,o);
    2018 
    2019                 // unique ID
    2020                 t.id = 'mep_' + mejs.mepIndex++;
    2021 
    2022                 // add to player array (for focus events)
    2023                 mejs.players[t.id] = t;
    2024 
    2025                 // start up
    2026                 t.init();
    2027 
    2028                 return t;
    2029         };
    2030 
    2031         // actual player
    2032         mejs.MediaElementPlayer.prototype = {
    2033 
    2034                 hasFocus: false,
    2035 
    2036                 controlsAreVisible: true,
    2037 
    2038                 init: function() {
    2039 
    2040                         var
    2041                                 t = this,
    2042                                 mf = mejs.MediaFeatures,
    2043                                 // options for MediaElement (shim)
    2044                                 meOptions = $.extend(true, {}, t.options, {
    2045                                         success: function(media, domNode) { t.meReady(media, domNode); },
    2046                                         error: function(e) { t.handleError(e);}
    2047                                 }),
    2048                                 tagName = t.media.tagName.toLowerCase();
    2049 
    2050                         t.isDynamic = (tagName !== 'audio' && tagName !== 'video');
    2051 
    2052                         if (t.isDynamic) {
    2053                                 // get video from src or href?
    2054                                 t.isVideo = t.options.isVideo;
    2055                         } else {
    2056                                 t.isVideo = (tagName !== 'audio' && t.options.isVideo);
    2057                         }
    2058 
    2059                         // use native controls in iPad, iPhone, and Android
    2060                         if ((mf.isiPad && t.options.iPadUseNativeControls) || (mf.isiPhone && t.options.iPhoneUseNativeControls)) {
    2061 
    2062                                 // add controls and stop
    2063                                 t.$media.attr('controls', 'controls');
    2064 
    2065                                 // attempt to fix iOS 3 bug
    2066                                 //t.$media.removeAttr('poster');
    2067                                 // no Issue found on iOS3 -ttroxell
    2068 
    2069                                 // override Apple's autoplay override for iPads
    2070                                 if (mf.isiPad && t.media.getAttribute('autoplay') !== null) {
    2071                                         t.media.load();
    2072                                         t.media.play();
    2073                                 }
    2074 
    2075                         } else if (mf.isAndroid && t.options.AndroidUseNativeControls) {
    2076 
    2077                                 // leave default player
    2078 
    2079                         } else {
    2080 
    2081                                 // DESKTOP: use MediaElementPlayer controls
    2082 
    2083                                 // remove native controls
    2084                                 t.$media.removeAttr('controls');
    2085 
    2086                                 // build container
    2087                                 t.container =
    2088                                         $('<div id="' + t.id + '" class="mejs-container ' + (mejs.MediaFeatures.svg ? 'svg' : 'no-svg') + '">'+
    2089                                                 '<div class="mejs-inner">'+
    2090                                                         '<div class="mejs-mediaelement"></div>'+
    2091                                                         '<div class="mejs-layers"></div>'+
    2092                                                         '<div class="mejs-controls"></div>'+
    2093                                                         '<div class="mejs-clear"></div>'+
    2094                                                 '</div>' +
    2095                                         '</div>')
    2096                                         .addClass(t.$media[0].className)
    2097                                         .insertBefore(t.$media);
    2098 
    2099                                 // add classes for user and content
    2100                                 t.container.addClass(
    2101                                         (mf.isAndroid ? 'mejs-android ' : '') +
    2102                                         (mf.isiOS ? 'mejs-ios ' : '') +
    2103                                         (mf.isiPad ? 'mejs-ipad ' : '') +
    2104                                         (mf.isiPhone ? 'mejs-iphone ' : '') +
    2105                                         (t.isVideo ? 'mejs-video ' : 'mejs-audio ')
    2106                                 );
    2107 
    2108 
    2109                                 // move the <video/video> tag into the right spot
    2110                                 if (mf.isiOS) {
    2111 
    2112                                         // sadly, you can't move nodes in iOS, so we have to destroy and recreate it!
    2113                                         var $newMedia = t.$media.clone();
    2114 
    2115                                         t.container.find('.mejs-mediaelement').append($newMedia);
    2116 
    2117                                         t.$media.remove();
    2118                                         t.$node = t.$media = $newMedia;
    2119                                         t.node = t.media = $newMedia[0]
    2120 
    2121                                 } else {
    2122 
    2123                                         // normal way of moving it into place (doesn't work on iOS)
    2124                                         t.container.find('.mejs-mediaelement').append(t.$media);
    2125                                 }
    2126 
    2127                                 // find parts
    2128                                 t.controls = t.container.find('.mejs-controls');
    2129                                 t.layers = t.container.find('.mejs-layers');
    2130 
    2131                                 // determine the size
    2132 
    2133                                 /* size priority:
    2134                                         (1) videoWidth (forced),
    2135                                         (2) style="width;height;"
    2136                                         (3) width attribute,
    2137                                         (4) defaultVideoWidth (for unspecified cases)
    2138                                 */
    2139 
    2140                                 var tagType = (t.isVideo ? 'video' : 'audio'),
    2141                                         capsTagName = tagType.substring(0,1).toUpperCase() + tagType.substring(1);
    2142 
    2143 
    2144                                 if (t.options[tagType + 'Width'] > 0 || t.options[tagType + 'Width'].toString().indexOf('%') > -1) {
    2145                                         t.width = t.options[tagType + 'Width'];
    2146                                 } else if (t.media.style.width !== '' && t.media.style.width !== null) {
    2147                                         t.width = t.media.style.width;
    2148                                 } else if (t.media.getAttribute('width') !== null) {
    2149                                         t.width = t.$media.attr('width');
    2150                                 } else {
    2151                                         t.width = t.options['default' + capsTagName + 'Width'];
    2152                                 }
    2153 
    2154                                 if (t.options[tagType + 'Height'] > 0 || t.options[tagType + 'Height'].toString().indexOf('%') > -1) {
    2155                                         t.height = t.options[tagType + 'Height'];
    2156                                 } else if (t.media.style.height !== '' && t.media.style.height !== null) {
    2157                                         t.height = t.media.style.height;
    2158                                 } else if (t.$media[0].getAttribute('height') !== null) {
    2159                                         t.height = t.$media.attr('height');
    2160                                 } else {
    2161                                         t.height = t.options['default' + capsTagName + 'Height'];
    2162                                 }
    2163 
    2164                                 // set the size, while we wait for the plugins to load below
    2165                                 t.setPlayerSize(t.width, t.height);
    2166 
    2167                                 // create MediaElementShim
    2168                                 meOptions.pluginWidth = t.height;
    2169                                 meOptions.pluginHeight = t.width;
    2170                         }
    2171 
    2172 
    2173 
    2174                         // create MediaElement shim
    2175                         mejs.MediaElement(t.$media[0], meOptions);
    2176 
    2177                         // controls are shown when loaded
    2178                         t.container.trigger('controlsshown');
    2179                 },
    2180 
    2181                 showControls: function(doAnimation) {
    2182                         var t = this;
    2183 
    2184                         doAnimation = typeof doAnimation == 'undefined' || doAnimation;
    2185 
    2186                         if (t.controlsAreVisible)
    2187                                 return;
    2188 
    2189                         if (doAnimation) {
    2190                                 t.controls
    2191                                         .css('visibility','visible')
    2192                                         .stop(true, true).fadeIn(200, function() {
    2193                                               t.controlsAreVisible = true;
    2194                                               t.container.trigger('controlsshown');
    2195                                         });
    2196 
    2197                                 // any additional controls people might add and want to hide
    2198                                 t.container.find('.mejs-control')
    2199                                         .css('visibility','visible')
    2200                                         .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
    2201 
    2202                         } else {
    2203                                 t.controls
    2204                                         .css('visibility','visible')
    2205                                         .css('display','block');
    2206 
    2207                                 // any additional controls people might add and want to hide
    2208                                 t.container.find('.mejs-control')
    2209                                         .css('visibility','visible')
    2210                                         .css('display','block');
    2211 
    2212                                 t.controlsAreVisible = true;
    2213                                 t.container.trigger('controlsshown');
    2214                         }
    2215 
    2216                         t.setControlsSize();
    2217 
    2218                 },
    2219 
    2220                 hideControls: function(doAnimation) {
    2221                         var t = this;
    2222 
    2223                         doAnimation = typeof doAnimation == 'undefined' || doAnimation;
    2224 
    2225                         if (!t.controlsAreVisible)
    2226                                 return;
    2227 
    2228                         if (doAnimation) {
    2229                                 // fade out main controls
    2230                                 t.controls.stop(true, true).fadeOut(200, function() {
    2231                                         $(this)
    2232                                                 .css('visibility','hidden')
    2233                                                 .css('display','block');
    2234 
    2235                                         t.controlsAreVisible = false;
    2236                                         t.container.trigger('controlshidden');
    2237                                 });
    2238 
    2239                                 // any additional controls people might add and want to hide
    2240                                 t.container.find('.mejs-control').stop(true, true).fadeOut(200, function() {
    2241                                         $(this)
    2242                                                 .css('visibility','hidden')
    2243                                                 .css('display','block');
    2244                                 });
    2245                         } else {
    2246 
    2247                                 // hide main controls
    2248                                 t.controls
    2249                                         .css('visibility','hidden')
    2250                                         .css('display','block');
    2251 
    2252                                 // hide others
    2253                                 t.container.find('.mejs-control')
    2254                                         .css('visibility','hidden')
    2255                                         .css('display','block');
    2256 
    2257                                 t.controlsAreVisible = false;
    2258                                 t.container.trigger('controlshidden');
    2259                         }
    2260                 },
    2261 
    2262                 controlsTimer: null,
    2263 
    2264                 startControlsTimer: function(timeout) {
    2265 
    2266                         var t = this;
    2267 
    2268                         timeout = typeof timeout != 'undefined' ? timeout : 1500;
    2269 
    2270                         t.killControlsTimer('start');
    2271 
    2272                         t.controlsTimer = setTimeout(function() {
    2273                                 //console.log('timer fired');
    2274                                 t.hideControls();
    2275                                 t.killControlsTimer('hide');
    2276                         }, timeout);
    2277                 },
    2278 
    2279                 killControlsTimer: function(src) {
    2280 
    2281                         var t = this;
    2282 
    2283                         if (t.controlsTimer !== null) {
    2284                                 clearTimeout(t.controlsTimer);
    2285                                 delete t.controlsTimer;
    2286                                 t.controlsTimer = null;
    2287                         }
    2288                 },
    2289 
    2290                 controlsEnabled: true,
    2291 
    2292                 disableControls: function() {
    2293                         var t= this;
    2294 
    2295                         t.killControlsTimer();
    2296                         t.hideControls(false);
    2297                         this.controlsEnabled = false;
    2298                 },
    2299 
    2300                 enableControls: function() {
    2301                         var t= this;
    2302 
    2303                         t.showControls(false);
    2304 
    2305                         t.controlsEnabled = true;
    2306                 },
    2307 
    2308 
    2309                 // Sets up all controls and events
    2310                 meReady: function(media, domNode) {
    2311 
    2312 
    2313                         var t = this,
    2314                                 mf = mejs.MediaFeatures,
    2315                                 autoplayAttr = domNode.getAttribute('autoplay'),
    2316                                 autoplay = !(typeof autoplayAttr == 'undefined' || autoplayAttr === null || autoplayAttr === 'false'),
    2317                                 featureIndex,
    2318                                 feature;
    2319 
    2320                         // make sure it can't create itself again if a plugin reloads
    2321                         if (t.created)
    2322                                 return;
    2323                         else
    2324                                 t.created = true;
    2325 
    2326                         t.media = media;
    2327                         t.domNode = domNode;
    2328 
    2329                         if (!(mf.isAndroid && t.options.AndroidUseNativeControls) && !(mf.isiPad && t.options.iPadUseNativeControls) && !(mf.isiPhone && t.options.iPhoneUseNativeControls)) {
    2330 
    2331                                 // two built in features
    2332                                 t.buildposter(t, t.controls, t.layers, t.media);
    2333                                 t.buildkeyboard(t, t.controls, t.layers, t.media);
    2334                                 t.buildoverlays(t, t.controls, t.layers, t.media);
    2335 
    2336                                 // grab for use by features
    2337                                 t.findTracks();
    2338 
    2339                                 // add user-defined features/controls
    2340                                 for (featureIndex in t.options.features) {
    2341                                         feature = t.options.features[featureIndex];
    2342                                         if (t['build' + feature]) {
    2343                                                 try {
    2344                                                         t['build' + feature](t, t.controls, t.layers, t.media);
    2345                                                 } catch (e) {
    2346                                                         // TODO: report control error
    2347                                                         //throw e;
    2348                                                         //console.log('error building ' + feature);
    2349                                                         //console.log(e);
    2350                                                 }
    2351                                         }
    2352                                 }
    2353 
    2354                                 t.container.trigger('controlsready');
    2355 
    2356                                 // reset all layers and controls
    2357                                 t.setPlayerSize(t.width, t.height);
    2358                                 t.setControlsSize();
    2359 
    2360 
    2361                                 // controls fade
    2362                                 if (t.isVideo) {
    2363 
    2364                                         if (mejs.MediaFeatures.hasTouch) {
    2365 
    2366                                                 // for touch devices (iOS, Android)
    2367                                                 // show/hide without animation on touch
    2368 
    2369                                                 t.$media.bind('touchstart', function() {
    2370 
    2371 
    2372                                                         // toggle controls
    2373                                                         if (t.controlsAreVisible) {
    2374                                                                 t.hideControls(false);
    2375                                                         } else {
    2376                                                                 if (t.controlsEnabled) {
    2377                                                                         t.showControls(false);
    2378                                                                 }
    2379                                                         }
    2380                                                 });
    2381 
    2382                                         } else {
    2383             // click to play/pause
    2384             t.media.addEventListener('click', function() {
    2385               if (t.options.clickToPlayPause) {
    2386                   if (t.media.paused) {
    2387                     t.media.play();
    2388                   } else {
    2389                     t.media.pause();
    2390                   }
    2391               }
    2392             });
    2393 
    2394                                                 // show/hide controls
    2395                                                 t.container
    2396                                                         .bind('mouseenter mouseover', function () {
    2397                                                                 if (t.controlsEnabled) {
    2398                                                                         if (!t.options.alwaysShowControls) {
    2399                                                                                 t.killControlsTimer('enter');
    2400                                                                                 t.showControls();
    2401                                                                                 t.startControlsTimer(2500);
    2402                                                                         }
    2403                                                                 }
    2404                                                         })
    2405                                                         .bind('mousemove', function() {
    2406                                                                 if (t.controlsEnabled) {
    2407                                                                         if (!t.controlsAreVisible) {
    2408                                                                                 t.showControls();
    2409                                                                         }
    2410                                                                         //t.killControlsTimer('move');
    2411                                                                         if (!t.options.alwaysShowControls) {
    2412                                                                                 t.startControlsTimer(2500);
    2413                                                                         }
    2414                                                                 }
    2415                                                         })
    2416                                                         .bind('mouseleave', function () {
    2417                                                                 if (t.controlsEnabled) {
    2418                                                                         if (!t.media.paused && !t.options.alwaysShowControls) {
    2419                                                                                 t.startControlsTimer(1000);
    2420                                                                         }
    2421                                                                 }
    2422                                                         });
    2423                                         }
    2424 
    2425                                         if(t.options.hideVideoControlsOnLoad) {
    2426                                                 t.hideControls(false);
    2427                                         }
    2428 
    2429                                         // check for autoplay
    2430                                         if (autoplay && !t.options.alwaysShowControls) {
    2431                                                 t.hideControls();
    2432                                         }
    2433 
    2434                                         // resizer
    2435                                         if (t.options.enableAutosize) {
    2436                                                 t.media.addEventListener('loadedmetadata', function(e) {
    2437                                                         // if the <video height> was not set and the options.videoHeight was not set
    2438                                                         // then resize to the real dimensions
    2439                                                         if (t.options.videoHeight <= 0 && t.domNode.getAttribute('height') === null && !isNaN(e.target.videoHeight)) {
    2440                                                                 t.setPlayerSize(e.target.videoWidth, e.target.videoHeight);
    2441                                                                 t.setControlsSize();
    2442                                                                 t.media.setVideoSize(e.target.videoWidth, e.target.videoHeight);
    2443                                                         }
    2444                                                 }, false);
    2445                                         }
    2446                                 }
    2447 
    2448                                 // EVENTS
    2449 
    2450                                 // FOCUS: when a video starts playing, it takes focus from other players (possibily pausing them)
    2451                                 media.addEventListener('play', function() {
    2452                                                 var playerIndex;
    2453 
    2454                                                 // go through all other players
    2455                                                 for (playerIndex in mejs.players) {
    2456                                                         var p = mejs.players[playerIndex];
    2457                                                         if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {
    2458                                                                 p.pause();
    2459                                                         }
    2460                                                         p.hasFocus = false;
    2461                                                 }
    2462 
    2463                                                 t.hasFocus = true;
    2464                                 },false);
    2465 
    2466 
    2467                                 // ended for all
    2468                                 t.media.addEventListener('ended', function (e) {
    2469                                         if(t.options.autoRewind) {
    2470                                                 try{
    2471                                                         t.media.setCurrentTime(0);
    2472                                                 } catch (exp) {
    2473 
    2474                                                 }
    2475                                         }
    2476                                         t.media.pause();
    2477 
    2478                                         if (t.setProgressRail)
    2479                                                 t.setProgressRail();
    2480                                         if (t.setCurrentRail)
    2481                                                 t.setCurrentRail();
    2482 
    2483                                         if (t.options.loop) {
    2484                                                 t.media.play();
    2485                                         } else if (!t.options.alwaysShowControls && t.controlsEnabled) {
    2486                                                 t.showControls();
    2487                                         }
    2488                                 }, false);
    2489 
    2490                                 // resize on the first play
    2491                                 t.media.addEventListener('loadedmetadata', function(e) {
    2492                                         if (t.updateDuration) {
    2493                                                 t.updateDuration();
    2494                                         }
    2495                                         if (t.updateCurrent) {
    2496                                                 t.updateCurrent();
    2497                                         }
    2498 
    2499                                         if (!t.isFullScreen) {
    2500                                                 t.setPlayerSize(t.width, t.height);
    2501                                                 t.setControlsSize();
    2502                                         }
    2503                                 }, false);
    2504 
    2505 
    2506                                 // webkit has trouble doing this without a delay
    2507                                 setTimeout(function () {
    2508                                         t.setPlayerSize(t.width, t.height);
    2509                                         t.setControlsSize();
    2510                                 }, 50);
    2511 
    2512                                 // adjust controls whenever window sizes (used to be in fullscreen only)
    2513                                 t.globalBind('resize', function() {
    2514 
    2515                                         // don't resize for fullscreen mode
    2516                                         if ( !(t.isFullScreen || (mejs.MediaFeatures.hasTrueNativeFullScreen && document.webkitIsFullScreen)) ) {
    2517                                                 t.setPlayerSize(t.width, t.height);
    2518                                         }
    2519 
    2520                                         // always adjust controls
    2521                                         t.setControlsSize();
    2522                                 });
    2523 
    2524                                 // TEMP: needs to be moved somewhere else
    2525                                 if (t.media.pluginType == 'youtube') {
    2526                                         t.container.find('.mejs-overlay-play').hide();
    2527                                 }
    2528                         }
    2529 
    2530                         // force autoplay for HTML5
    2531                         if (autoplay && media.pluginType == 'native') {
    2532                                 media.load();
    2533                                 media.play();
    2534                         }
    2535 
    2536 
    2537                         if (t.options.success) {
    2538 
    2539                                 if (typeof t.options.success == 'string') {
    2540                                                 window[t.options.success](t.media, t.domNode, t);
    2541                                 } else {
    2542                                                 t.options.success(t.media, t.domNode, t);
    2543                                 }
    2544                         }
    2545                 },
    2546 
    2547                 handleError: function(e) {
    2548                         var t = this;
    2549 
    2550                         t.controls.hide();
    2551 
    2552                         // Tell user that the file cannot be played
    2553                         if (t.options.error) {
    2554                                 t.options.error(e);
    2555                         }
    2556                 },
    2557 
    2558                 setPlayerSize: function(width,height) {
    2559                         var t = this;
    2560 
    2561                         if (typeof width != 'undefined')
    2562                                 t.width = width;
    2563 
    2564                         if (typeof height != 'undefined')
    2565                                 t.height = height;
    2566 
    2567       // detect 100% mode - use currentStyle for IE since css() doesn't return percentages
    2568       if (t.height.toString().indexOf('%') > 0 || t.$node.css('max-width') === '100%' || (t.$node[0].currentStyle && t.$node[0].currentStyle.maxWidth === '100%')) {
    2569 
    2570                                 // do we have the native dimensions yet?
    2571                                 var
    2572                                         nativeWidth = t.isVideo ? ((t.media.videoWidth && t.media.videoWidth > 0) ? t.media.videoWidth : t.options.defaultVideoWidth) : t.options.defaultAudioWidth,
    2573                                         nativeHeight = t.isVideo ? ((t.media.videoHeight && t.media.videoHeight > 0) ? t.media.videoHeight : t.options.defaultVideoHeight) : t.options.defaultAudioHeight,
    2574                                         parentWidth = t.container.parent().closest(':visible').width(),
    2575                                         newHeight = t.isVideo || !t.options.autosizeProgress ? parseInt(parentWidth * nativeHeight/nativeWidth, 10) : nativeHeight;
    2576 
    2577                                 if (t.container.parent()[0].tagName.toLowerCase() === 'body') { // && t.container.siblings().count == 0) {
    2578                                         parentWidth = $(window).width();
    2579                                         newHeight = $(window).height();
    2580                                 }
    2581 
    2582                                 if ( newHeight != 0 && parentWidth != 0 ) {
    2583                                         // set outer container size
    2584                                         t.container
    2585                                                 .width(parentWidth)
    2586                                                 .height(newHeight);
    2587 
    2588                                         // set native <video> or <audio> and shims
    2589                                         t.$media.add(t.container.find('.mejs-shim'))
    2590                                                 .width('100%')
    2591                                                 .height('100%');
    2592 
    2593                                         // if shim is ready, send the size to the embeded plugin
    2594                                         if (t.isVideo) {
    2595                                                 if (t.media.setVideoSize) {
    2596                                                         t.media.setVideoSize(parentWidth, newHeight);
    2597                                                 }
    2598                                         }
    2599 
    2600                                         // set the layers
    2601                                         t.layers.children('.mejs-layer')
    2602                                                 .width('100%')
    2603                                                 .height('100%');
    2604                                 }
    2605 
    2606 
    2607                         } else {
    2608 
    2609                                 t.container
    2610                                         .width(t.width)
    2611                                         .height(t.height);
    2612 
    2613                                 t.layers.children('.mejs-layer')
    2614                                         .width(t.width)
    2615                                         .height(t.height);
    2616 
    2617                         }
    2618                 },
    2619 
    2620                 setControlsSize: function() {
    2621                         var t = this,
    2622                                 usedWidth = 0,
    2623                                 railWidth = 0,
    2624                                 rail = t.controls.find('.mejs-time-rail'),
    2625                                 total = t.controls.find('.mejs-time-total'),
    2626                                 current = t.controls.find('.mejs-time-current'),
    2627                                 loaded = t.controls.find('.mejs-time-loaded'),
    2628                                 others = rail.siblings();
    2629 
    2630 
    2631                         // allow the size to come from custom CSS
    2632                         if (t.options && !t.options.autosizeProgress) {
    2633                                 // Also, frontends devs can be more flexible
    2634                                 // due the opportunity of absolute positioning.
    2635                                 railWidth = parseInt(rail.css('width'));
    2636                         }
    2637 
    2638                         // attempt to autosize
    2639                         if (railWidth === 0 || !railWidth) {
    2640 
    2641                                 // find the size of all the other controls besides the rail
    2642                                 others.each(function() {
    2643                                         var $this = $(this);
    2644                                         if ($this.css('position') != 'absolute' && $this.is(':visible')) {
    2645                                                 usedWidth += $(this).outerWidth(true);
    2646                                         }
    2647                                 });
    2648 
    2649                                 // fit the rail into the remaining space
    2650                                 railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.width());
    2651                         }
    2652 
    2653                         // outer area
    2654                         rail.width(railWidth);
    2655                         // dark space
    2656                         total.width(railWidth - (total.outerWidth(true) - total.width()));
    2657 
    2658                         if (t.setProgressRail)
    2659                                 t.setProgressRail();
    2660                         if (t.setCurrentRail)
    2661                                 t.setCurrentRail();
    2662                 },
    2663 
    2664 
    2665                 buildposter: function(player, controls, layers, media) {
    2666                         var t = this,
    2667                                 poster =
    2668                                 $('<div class="mejs-poster mejs-layer">' +
    2669                                 '</div>')
    2670                                         .appendTo(layers),
    2671                                 posterUrl = player.$media.attr('poster');
    2672 
    2673                         // prioriy goes to option (this is useful if you need to support iOS 3.x (iOS completely fails with poster)
    2674                         if (player.options.poster !== '') {
    2675                                 posterUrl = player.options.poster;
    2676                         }
    2677 
    2678                         // second, try the real poster
    2679                         if (posterUrl !== '' && posterUrl != null) {
    2680                                 t.setPoster(posterUrl);
    2681                         } else {
    2682                                 poster.hide();
    2683                         }
    2684 
    2685                         media.addEventListener('play',function() {
    2686                                 poster.hide();
    2687                         }, false);
    2688                 },
    2689 
    2690                 setPoster: function(url) {
    2691                         var t = this,
    2692                                 posterDiv = t.container.find('.mejs-poster'),
    2693                                 posterImg = posterDiv.find('img');
    2694 
    2695                         if (posterImg.length == 0) {
    2696                                 posterImg = $('<img width="100%" height="100%" />').appendTo(posterDiv);
    2697                         }
    2698 
    2699                         posterImg.attr('src', url);
    2700                 },
    2701 
    2702                 buildoverlays: function(player, controls, layers, media) {
    2703             var t = this;
    2704                         if (!player.isVideo)
    2705                                 return;
    2706 
    2707                         var
    2708                         loading =
    2709                                 $('<div class="mejs-overlay mejs-layer">'+
    2710                                         '<div class="mejs-overlay-loading"><span></span></div>'+
    2711                                 '</div>')
    2712                                 .hide() // start out hidden
    2713                                 .appendTo(layers),
    2714                         error =
    2715                                 $('<div class="mejs-overlay mejs-layer">'+
    2716                                         '<div class="mejs-overlay-error"></div>'+
    2717                                 '</div>')
    2718                                 .hide() // start out hidden
    2719                                 .appendTo(layers),
    2720                         // this needs to come last so it's on top
    2721                         bigPlay =
    2722                                 $('<div class="mejs-overlay mejs-layer mejs-overlay-play">'+
    2723                                         '<div class="mejs-overlay-button"></div>'+
    2724                                 '</div>')
    2725                                 .appendTo(layers)
    2726                                 .click(function() {
    2727                     if (t.options.clickToPlayPause) {
    2728                         if (media.paused) {
    2729                             media.play();
    2730                         } else {
    2731                             media.pause();
    2732                         }
    2733                     }
    2734                                 });
    2735 
    2736                         /*
    2737                         if (mejs.MediaFeatures.isiOS || mejs.MediaFeatures.isAndroid) {
    2738                                 bigPlay.remove();
    2739                                 loading.remove();
    2740                         }
    2741                         */
    2742 
    2743 
    2744                         // show/hide big play button
    2745                         media.addEventListener('play',function() {
    2746                                 bigPlay.hide();
    2747                                 loading.hide();
    2748                                 controls.find('.mejs-time-buffering').hide();
    2749                                 error.hide();
    2750                         }, false);
    2751 
    2752                         media.addEventListener('playing', function() {
    2753                                 bigPlay.hide();
    2754                                 loading.hide();
    2755                                 controls.find('.mejs-time-buffering').hide();
    2756                                 error.hide();
    2757                         }, false);
    2758 
    2759                         media.addEventListener('seeking', function() {
    2760                                 loading.show();
    2761                                 controls.find('.mejs-time-buffering').show();
    2762                         }, false);
    2763 
    2764                         media.addEventListener('seeked', function() {
    2765                                 loading.hide();
    2766                                 controls.find('.mejs-time-buffering').hide();
    2767                         }, false);
    2768 
    2769                         media.addEventListener('pause',function() {
    2770                                 if (!mejs.MediaFeatures.isiPhone) {
    2771                                         bigPlay.show();
    2772                                 }
    2773                         }, false);
    2774 
    2775                         media.addEventListener('waiting', function() {
    2776                                 loading.show();
    2777                                 controls.find('.mejs-time-buffering').show();
    2778                         }, false);
    2779 
    2780 
    2781                         // show/hide loading
    2782                         media.addEventListener('loadeddata',function() {
    2783                                 // for some reason Chrome is firing this event
    2784                                 //if (mejs.MediaFeatures.isChrome && media.getAttribute && media.getAttribute('preload') === 'none')
    2785                                 //      return;
    2786 
    2787                                 loading.show();
    2788                                 controls.find('.mejs-time-buffering').show();
    2789                         }, false);
    2790                         media.addEventListener('canplay',function() {
    2791                                 loading.hide();
    2792                                 controls.find('.mejs-time-buffering').hide();
    2793                         }, false);
    2794 
    2795                         // error handling
    2796                         media.addEventListener('error',function() {
    2797                                 loading.hide();
    2798                                 controls.find('.mejs-time-buffering').hide();
    2799                                 error.show();
    2800                                 error.find('mejs-overlay-error').html("Error loading this resource");
    2801                         }, false);
    2802                 },
    2803 
    2804                 buildkeyboard: function(player, controls, layers, media) {
    2805 
    2806                                 var t = this;
    2807 
    2808                                 // listen for key presses
    2809                                 t.globalBind('keydown', function(e) {
    2810 
    2811                                                 if (player.hasFocus && player.options.enableKeyboard) {
    2812 
    2813                                                                 // find a matching key
    2814                                                                 for (var i=0, il=player.options.keyActions.length; i<il; i++) {
    2815                                                                                 var keyAction = player.options.keyActions[i];
    2816 
    2817                                                                                 for (var j=0, jl=keyAction.keys.length; j<jl; j++) {
    2818                                                                                                 if (e.keyCode == keyAction.keys[j]) {
    2819                                                                                                                 e.preventDefault();
    2820                                                                                                                 keyAction.action(player, media, e.keyCode);
    2821                                                                                                                 return false;
    2822                                                                                                 }
    2823                                                                                 }
    2824                                                                 }
    2825                                                 }
    2826 
    2827                                                 return true;
    2828                                 });
    2829 
    2830                                 // check if someone clicked outside a player region, then kill its focus
    2831                                 t.globalBind('click', function(event) {
    2832                                                 if ($(event.target).closest('.mejs-container').length == 0) {
    2833                                                                 player.hasFocus = false;
    2834                                                 }
    2835                                 });
    2836 
    2837                 },
    2838 
    2839                 findTracks: function() {
    2840                         var t = this,
    2841                                 tracktags = t.$media.find('track');
    2842 
    2843                         // store for use by plugins
    2844                         t.tracks = [];
    2845                         tracktags.each(function(index, track) {
    2846 
    2847                                 track = $(track);
    2848 
    2849                                 t.tracks.push({
    2850                                         srclang: (track.attr('srclang')) ? track.attr('srclang').toLowerCase() : '',
    2851                                         src: track.attr('src'),
    2852                                         kind: track.attr('kind'),
    2853                                         label: track.attr('label') || '',
    2854                                         entries: [],
    2855                                         isLoaded: false
    2856                                 });
    2857                         });
    2858                 },
    2859                 changeSkin: function(className) {
    2860                         this.container[0].className = 'mejs-container ' + className;
    2861                         this.setPlayerSize(this.width, this.height);
    2862                         this.setControlsSize();
    2863                 },
    2864                 play: function() {
    2865                         this.media.play();
    2866                 },
    2867                 pause: function() {
    2868                         this.media.pause();
    2869                 },
    2870                 load: function() {
    2871                         this.media.load();
    2872                 },
    2873                 setMuted: function(muted) {
    2874                         this.media.setMuted(muted);
    2875                 },
    2876                 setCurrentTime: function(time) {
    2877                         this.media.setCurrentTime(time);
    2878                 },
    2879                 getCurrentTime: function() {
    2880                         return this.media.currentTime;
    2881                 },
    2882                 setVolume: function(volume) {
    2883                         this.media.setVolume(volume);
    2884                 },
    2885                 getVolume: function() {
    2886                         return this.media.volume;
    2887                 },
    2888                 setSrc: function(src) {
    2889                         this.media.setSrc(src);
    2890                 },
    2891                 remove: function() {
    2892                         var t = this, featureIndex, feature;
    2893 
    2894                         // invoke features cleanup
    2895                         for (featureIndex in t.options.features) {
    2896                                 feature = t.options.features[featureIndex];
    2897                                 if (t['clean' + feature]) {
    2898                                         try {
    2899                                                 t['clean' + feature](t);
    2900                                         } catch (e) {
    2901                                                 // TODO: report control error
    2902                                                 //throw e;
    2903                                                 //console.log('error building ' + feature);
    2904                                                 //console.log(e);
    2905                                         }
    2906                                 }
    2907                         }
    2908 
    2909                         if (t.media.pluginType === 'native') {
    2910                                 t.$media.prop('controls', true);
    2911                         } else {
    2912                                 t.media.remove();
    2913                         }
    2914 
    2915                         // grab video and put it back in place
    2916                         if (!t.isDynamic) {
    2917                                 if (t.media.pluginType === 'native') {
    2918                                         // detach events from the video
    2919                                         // TODO: detach event listeners better than this;
    2920                                         //       also detach ONLY the events attached by this plugin!
    2921                                         //t.$node.clone().insertBefore(t.container);
    2922                                         //t.$node.remove();
    2923                                 }
    2924                                 /*else*/ t.$node.insertBefore(t.container)
    2925                         }
    2926 
    2927                         // Remove the player from the mejs.players array so that pauseOtherPlayers doesn't blow up when trying to pause a non existance flash api.
    2928                         mejs.players.splice( $.inArray( t, mejs.players ), 1);
    2929 
    2930                         t.container.remove();
    2931                         t.globalUnbind();
    2932                         delete t.node.player;
    2933                         delete mejs.players[t.id];
    2934                 }
    2935         };
    2936 
    2937         (function(){
    2938                 var rwindow = /^((after|before)print|(before)?unload|hashchange|message|o(ff|n)line|page(hide|show)|popstate|resize|storage)\b/;
    2939 
    2940                 function splitEvents(events, id) {
    2941                         // add player ID as an event namespace so it's easier to unbind them all later
    2942                         var ret = {d: [], w: []};
    2943                         $.each((events || '').split(' '), function(k, v){
    2944                                 ret[rwindow.test(v) ? 'w' : 'd'].push(v + '.' + id);
    2945                         });
    2946                         ret.d = ret.d.join(' ');
    2947                         ret.w = ret.w.join(' ');
    2948                         return ret;
    2949                 }
    2950 
    2951                 mejs.MediaElementPlayer.prototype.globalBind = function(events, data, callback) {
    2952                         var t = this;
    2953                         events = splitEvents(events, t.id);
    2954                         if (events.d) $(document).bind(events.d, data, callback);
    2955                         if (events.w) $(window).bind(events.w, data, callback);
    2956                 };
    2957 
    2958                 mejs.MediaElementPlayer.prototype.globalUnbind = function(events, callback) {
    2959                         var t = this;
    2960                         events = splitEvents(events, t.id);
    2961                         if (events.d) $(document).unbind(events.d, callback);
    2962                         if (events.w) $(window).unbind(events.w, callback);
    2963                 };
    2964         })();
    2965 
    2966         // turn into jQuery plugin
    2967         if (typeof jQuery != 'undefined') {
    2968                 jQuery.fn.mediaelementplayer = function (options) {
    2969                         if (options === false) {
    2970                                 this.each(function () {
    2971                                         var player = jQuery(this).data('mediaelementplayer');
    2972                                         if (player) {
    2973                                                 player.remove();
    2974                                         }
    2975                                         jQuery(this).removeData('mediaelementplayer');
    2976                                 });
    2977                         }
    2978                         else {
    2979                                 this.each(function () {
    2980                                         jQuery(this).data('mediaelementplayer', new mejs.MediaElementPlayer(this, options));
    2981                                 });
    2982                         }
    2983                         return this;
    2984                 };
    2985         }
    2986 
    2987         $(document).ready(function() {
    2988                 // auto enable using JSON attribute
    2989                 $('.mejs-player').mediaelementplayer();
    2990         });
    2991 
    2992         // push out to window
    2993         window.MediaElementPlayer = mejs.MediaElementPlayer;
    2994 
    2995 })(mejs.$);
    2996 
    2997 (function($) {
    2998 
    2999         $.extend(mejs.MepDefaults, {
    3000                 playpauseText: 'Play/Pause'
    3001         });
    3002 
    3003         // PLAY/pause BUTTON
    3004         $.extend(MediaElementPlayer.prototype, {
    3005                 buildplaypause: function(player, controls, layers, media) {
    3006                         var
    3007                                 t = this,
    3008                                 play =
    3009                                 $('<div class="mejs-button mejs-playpause-button mejs-play" >' +
    3010                                         '<button type="button" aria-controls="' + t.id + '" title="' + t.options.playpauseText + '"></button>' +
    3011                                 '</div>')
    3012                                 .appendTo(controls)
    3013                                 .click(function(e) {
    3014                                         e.preventDefault();
    3015 
    3016                                         if (media.paused) {
    3017                                                 media.play();
    3018                                         } else {
    3019                                                 media.pause();
    3020                                         }
    3021 
    3022                                         return false;
    3023                                 });
    3024 
    3025                         media.addEventListener('play',function() {
    3026                                 play.removeClass('mejs-play').addClass('mejs-pause');
    3027                         }, false);
    3028                         media.addEventListener('playing',function() {
    3029                                 play.removeClass('mejs-play').addClass('mejs-pause');
    3030                         }, false);
    3031 
    3032 
    3033                         media.addEventListener('pause',function() {
    3034                                 play.removeClass('mejs-pause').addClass('mejs-play');
    3035                         }, false);
    3036                         media.addEventListener('paused',function() {
    3037                                 play.removeClass('mejs-pause').addClass('mejs-play');
    3038                         }, false);
    3039                 }
    3040         });
    3041 
    3042 })(mejs.$);
    3043 (function($) {
    3044 
    3045         $.extend(mejs.MepDefaults, {
    3046                 stopText: 'Stop'
    3047         });
    3048 
    3049         // STOP BUTTON
    3050         $.extend(MediaElementPlayer.prototype, {
    3051                 buildstop: function(player, controls, layers, media) {
    3052                         var t = this,
    3053                                 stop =
    3054                                 $('<div class="mejs-button mejs-stop-button mejs-stop">' +
    3055                                         '<button type="button" aria-controls="' + t.id + '" title="' + t.options.stopText + '"></button>' +
    3056                                 '</div>')
    3057                                 .appendTo(controls)
    3058                                 .click(function() {
    3059                                         if (!media.paused) {
    3060                                                 media.pause();
    3061                                         }
    3062                                         if (media.currentTime > 0) {
    3063                                                 media.setCurrentTime(0);
    3064                         media.pause();
    3065                                                 controls.find('.mejs-time-current').width('0px');
    3066                                                 controls.find('.mejs-time-handle').css('left', '0px');
    3067                                                 controls.find('.mejs-time-float-current').html( mejs.Utility.secondsToTimeCode(0) );
    3068                                                 controls.find('.mejs-currenttime').html( mejs.Utility.secondsToTimeCode(0) );
    3069                                                 layers.find('.mejs-poster').show();
    3070                                         }
    3071                                 });
    3072                 }
    3073         });
    3074 
    3075 })(mejs.$);
    3076 (function($) {
    3077         // progress/loaded bar
    3078         $.extend(MediaElementPlayer.prototype, {
    3079                 buildprogress: function(player, controls, layers, media) {
    3080 
    3081                         $('<div class="mejs-time-rail">'+
    3082                                 '<span class="mejs-time-total">'+
    3083                                         '<span class="mejs-time-buffering"></span>'+
    3084                                         '<span class="mejs-time-loaded"></span>'+
    3085                                         '<span class="mejs-time-current"></span>'+
    3086                                         '<span class="mejs-time-handle"></span>'+
    3087                                         '<span class="mejs-time-float">' +
    3088                                                 '<span class="mejs-time-float-current">00:00</span>' +
    3089                                                 '<span class="mejs-time-float-corner"></span>' +
    3090                                         '</span>'+
    3091                                 '</span>'+
    3092                         '</div>')
    3093                                 .appendTo(controls);
    3094                                 controls.find('.mejs-time-buffering').hide();
    3095 
    3096                         var
    3097                                 t = this,
    3098                                 total = controls.find('.mejs-time-total'),
    3099                                 loaded  = controls.find('.mejs-time-loaded'),
    3100                                 current  = controls.find('.mejs-time-current'),
    3101                                 handle  = controls.find('.mejs-time-handle'),
    3102                                 timefloat  = controls.find('.mejs-time-float'),
    3103                                 timefloatcurrent  = controls.find('.mejs-time-float-current'),
    3104                                 handleMouseMove = function (e) {
    3105                                         // mouse position relative to the object
    3106                                         var x = e.pageX,
    3107                                                 offset = total.offset(),
    3108                                                 width = total.outerWidth(true),
    3109                                                 percentage = 0,
    3110                                                 newTime = 0,
    3111                                                 pos = 0;
    3112 
    3113 
    3114                                         if (media.duration) {
    3115                                                 if (x < offset.left) {
    3116                                                         x = offset.left;
    3117                                                 } else if (x > width + offset.left) {
    3118                                                         x = width + offset.left;
    3119                                                 }
    3120 
    3121                                                 pos = x - offset.left;
    3122                                                 percentage = (pos / width);
    3123                                                 newTime = (percentage <= 0.02) ? 0 : percentage * media.duration;
    3124 
    3125                                                 // seek to where the mouse is
    3126                                                 if (mouseIsDown && newTime !== media.currentTime) {
    3127                                                         media.setCurrentTime(newTime);
    3128                                                 }
    3129 
    3130                                                 // position floating time box
    3131                                                 if (!mejs.MediaFeatures.hasTouch) {
    3132                                                                 timefloat.css('left', pos);
    3133                                                                 timefloatcurrent.html( mejs.Utility.secondsToTimeCode(newTime) );
    3134                                                                 timefloat.show();
    3135                                                 }
    3136                                         }
    3137                                 },
    3138                                 mouseIsDown = false,
    3139                                 mouseIsOver = false;
    3140 
    3141                         // handle clicks
    3142                         //controls.find('.mejs-time-rail').delegate('span', 'click', handleMouseMove);
    3143                         total
    3144                                 .bind('mousedown', function (e) {
    3145                                         // only handle left clicks
    3146                                         if (e.which === 1) {
    3147                                                 mouseIsDown = true;
    3148                                                 handleMouseMove(e);
    3149                                                 t.globalBind('mousemove.dur', function(e) {
    3150                                                         handleMouseMove(e);
    3151                                                 });
    3152                                                 t.globalBind('mouseup.dur', function (e) {
    3153                                                         mouseIsDown = false;
    3154                                                         timefloat.hide();
    3155                                                         t.globalUnbind('.dur');
    3156                                                 });
    3157                                                 return false;
    3158                                         }
    3159                                 })
    3160                                 .bind('mouseenter', function(e) {
    3161                                         mouseIsOver = true;
    3162                                         t.globalBind('mousemove.dur', function(e) {
    3163                                                 handleMouseMove(e);
    3164                                         });
    3165                                         if (!mejs.MediaFeatures.hasTouch) {
    3166                                                 timefloat.show();
    3167                                         }
    3168                                 })
    3169                                 .bind('mouseleave',function(e) {
    3170                                         mouseIsOver = false;
    3171                                         if (!mouseIsDown) {
    3172                                                 t.globalUnbind('.dur');
    3173                                                 timefloat.hide();
    3174                                         }
    3175                                 });
    3176 
    3177                         // loading
    3178                         media.addEventListener('progress', function (e) {
    3179                                 player.setProgressRail(e);
    3180                                 player.setCurrentRail(e);
    3181                         }, false);
    3182 
    3183                         // current time
    3184                         media.addEventListener('timeupdate', function(e) {
    3185                                 player.setProgressRail(e);
    3186                                 player.setCurrentRail(e);
    3187                         }, false);
    3188 
    3189 
    3190                         // store for later use
    3191                         t.loaded = loaded;
    3192                         t.total = total;
    3193                         t.current = current;
    3194                         t.handle = handle;
    3195                 },
    3196                 setProgressRail: function(e) {
    3197 
    3198                         var
    3199                                 t = this,
    3200                                 target = (e != undefined) ? e.target : t.media,
    3201                                 percent = null;
    3202 
    3203                         // newest HTML5 spec has buffered array (FF4, Webkit)
    3204                         if (target && target.buffered && target.buffered.length > 0 && target.buffered.end && target.duration) {
    3205                                 // TODO: account for a real array with multiple values (only Firefox 4 has this so far)
    3206                                 percent = target.buffered.end(0) / target.duration;
    3207                         }
    3208                         // Some browsers (e.g., FF3.6 and Safari 5) cannot calculate target.bufferered.end()
    3209                         // to be anything other than 0. If the byte count is available we use this instead.
    3210                         // Browsers that support the else if do not seem to have the bufferedBytes value and
    3211                         // should skip to there. Tested in Safari 5, Webkit head, FF3.6, Chrome 6, IE 7/8.
    3212                         else if (target && target.bytesTotal != undefined && target.bytesTotal > 0 && target.bufferedBytes != undefined) {
    3213                                 percent = target.bufferedBytes / target.bytesTotal;
    3214                         }
    3215                         // Firefox 3 with an Ogg file seems to go this way
    3216                         else if (e && e.lengthComputable && e.total != 0) {
    3217                                 percent = e.loaded/e.total;
    3218                         }
    3219 
    3220                         // finally update the progress bar
    3221                         if (percent !== null) {
    3222                                 percent = Math.min(1, Math.max(0, percent));
    3223                                 // update loaded bar
    3224                                 if (t.loaded && t.total) {
    3225                                         t.loaded.width(t.total.width() * percent);
    3226                                 }
    3227                         }
    3228                 },
    3229                 setCurrentRail: function() {
    3230 
    3231                         var t = this;
    3232 
    3233                         if (t.media.currentTime != undefined && t.media.duration) {
    3234 
    3235                                 // update bar and handle
    3236                                 if (t.total && t.handle) {
    3237                                         var
    3238                                                 newWidth = Math.round(t.total.width() * t.media.currentTime / t.media.duration),
    3239                                                 handlePos = newWidth - Math.round(t.handle.outerWidth(true) / 2);
    3240 
    3241                                         t.current.width(newWidth);
    3242                                         t.handle.css('left', handlePos);
    3243                                 }
    3244                         }
    3245 
    3246                 }
    3247         });
    3248 })(mejs.$);
    3249 
    3250 (function($) {
    3251 
    3252         // options
    3253         $.extend(mejs.MepDefaults, {
    3254                 duration: -1,
    3255                 timeAndDurationSeparator: ' <span> | </span> '
    3256         });
    3257 
    3258 
    3259         // current and duration 00:00 / 00:00
    3260         $.extend(MediaElementPlayer.prototype, {
    3261                 buildcurrent: function(player, controls, layers, media) {
    3262                         var t = this;
    3263 
    3264                         $('<div class="mejs-time">'+
    3265                                         '<span class="mejs-currenttime">' + (player.options.alwaysShowHours ? '00:' : '')
    3266                                         + (player.options.showTimecodeFrameCount? '00:00:00':'00:00')+ '</span>'+
    3267                                         '</div>')
    3268                                         .appendTo(controls);
    3269 
    3270                         t.currenttime = t.controls.find('.mejs-currenttime');
    3271 
    3272                         media.addEventListener('timeupdate',function() {
    3273                                 player.updateCurrent();
    3274                         }, false);
    3275                 },
    3276 
    3277 
    3278                 buildduration: function(player, controls, layers, media) {
    3279                         var t = this;
    3280 
    3281                         if (controls.children().last().find('.mejs-currenttime').length > 0) {
    3282                                 $(t.options.timeAndDurationSeparator +
    3283                                         '<span class="mejs-duration">' +
    3284                                                 (t.options.duration > 0 ?
    3285                                                         mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount,  t.options.framesPerSecond || 25) :
    3286                                                         ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
    3287                                                 ) +
    3288                                         '</span>')
    3289                                         .appendTo(controls.find('.mejs-time'));
    3290                         } else {
    3291 
    3292                                 // add class to current time
    3293                                 controls.find('.mejs-currenttime').parent().addClass('mejs-currenttime-container');
    3294 
    3295                                 $('<div class="mejs-time mejs-duration-container">'+
    3296                                         '<span class="mejs-duration">' +
    3297                                                 (t.options.duration > 0 ?
    3298                                                         mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount,  t.options.framesPerSecond || 25) :
    3299                                                         ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
    3300                                                 ) +
    3301                                         '</span>' +
    3302                                 '</div>')
    3303                                 .appendTo(controls);
    3304                         }
    3305 
    3306                         t.durationD = t.controls.find('.mejs-duration');
    3307 
    3308                         media.addEventListener('timeupdate',function() {
    3309                                 player.updateDuration();
    3310                         }, false);
    3311                 },
    3312 
    3313                 updateCurrent:  function() {
    3314                         var t = this;
    3315 
    3316                         if (t.currenttime) {
    3317                                 t.currenttime.html(mejs.Utility.secondsToTimeCode(t.media.currentTime, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount,  t.options.framesPerSecond || 25));
    3318                         }
    3319                 },
    3320 
    3321                 updateDuration: function() {
    3322                         var t = this;
    3323 
    3324                         //Toggle the long video class if the video is longer than an hour.
    3325                         t.container.toggleClass("mejs-long-video", t.media.duration > 3600);
    3326 
    3327                         if (t.durationD && (t.options.duration > 0 || t.media.duration)) {
    3328                                 t.durationD.html(mejs.Utility.secondsToTimeCode(t.options.duration > 0 ? t.options.duration : t.media.duration, t.options.alwaysShowHours, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
    3329                         }
    3330                 }
    3331         });
    3332 
    3333 })(mejs.$);
    3334 (function($) {
    3335 
    3336         $.extend(mejs.MepDefaults, {
    3337                 muteText: 'Mute Toggle',
    3338                 hideVolumeOnTouchDevices: true,
    3339 
    3340                 audioVolume: 'horizontal',
    3341                 videoVolume: 'vertical'
    3342         });
    3343 
    3344         $.extend(MediaElementPlayer.prototype, {
    3345                 buildvolume: function(player, controls, layers, media) {
    3346 
    3347                         // Android and iOS don't support volume controls
    3348                         if (mejs.MediaFeatures.hasTouch && this.options.hideVolumeOnTouchDevices)
    3349                                 return;
    3350 
    3351                         var t = this,
    3352                                 mode = (t.isVideo) ? t.options.videoVolume : t.options.audioVolume,
    3353                                 mute = (mode == 'horizontal') ?
    3354 
    3355                                 // horizontal version
    3356                                 $('<div class="mejs-button mejs-volume-button mejs-mute">'+
    3357                                         '<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '"></button>'+
    3358                                 '</div>' +
    3359                                 '<div class="mejs-horizontal-volume-slider">'+ // outer background
    3360                                         '<div class="mejs-horizontal-volume-total"></div>'+ // line background
    3361                                         '<div class="mejs-horizontal-volume-current"></div>'+ // current volume
    3362                                         '<div class="mejs-horizontal-volume-handle"></div>'+ // handle
    3363                                 '</div>'
    3364                                 )
    3365                                         .appendTo(controls) :
    3366 
    3367                                 // vertical version
    3368                                 $('<div class="mejs-button mejs-volume-button mejs-mute">'+
    3369                                         '<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '"></button>'+
    3370                                         '<div class="mejs-volume-slider">'+ // outer background
    3371                                                 '<div class="mejs-volume-total"></div>'+ // line background
    3372                                                 '<div class="mejs-volume-current"></div>'+ // current volume
    3373                                                 '<div class="mejs-volume-handle"></div>'+ // handle
    3374                                         '</div>'+
    3375                                 '</div>')
    3376                                         .appendTo(controls),
    3377                         volumeSlider = t.container.find('.mejs-volume-slider, .mejs-horizontal-volume-slider'),
    3378                         volumeTotal = t.container.find('.mejs-volume-total, .mejs-horizontal-volume-total'),
    3379                         volumeCurrent = t.container.find('.mejs-volume-current, .mejs-horizontal-volume-current'),
    3380                         volumeHandle = t.container.find('.mejs-volume-handle, .mejs-horizontal-volume-handle'),
    3381 
    3382                         positionVolumeHandle = function(volume, secondTry) {
    3383 
    3384                                 if (!volumeSlider.is(':visible') && typeof secondTry == 'undefined') {
    3385                                         volumeSlider.show();
    3386                                         positionVolumeHandle(volume, true);
    3387                                         volumeSlider.hide()
    3388                                         return;
    3389                                 }
    3390 
    3391                                 // correct to 0-1
    3392                                 volume = Math.max(0,volume);
    3393                                 volume = Math.min(volume,1);
    3394 
    3395                                 // ajust mute button style
    3396                                 if (volume == 0) {
    3397                                         mute.removeClass('mejs-mute').addClass('mejs-unmute');
    3398                                 } else {
    3399                                         mute.removeClass('mejs-unmute').addClass('mejs-mute');
    3400                                 }
    3401 
    3402                                 // position slider
    3403                                 if (mode == 'vertical') {
    3404                                         var
    3405 
    3406                                                 // height of the full size volume slider background
    3407                                                 totalHeight = volumeTotal.height(),
    3408 
    3409                                                 // top/left of full size volume slider background
    3410                                                 totalPosition = volumeTotal.position(),
    3411 
    3412                                                 // the new top position based on the current volume
    3413                                                 // 70% volume on 100px height == top:30px
    3414                                                 newTop = totalHeight - (totalHeight * volume);
    3415 
    3416                                         // handle
    3417                                         volumeHandle.css('top', Math.round(totalPosition.top + newTop - (volumeHandle.height() / 2)));
    3418 
    3419                                         // show the current visibility
    3420                                         volumeCurrent.height(totalHeight - newTop );
    3421                                         volumeCurrent.css('top', totalPosition.top + newTop);
    3422                                 } else {
    3423                                         var
    3424 
    3425                                                 // height of the full size volume slider background
    3426                                                 totalWidth = volumeTotal.width(),
    3427 
    3428                                                 // top/left of full size volume slider background
    3429                                                 totalPosition = volumeTotal.position(),
    3430 
    3431                                                 // the new left position based on the current volume
    3432                                                 newLeft = totalWidth * volume;
    3433 
    3434                                         // handle
    3435                                         volumeHandle.css('left', Math.round(totalPosition.left + newLeft - (volumeHandle.width() / 2)));
    3436 
    3437                                         // rezize the current part of the volume bar
    3438                                         volumeCurrent.width( Math.round(newLeft) );
    3439                                 }
    3440                         },
    3441                         handleVolumeMove = function(e) {
    3442 
    3443                                 var volume = null,
    3444                                         totalOffset = volumeTotal.offset();
    3445 
    3446                                 // calculate the new volume based on the moust position
    3447                                 if (mode == 'vertical') {
    3448 
    3449                                         var
    3450                                                 railHeight = volumeTotal.height(),
    3451                                                 totalTop = parseInt(volumeTotal.css('top').replace(/px/,''),10),
    3452                                                 newY = e.pageY - totalOffset.top;
    3453 
    3454                                         volume = (railHeight - newY) / railHeight;
    3455 
    3456                                         // the controls just hide themselves (usually when mouse moves too far up)
    3457                                         if (totalOffset.top == 0 || totalOffset.left == 0)
    3458                                                 return;
    3459 
    3460                                 } else {
    3461                                         var
    3462                                                 railWidth = volumeTotal.width(),
    3463                                                 newX = e.pageX - totalOffset.left;
    3464 
    3465                                         volume = newX / railWidth;
    3466                                 }
    3467 
    3468                                 // ensure the volume isn't outside 0-1
    3469                                 volume = Math.max(0,volume);
    3470                                 volume = Math.min(volume,1);
    3471 
    3472                                 // position the slider and handle
    3473                                 positionVolumeHandle(volume);
    3474 
    3475                                 // set the media object (this will trigger the volumechanged event)
    3476                                 if (volume == 0) {
    3477                                         media.setMuted(true);
    3478                                 } else {
    3479                                         media.setMuted(false);
    3480                                 }
    3481                                 media.setVolume(volume);
    3482                         },
    3483                         mouseIsDown = false,
    3484                         mouseIsOver = false;
    3485 
    3486                         // SLIDER
    3487 
    3488                         mute
    3489                                 .hover(function() {
    3490                                         volumeSlider.show();
    3491                                         mouseIsOver = true;
    3492                                 }, function() {
    3493                                         mouseIsOver = false;
    3494 
    3495                                         if (!mouseIsDown && mode == 'vertical') {
    3496                                                 volumeSlider.hide();
    3497                                         }
    3498                                 });
    3499 
    3500                         volumeSlider
    3501                                 .bind('mouseover', function() {
    3502                                         mouseIsOver = true;
    3503                                 })
    3504                                 .bind('mousedown', function (e) {
    3505                                         handleVolumeMove(e);
    3506                                         t.globalBind('mousemove.vol', function(e) {
    3507                                                 handleVolumeMove(e);
    3508                                         });
    3509                                         t.globalBind('mouseup.vol', function () {
    3510                                                 mouseIsDown = false;
    3511                                                 t.globalUnbind('.vol');
    3512 
    3513                                                 if (!mouseIsOver && mode == 'vertical') {
    3514                                                         volumeSlider.hide();
    3515                                                 }
    3516                                         });
    3517                                         mouseIsDown = true;
    3518 
    3519                                         return false;
    3520                                 });
    3521 
    3522 
    3523                         // MUTE button
    3524                         mute.find('button').click(function() {
    3525                                 media.setMuted( !media.muted );
    3526                         });
    3527 
    3528                         // listen for volume change events from other sources
    3529                         media.addEventListener('volumechange', function(e) {
    3530                                 if (!mouseIsDown) {
    3531                                         if (media.muted) {
    3532                                                 positionVolumeHandle(0);
    3533                                                 mute.removeClass('mejs-mute').addClass('mejs-unmute');
    3534                                         } else {
    3535                                                 positionVolumeHandle(media.volume);
    3536                                                 mute.removeClass('mejs-unmute').addClass('mejs-mute');
    3537                                         }
    3538                                 }
    3539                         }, false);
    3540 
    3541                         if (t.container.is(':visible')) {
    3542                                 // set initial volume
    3543                                 positionVolumeHandle(player.options.startVolume);
    3544 
    3545                                 // mutes the media and sets the volume icon muted if the initial volume is set to 0
    3546         if (player.options.startVolume === 0) {
    3547           media.setMuted(true);
    3548         }
    3549 
    3550                                 // shim gets the startvolume as a parameter, but we have to set it on the native <video> and <audio> elements
    3551                                 if (media.pluginType === 'native') {
    3552                                         media.setVolume(player.options.startVolume);
    3553                                 }
    3554                         }
    3555                 }
    3556         });
    3557 
    3558 })(mejs.$);
    3559 
    3560 (function($) {
    3561 
    3562         $.extend(mejs.MepDefaults, {
    3563                 usePluginFullScreen: true,
    3564                 newWindowCallback: function() { return '';},
    3565                 fullscreenText: mejs.i18n.t('Fullscreen')
    3566         });
    3567 
    3568         $.extend(MediaElementPlayer.prototype, {
    3569 
    3570                 isFullScreen: false,
    3571 
    3572                 isNativeFullScreen: false,
    3573 
    3574                 docStyleOverflow: null,
    3575 
    3576                 isInIframe: false,
    3577 
    3578                 buildfullscreen: function(player, controls, layers, media) {
    3579 
    3580                         if (!player.isVideo)
    3581                                 return;
    3582 
    3583                         player.isInIframe = (window.location != window.parent.location);
    3584 
    3585                         // native events
    3586                         if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
    3587 
    3588                                 // chrome doesn't alays fire this in an iframe
    3589                                 var func = function(e) {
    3590 
    3591                                         if (mejs.MediaFeatures.isFullScreen()) {
    3592                                                 player.isNativeFullScreen = true;
    3593                                                 // reset the controls once we are fully in full screen
    3594                                                 player.setControlsSize();
    3595                                         } else {
    3596                                                 player.isNativeFullScreen = false;
    3597                                                 // when a user presses ESC
    3598                                                 // make sure to put the player back into place
    3599                                                 player.exitFullScreen();
    3600                                         }
    3601                                 };
    3602 
    3603                                 if (mejs.MediaFeatures.hasMozNativeFullScreen) {
    3604                                         player.globalBind(mejs.MediaFeatures.fullScreenEventName, func);
    3605                                 } else {
    3606                                         player.container.bind(mejs.MediaFeatures.fullScreenEventName, func);
    3607                                 }
    3608                         }
    3609 
    3610                         var t = this,
    3611                                 normalHeight = 0,
    3612                                 normalWidth = 0,
    3613                                 container = player.container,
    3614                                 fullscreenBtn =
    3615                                         $('<div class="mejs-button mejs-fullscreen-button">' +
    3616                                                 '<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
    3617                                         '</div>')
    3618                                         .appendTo(controls);
    3619 
    3620                                 if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {
    3621 
    3622                                         fullscreenBtn.click(function() {
    3623                                                 var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;
    3624 
    3625                                                 if (isFullScreen) {
    3626                                                         player.exitFullScreen();
    3627                                                 } else {
    3628                                                         player.enterFullScreen();
    3629                                                 }
    3630                                         });
    3631 
    3632                                 } else {
    3633 
    3634                                         var hideTimeout = null,
    3635                                                 supportsPointerEvents = (function() {
    3636                                                         // TAKEN FROM MODERNIZR
    3637                                                         var element = document.createElement('x'),
    3638                                                                 documentElement = document.documentElement,
    3639                                                                 getComputedStyle = window.getComputedStyle,
    3640                                                                 supports;
    3641                                                         if(!('pointerEvents' in element.style)){
    3642                                                                 return false;
    3643                                                         }
    3644                                                         element.style.pointerEvents = 'auto';
    3645                                                         element.style.pointerEvents = 'x';
    3646                                                         documentElement.appendChild(element);
    3647                                                         supports = getComputedStyle &&
    3648                                                                 getComputedStyle(element, '').pointerEvents === 'auto';
    3649                                                         documentElement.removeChild(element);
    3650                                                         return !!supports;
    3651                                                 })();
    3652 
    3653                                         //console.log('supportsPointerEvents', supportsPointerEvents);
    3654 
    3655                                         if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(
    3656 
    3657                                                 // allows clicking through the fullscreen button and controls down directly to Flash
    3658 
    3659                                                 /*
    3660                                                  When a user puts his mouse over the fullscreen button, the controls are disabled
    3661                                                  So we put a div over the video and another one on iether side of the fullscreen button
    3662                                                  that caputre mouse movement
    3663                                                  and restore the controls once the mouse moves outside of the fullscreen button
    3664                                                 */
    3665 
    3666                                                 var fullscreenIsDisabled = false,
    3667                                                         restoreControls = function() {
    3668                                                                 if (fullscreenIsDisabled) {
    3669                                                                         // hide the hovers
    3670                                                                         videoHoverDiv.hide();
    3671                                                                         controlsLeftHoverDiv.hide();
    3672                                                                         controlsRightHoverDiv.hide();
    3673 
    3674                                                                         // restore the control bar
    3675                                                                         fullscreenBtn.css('pointer-events', '');
    3676                                                                         t.controls.css('pointer-events', '');
    3677 
    3678                                                                         // store for later
    3679                                                                         fullscreenIsDisabled = false;
    3680                                                                 }
    3681                                                         },
    3682                                                         videoHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
    3683                                                         controlsLeftHoverDiv = $('<div class="mejs-fullscreen-hover"  />').appendTo(t.container).mouseover(restoreControls),
    3684                                                         controlsRightHoverDiv = $('<div class="mejs-fullscreen-hover"  />').appendTo(t.container).mouseover(restoreControls),
    3685                                                         positionHoverDivs = function() {
    3686                                                                 var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};
    3687                                                                 videoHoverDiv.css(style);
    3688                                                                 controlsLeftHoverDiv.css(style);
    3689                                                                 controlsRightHoverDiv.css(style);
    3690 
    3691                                                                 // over video, but not controls
    3692                                                                 videoHoverDiv
    3693                                                                         .width( t.container.width() )
    3694                                                                         .height( t.container.height() - t.controls.height() );
    3695 
    3696                                                                 // over controls, but not the fullscreen button
    3697                                                                 var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;
    3698                                                                         fullScreenBtnWidth = fullscreenBtn.outerWidth(true);
    3699 
    3700                                                                 controlsLeftHoverDiv
    3701                                                                         .width( fullScreenBtnOffset )
    3702                                                                         .height( t.controls.height() )
    3703                                                                         .css({top: t.container.height() - t.controls.height()});
    3704 
    3705                                                                 // after the fullscreen button
    3706                                                                 controlsRightHoverDiv
    3707                                                                         .width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )
    3708                                                                         .height( t.controls.height() )
    3709                                                                         .css({top: t.container.height() - t.controls.height(),
    3710                                                                                  left: fullScreenBtnOffset + fullScreenBtnWidth});
    3711                                                         };
    3712 
    3713                                                 t.globalBind('resize', function() {
    3714                                                         positionHoverDivs();
    3715                                                 });
    3716 
    3717                                                 // on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
    3718                                                 fullscreenBtn
    3719                                                         .mouseover(function() {
    3720 
    3721                                                                 if (!t.isFullScreen) {
    3722 
    3723                                                                         var buttonPos = fullscreenBtn.offset(),
    3724                                                                                 containerPos = player.container.offset();
    3725 
    3726                                                                         // move the button in Flash into place
    3727                                                                         media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);
    3728 
    3729                                                                         // allows click through
    3730                                                                         fullscreenBtn.css('pointer-events', 'none');
    3731                                                                         t.controls.css('pointer-events', 'none');
    3732 
    3733                                                                         // show the divs that will restore things
    3734                                                                         videoHoverDiv.show();
    3735                                                                         controlsRightHoverDiv.show();
    3736                                                                         controlsLeftHoverDiv.show();
    3737                                                                         positionHoverDivs();
    3738 
    3739                                                                         fullscreenIsDisabled = true;
    3740                                                                 }
    3741 
    3742                                                         });
    3743 
    3744                                                 // restore controls anytime the user enters or leaves fullscreen
    3745                                                 media.addEventListener('fullscreenchange', function(e) {
    3746                                                         restoreControls();
    3747                                                 });
    3748 
    3749 
    3750                                                 // the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
    3751                                                 // so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
    3752                                                 /*
    3753                                                 t.globalBind('mousemove', function(e) {
    3754 
    3755                                                         // if the mouse is anywhere but the fullsceen button, then restore it all
    3756                                                         if (fullscreenIsDisabled) {
    3757 
    3758                                                                 var fullscreenBtnPos = fullscreenBtn.offset();
    3759 
    3760 
    3761                                                                 if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||
    3762                                                                         e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)
    3763                                                                         ) {
    3764 
    3765                                                                         fullscreenBtn.css('pointer-events', '');
    3766                                                                         t.controls.css('pointer-events', '');
    3767 
    3768                                                                         fullscreenIsDisabled = false;
    3769                                                                 }
    3770                                                         }
    3771                                                 });
    3772                                                 */
    3773 
    3774 
    3775                                         } else {
    3776 
    3777                                                 // the hover state will show the fullscreen button in Flash to hover up and click
    3778 
    3779                                                 fullscreenBtn
    3780                                                         .mouseover(function() {
    3781 
    3782                                                                 if (hideTimeout !== null) {
    3783                                                                         clearTimeout(hideTimeout);
    3784                                                                         delete hideTimeout;
    3785                                                                 }
    3786 
    3787                                                                 var buttonPos = fullscreenBtn.offset(),
    3788                                                                         containerPos = player.container.offset();
    3789 
    3790                                                                 media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);
    3791 
    3792                                                         })
    3793                                                         .mouseout(function() {
    3794 
    3795                                                                 if (hideTimeout !== null) {
    3796                                                                         clearTimeout(hideTimeout);
    3797                                                                         delete hideTimeout;
    3798                                                                 }
    3799 
    3800                                                                 hideTimeout = setTimeout(function() {
    3801                                                                         media.hideFullscreenButton();
    3802                                                                 }, 1500);
    3803 
    3804 
    3805                                                         });
    3806                                         }
    3807                                 }
    3808 
    3809                         player.fullscreenBtn = fullscreenBtn;
    3810 
    3811                         t.globalBind('keydown',function (e) {
    3812                                 if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
    3813                                         player.exitFullScreen();
    3814                                 }
    3815                         });
    3816 
    3817                 },
    3818 
    3819                 cleanfullscreen: function(player) {
    3820                         player.exitFullScreen();
    3821                 },
    3822 
    3823                 enterFullScreen: function() {
    3824 
    3825                         var t = this;
    3826 
    3827                         // firefox+flash can't adjust plugin sizes without resetting :(
    3828                         if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
    3829                                 //t.media.setFullscreen(true);
    3830                                 //player.isFullScreen = true;
    3831                                 return;
    3832                         }
    3833 
    3834                         // store overflow
    3835                         docStyleOverflow = document.documentElement.style.overflow;
    3836                         // set it to not show scroll bars so 100% will work
    3837                         document.documentElement.style.overflow = 'hidden';
    3838 
    3839                         // store sizing
    3840                         normalHeight = t.container.height();
    3841                         normalWidth = t.container.width();
    3842 
    3843                         // attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
    3844                         if (t.media.pluginType === 'native') {
    3845                                 if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
    3846 
    3847                                         mejs.MediaFeatures.requestFullScreen(t.container[0]);
    3848                                         //return;
    3849 
    3850                                         if (t.isInIframe) {
    3851                                                 // sometimes exiting from fullscreen doesn't work
    3852                                                 // notably in Chrome <iframe>. Fixed in version 17
    3853                                                 setTimeout(function checkFullscreen() {
    3854 
    3855                                                         if (t.isNativeFullScreen) {
    3856 
    3857                                                                 // check if the video is suddenly not really fullscreen
    3858                                                                 if ($(window).width() !== screen.width) {
    3859                                                                         // manually exit
    3860                                                                         t.exitFullScreen();
    3861                                                                 } else {
    3862                                                                         // test again
    3863                                                                         setTimeout(checkFullscreen, 500);
    3864                                                                 }
    3865                                                         }
    3866 
    3867 
    3868                                                 }, 500);
    3869                                         }
    3870 
    3871                                 } else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
    3872                                         t.media.webkitEnterFullscreen();
    3873                                         return;
    3874                                 }
    3875                         }
    3876 
    3877                         // check for iframe launch
    3878                         if (t.isInIframe) {
    3879                                 var url = t.options.newWindowCallback(this);
    3880 
    3881 
    3882                                 if (url !== '') {
    3883 
    3884                                         // launch immediately
    3885                                         if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
    3886                                                 t.pause();
    3887                                                 window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
    3888                                                 return;
    3889                                         } else {
    3890                                                 setTimeout(function() {
    3891                                                         if (!t.isNativeFullScreen) {
    3892                                                                 t.pause();
    3893                                                                 window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
    3894                                                         }
    3895                                                 }, 250);
    3896                                         }
    3897                                 }
    3898 
    3899                         }
    3900 
    3901                         // full window code
    3902 
    3903 
    3904 
    3905                         // make full size
    3906                         t.container
    3907                                 .addClass('mejs-container-fullscreen')
    3908                                 .width('100%')
    3909                                 .height('100%');
    3910                                 //.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});
    3911 
    3912                         // Only needed for safari 5.1 native full screen, can cause display issues elsewhere
    3913                         // Actually, it seems to be needed for IE8, too
    3914                         //if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
    3915                                 setTimeout(function() {
    3916                                         t.container.css({width: '100%', height: '100%'});
    3917                                         t.setControlsSize();
    3918                                 }, 500);
    3919                         //}
    3920 
    3921                         if (t.pluginType === 'native') {
    3922                                 t.$media
    3923                                         .width('100%')
    3924                                         .height('100%');
    3925                         } else {
    3926                                 t.container.find('.mejs-shim')
    3927                                         .width('100%')
    3928                                         .height('100%');
    3929 
    3930                                 //if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
    3931                                         t.media.setVideoSize($(window).width(),$(window).height());
    3932                                 //}
    3933                         }
    3934 
    3935                         t.layers.children('div')
    3936                                 .width('100%')
    3937                                 .height('100%');
    3938 
    3939                         if (t.fullscreenBtn) {
    3940                                 t.fullscreenBtn
    3941                                         .removeClass('mejs-fullscreen')
    3942                                         .addClass('mejs-unfullscreen');
    3943                         }
    3944 
    3945                         t.setControlsSize();
    3946                         t.isFullScreen = true;
    3947                 },
    3948 
    3949                 exitFullScreen: function() {
    3950 
    3951                         var t = this;
    3952 
    3953                         // firefox can't adjust plugins
    3954                         if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
    3955                                 t.media.setFullscreen(false);
    3956                                 //player.isFullScreen = false;
    3957                                 return;
    3958                         }
    3959 
    3960                         // come outo of native fullscreen
    3961                         if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
    3962                                 mejs.MediaFeatures.cancelFullScreen();
    3963                         }
    3964 
    3965                         // restore scroll bars to document
    3966                         document.documentElement.style.overflow = docStyleOverflow;
    3967 
    3968                         t.container
    3969                                 .removeClass('mejs-container-fullscreen')
    3970                                 .width(normalWidth)
    3971                                 .height(normalHeight);
    3972                                 //.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});
    3973 
    3974                         if (t.pluginType === 'native') {
    3975                                 t.$media
    3976                                         .width(normalWidth)
    3977                                         .height(normalHeight);
    3978                         } else {
    3979                                 t.container.find('object embed')
    3980                                         .width(normalWidth)
    3981                                         .height(normalHeight);
    3982 
    3983                                 t.media.setVideoSize(normalWidth, normalHeight);
    3984                         }
    3985 
    3986                         t.layers.children('div')
    3987                                 .width(normalWidth)
    3988                                 .height(normalHeight);
    3989 
    3990                         t.fullscreenBtn
    3991                                 .removeClass('mejs-unfullscreen')
    3992                                 .addClass('mejs-fullscreen');
    3993 
    3994                         t.setControlsSize();
    3995                         t.isFullScreen = false;
    3996                 }
    3997         });
    3998 
    3999 })(mejs.$);
    4000 
    4001 (function($) {
    4002 
    4003         // add extra default options
    4004         $.extend(mejs.MepDefaults, {
    4005                 // this will automatically turn on a <track>
    4006                 startLanguage: '',
    4007 
    4008                 tracksText: 'Captions/Subtitles',
    4009 
    4010                 // option to remove the [cc] button when no <track kind="subtitles"> are present
    4011                 hideCaptionsButtonWhenEmpty: true,
    4012 
    4013                 // If true and we only have one track, change captions to popup
    4014                 toggleCaptionsButtonWhenOnlyOne: false,
    4015 
    4016                 // #id or .class
    4017                 slidesSelector: ''
    4018         });
    4019 
    4020         $.extend(MediaElementPlayer.prototype, {
    4021 
    4022                 hasChapters: false,
    4023 
    4024                 buildtracks: function(player, controls, layers, media) {
    4025                         if (!player.isVideo)
    4026                                 return;
    4027 
    4028                         if (player.tracks.length == 0)
    4029                                 return;
    4030 
    4031                         var t = this,
    4032                                 i,
    4033                                 options = '';
    4034 
    4035                         player.chapters =
    4036                                         $('<div class="mejs-chapters mejs-layer"></div>')
    4037                                                 .prependTo(layers).hide();
    4038                         player.captions =
    4039                                         $('<div class="mejs-captions-layer mejs-layer"><div class="mejs-captions-position mejs-captions-position-hover"><span class="mejs-captions-text"></span></div></div>')
    4040                                                 .prependTo(layers).hide();
    4041                         player.captionsText = player.captions.find('.mejs-captions-text');
    4042                         player.captionsButton =
    4043                                         $('<div class="mejs-button mejs-captions-button">'+
    4044                                                 '<button type="button" aria-controls="' + t.id + '" title="' + t.options.tracksText + '"></button>'+
    4045                                                 '<div class="mejs-captions-selector">'+
    4046                                                         '<ul>'+
    4047                                                                 '<li>'+
    4048                                                                         '<input type="radio" name="' + player.id + '_captions" id="' + player.id + '_captions_none" value="none" checked="checked" />' +
    4049                                                                         '<label for="' + player.id + '_captions_none">None</label>'+
    4050                                                                 '</li>' +
    4051                                                         '</ul>'+
    4052                                                 '</div>'+
    4053                                         '</div>')
    4054                                                 .appendTo(controls);
    4055 
    4056 
    4057                         var subtitleCount = 0;
    4058                         for (i=0; i<player.tracks.length; i++) {
    4059                                 if (player.tracks[i].kind == 'subtitles') {
    4060                                         subtitleCount++;
    4061                                 }
    4062                         }
    4063 
    4064                         // if only one language then just make the button a toggle
    4065                         if (t.options.toggleCaptionsButtonWhenOnlyOne && subtitleCount == 1){
    4066                                 // click
    4067                                 player.captionsButton.on('click',function() {
    4068                                         if (player.selectedTrack == null) {
    4069                                                 var lang = player.tracks[0].srclang;
    4070                                         } else {
    4071                                                 var lang = 'none';
    4072                                         }
    4073                                         player.setTrack(lang);
    4074                                 });
    4075                         } else {
    4076                                 // hover
    4077                                 player.captionsButton.hover(function() {
    4078                                         $(this).find('.mejs-captions-selector').css('visibility','visible');
    4079                                 }, function() {
    4080                                         $(this).find('.mejs-captions-selector').css('visibility','hidden');
    4081                                 })
    4082 
    4083                                 // handle clicks to the language radio buttons
    4084                                 .on('click','input[type=radio]',function() {
    4085                                         lang = this.value;
    4086                                         player.setTrack(lang);
    4087                                 });
    4088 
    4089                         }
    4090 
    4091                         if (!player.options.alwaysShowControls) {
    4092                                 // move with controls
    4093                                 player.container
    4094                                         .bind('controlsshown', function () {
    4095                                                 // push captions above controls
    4096                                                 player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
    4097 
    4098                                         })
    4099                                         .bind('controlshidden', function () {
    4100                                                 if (!media.paused) {
    4101                                                         // move back to normal place
    4102                                                         player.container.find('.mejs-captions-position').removeClass('mejs-captions-position-hover');
    4103                                                 }
    4104                                         });
    4105                         } else {
    4106                                 player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
    4107                         }
    4108 
    4109                         player.trackToLoad = -1;
    4110                         player.selectedTrack = null;
    4111                         player.isLoadingTrack = false;
    4112 
    4113 
    4114 
    4115                         // add to list
    4116                         for (i=0; i<player.tracks.length; i++) {
    4117                                 if (player.tracks[i].kind == 'subtitles') {
    4118                                         player.addTrackButton(player.tracks[i].srclang, player.tracks[i].label);
    4119                                 }
    4120                         }
    4121 
    4122                         // start loading tracks
    4123                         player.loadNextTrack();
    4124 
    4125 
    4126                         media.addEventListener('timeupdate',function(e) {
    4127                                 player.displayCaptions();
    4128                         }, false);
    4129 
    4130                         if (player.options.slidesSelector != '') {
    4131                                 player.slidesContainer = $(player.options.slidesSelector);
    4132 
    4133                                 media.addEventListener('timeupdate',function(e) {
    4134                                         player.displaySlides();
    4135                                 }, false);
    4136 
    4137                         }
    4138 
    4139                         media.addEventListener('loadedmetadata', function(e) {
    4140                                 player.displayChapters();
    4141                         }, false);
    4142 
    4143                         player.container.hover(
    4144                                 function () {
    4145                                         // chapters
    4146                                         if (player.hasChapters) {
    4147                                                 player.chapters.css('visibility','visible');
    4148                                                 player.chapters.fadeIn(200).height(player.chapters.find('.mejs-chapter').outerHeight());
    4149                                         }
    4150                                 },
    4151                                 function () {
    4152                                         if (player.hasChapters && !media.paused) {
    4153                                                 player.chapters.fadeOut(200, function() {
    4154                                                         $(this).css('visibility','hidden');
    4155                                                         $(this).css('display','block');
    4156                                                 });
    4157                                         }
    4158                                 });
    4159 
    4160                         // check for autoplay
    4161                         if (player.node.getAttribute('autoplay') !== null) {
    4162                                 player.chapters.css('visibility','hidden');
    4163                         }
    4164                 },
    4165 
    4166                 setTrack: function(lang){
    4167 
    4168                         var t = this,
    4169                                 i;
    4170 
    4171                         if (lang == 'none') {
    4172                                 t.selectedTrack = null;
    4173                                 t.captionsButton.removeClass('mejs-captions-enabled');
    4174                         } else {
    4175                                 for (i=0; i<t.tracks.length; i++) {
    4176                                         if (t.tracks[i].srclang == lang) {
    4177                                                 if (t.selectedTrack == null)
    4178                                                     t.captionsButton.addClass('mejs-captions-enabled');
    4179                                                 t.selectedTrack = t.tracks[i];
    4180                                                 t.captions.attr('lang', t.selectedTrack.srclang);
    4181                                                 t.displayCaptions();
    4182                                                 break;
    4183                                         }
    4184                                 }
    4185                         }
    4186                 },
    4187 
    4188                 loadNextTrack: function() {
    4189                         var t = this;
    4190 
    4191                         t.trackToLoad++;
    4192                         if (t.trackToLoad < t.tracks.length) {
    4193                                 t.isLoadingTrack = true;
    4194                                 t.loadTrack(t.trackToLoad);
    4195                         } else {
    4196                                 // add done?
    4197                                 t.isLoadingTrack = false;
    4198 
    4199                                 t.checkForTracks();
    4200                         }
    4201                 },
    4202 
    4203                 loadTrack: function(index){
    4204                         var
    4205                                 t = this,
    4206                                 track = t.tracks[index],
    4207                                 after = function() {
    4208 
    4209                                         track.isLoaded = true;
    4210 
    4211                                         // create button
    4212                                         //t.addTrackButton(track.srclang);
    4213                                         t.enableTrackButton(track.srclang, track.label);
    4214 
    4215                                         t.loadNextTrack();
    4216 
    4217                                 };
    4218 
    4219 
    4220                         $.ajax({
    4221                                 url: track.src,
    4222                                 dataType: "text",
    4223                                 success: function(d) {
    4224 
    4225                                         // parse the loaded file
    4226                                         if (typeof d == "string" && (/<tt\s+xml/ig).exec(d)) {
    4227                                                 track.entries = mejs.TrackFormatParser.dfxp.parse(d);
    4228                                         } else {
    4229                                                 track.entries = mejs.TrackFormatParser.webvvt.parse(d);
    4230                                         }
    4231 
    4232                                         after();
    4233 
    4234                                         if (track.kind == 'chapters') {
    4235                                                 t.media.addEventListener('play', function(e) {
    4236                                                         if (t.media.duration > 0) {
    4237                                                                 t.displayChapters(track);
    4238                                                         }
    4239                                                 }, false);
    4240                                         }
    4241 
    4242                                         if (track.kind == 'slides') {
    4243                                                 t.setupSlides(track);
    4244                                         }
    4245                                 },
    4246                                 error: function() {
    4247                                         t.loadNextTrack();
    4248                                 }
    4249                         });
    4250                 },
    4251 
    4252                 enableTrackButton: function(lang, label) {
    4253                         var t = this;
    4254 
    4255                         if (label === '') {
    4256                                 label = mejs.language.codes[lang] || lang;
    4257                         }
    4258 
    4259                         t.captionsButton
    4260                                 .find('input[value=' + lang + ']')
    4261                                         .prop('disabled',false)
    4262                                 .siblings('label')
    4263                                         .html( label );
    4264 
    4265                         // auto select
    4266                         if (t.options.startLanguage == lang) {
    4267                                 $('#' + t.id + '_captions_' + lang).click();
    4268                         }
    4269 
    4270                         t.adjustLanguageBox();
    4271                 },
    4272 
    4273                 addTrackButton: function(lang, label) {
    4274                         var t = this;
    4275                         if (label === '') {
    4276                                 label = mejs.language.codes[lang] || lang;
    4277                         }
    4278 
    4279                         t.captionsButton.find('ul').append(
    4280                                 $('<li>'+
    4281                                         '<input type="radio" name="' + t.id + '_captions" id="' + t.id + '_captions_' + lang + '" value="' + lang + '" disabled="disabled" />' +
    4282                                         '<label for="' + t.id + '_captions_' + lang + '">' + label + ' (loading)' + '</label>'+
    4283                                 '</li>')
    4284                         );
    4285 
    4286                         t.adjustLanguageBox();
    4287 
    4288                         // remove this from the dropdownlist (if it exists)
    4289                         t.container.find('.mejs-captions-translations option[value=' + lang + ']').remove();
    4290                 },
    4291 
    4292                 adjustLanguageBox:function() {
    4293                         var t = this;
    4294                         // adjust the size of the outer box
    4295                         t.captionsButton.find('.mejs-captions-selector').height(
    4296                                 t.captionsButton.find('.mejs-captions-selector ul').outerHeight(true) +
    4297                                 t.captionsButton.find('.mejs-captions-translations').outerHeight(true)
    4298                         );
    4299                 },
    4300 
    4301                 checkForTracks: function() {
    4302                         var
    4303                                 t = this,
    4304                                 hasSubtitles = false;
    4305 
    4306                         // check if any subtitles
    4307                         if (t.options.hideCaptionsButtonWhenEmpty) {
    4308                                 for (i=0; i<t.tracks.length; i++) {
    4309                                         if (t.tracks[i].kind == 'subtitles') {
    4310                                                 hasSubtitles = true;
    4311                                                 break;
    4312                                         }
    4313                                 }
    4314 
    4315                                 if (!hasSubtitles) {
    4316                                         t.captionsButton.hide();
    4317                                         t.setControlsSize();
    4318                                 }
    4319                         }
    4320                 },
    4321 
    4322                 displayCaptions: function() {
    4323 
    4324                         if (typeof this.tracks == 'undefined')
    4325                                 return;
    4326 
    4327                         var
    4328                                 t = this,
    4329                                 i,
    4330                                 track = t.selectedTrack;
    4331 
    4332                         if (track != null && track.isLoaded) {
    4333                                 for (i=0; i<track.entries.times.length; i++) {
    4334                                         if (t.media.currentTime >= track.entries.times[i].start && t.media.currentTime <= track.entries.times[i].stop){
    4335                                                 t.captionsText.html(track.entries.text[i]);
    4336                                                 t.captions.show().height(0);
    4337                                                 return; // exit out if one is visible;
    4338                                         }
    4339                                 }
    4340                                 t.captions.hide();
    4341                         } else {
    4342                                 t.captions.hide();
    4343                         }
    4344                 },
    4345 
    4346                 setupSlides: function(track) {
    4347                         var t = this;
    4348 
    4349                         t.slides = track;
    4350                         t.slides.entries.imgs = [t.slides.entries.text.length];
    4351                         t.showSlide(0);
    4352 
    4353                 },
    4354 
    4355                 showSlide: function(index) {
    4356                         if (typeof this.tracks == 'undefined' || typeof this.slidesContainer == 'undefined') {
    4357                                 return;
    4358                         }
    4359 
    4360                         var t = this,
    4361                                 url = t.slides.entries.text[index],
    4362                                 img = t.slides.entries.imgs[index];
    4363 
    4364                         if (typeof img == 'undefined' || typeof img.fadeIn == 'undefined') {
    4365 
    4366                                 t.slides.entries.imgs[index] = img = $('<img src="' + url + '">')
    4367                                                 .on('load', function() {
    4368                                                         img.appendTo(t.slidesContainer)
    4369                                                                 .hide()
    4370                                                                 .fadeIn()
    4371                                                                 .siblings(':visible')
    4372                                                                         .fadeOut();
    4373 
    4374                                                 });
    4375 
    4376                         } else {
    4377 
    4378                                 if (!img.is(':visible') && !img.is(':animated')) {
    4379 
    4380                                         console.log('showing existing slide');
    4381 
    4382                                         img.fadeIn()
    4383                                                 .siblings(':visible')
    4384                                                         .fadeOut();
    4385                                 }
    4386                         }
    4387 
    4388                 },
    4389 
    4390                 displaySlides: function() {
    4391 
    4392                         if (typeof this.slides == 'undefined')
    4393                                 return;
    4394 
    4395                         var
    4396                                 t = this,
    4397                                 slides = t.slides,
    4398                                 i;
    4399 
    4400                         for (i=0; i<slides.entries.times.length; i++) {
    4401                                 if (t.media.currentTime >= slides.entries.times[i].start && t.media.currentTime <= slides.entries.times[i].stop){
    4402 
    4403                                         t.showSlide(i);
    4404 
    4405                                         return; // exit out if one is visible;
    4406                                 }
    4407                         }
    4408                 },
    4409 
    4410                 displayChapters: function() {
    4411                         var
    4412                                 t = this,
    4413                                 i;
    4414 
    4415                         for (i=0; i<t.tracks.length; i++) {
    4416                                 if (t.tracks[i].kind == 'chapters' && t.tracks[i].isLoaded) {
    4417                                         t.drawChapters(t.tracks[i]);
    4418                                         t.hasChapters = true;
    4419                                         break;
    4420                                 }
    4421                         }
    4422                 },
    4423 
    4424                 drawChapters: function(chapters) {
    4425                         var
    4426                                 t = this,
    4427                                 i,
    4428                                 dur,
    4429                                 //width,
    4430                                 //left,
    4431                                 percent = 0,
    4432                                 usedPercent = 0;
    4433 
    4434                         t.chapters.empty();
    4435 
    4436                         for (i=0; i<chapters.entries.times.length; i++) {
    4437                                 dur = chapters.entries.times[i].stop - chapters.entries.times[i].start;
    4438                                 percent = Math.floor(dur / t.media.duration * 100);
    4439                                 if (percent + usedPercent > 100 || // too large
    4440                                         i == chapters.entries.times.length-1 && percent + usedPercent < 100) // not going to fill it in
    4441                                         {
    4442                                         percent = 100 - usedPercent;
    4443                                 }
    4444                                 //width = Math.floor(t.width * dur / t.media.duration);
    4445                                 //left = Math.floor(t.width * chapters.entries.times[i].start / t.media.duration);
    4446                                 //if (left + width > t.width) {
    4447                                 //      width = t.width - left;
    4448                                 //}
    4449 
    4450                                 t.chapters.append( $(
    4451                                         '<div class="mejs-chapter" rel="' + chapters.entries.times[i].start + '" style="left: ' + usedPercent.toString() + '%;width: ' + percent.toString() + '%;">' +
    4452                                                 '<div class="mejs-chapter-block' + ((i==chapters.entries.times.length-1) ? ' mejs-chapter-block-last' : '') + '">' +
    4453                                                         '<span class="ch-title">' + chapters.entries.text[i] + '</span>' +
    4454                                                         '<span class="ch-time">' + mejs.Utility.secondsToTimeCode(chapters.entries.times[i].start) + '&ndash;' + mejs.Utility.secondsToTimeCode(chapters.entries.times[i].stop) + '</span>' +
    4455                                                 '</div>' +
    4456                                         '</div>'));
    4457                                 usedPercent += percent;
    4458                         }
    4459 
    4460                         t.chapters.find('div.mejs-chapter').click(function() {
    4461                                 t.media.setCurrentTime( parseFloat( $(this).attr('rel') ) );
    4462                                 if (t.media.paused) {
    4463                                         t.media.play();
    4464                                 }
    4465                         });
    4466 
    4467                         t.chapters.show();
    4468                 }
    4469         });
    4470 
    4471 
    4472 
    4473         mejs.language = {
    4474                 codes:  {
    4475                         af:'Afrikaans',
    4476                         sq:'Albanian',
    4477                         ar:'Arabic',
    4478                         be:'Belarusian',
    4479                         bg:'Bulgarian',
    4480                         ca:'Catalan',
    4481                         zh:'Chinese',
    4482                         'zh-cn':'Chinese Simplified',
    4483                         'zh-tw':'Chinese Traditional',
    4484                         hr:'Croatian',
    4485                         cs:'Czech',
    4486                         da:'Danish',
    4487                         nl:'Dutch',
    4488                         en:'English',
    4489                         et:'Estonian',
    4490                         tl:'Filipino',
    4491                         fi:'Finnish',
    4492                         fr:'French',
    4493                         gl:'Galician',
    4494                         de:'German',
    4495                         el:'Greek',
    4496                         ht:'Haitian Creole',
    4497                         iw:'Hebrew',
    4498                         hi:'Hindi',
    4499                         hu:'Hungarian',
    4500                         is:'Icelandic',
    4501                         id:'Indonesian',
    4502                         ga:'Irish',
    4503                         it:'Italian',
    4504                         ja:'Japanese',
    4505                         ko:'Korean',
    4506                         lv:'Latvian',
    4507                         lt:'Lithuanian',
    4508                         mk:'Macedonian',
    4509                         ms:'Malay',
    4510                         mt:'Maltese',
    4511                         no:'Norwegian',
    4512                         fa:'Persian',
    4513                         pl:'Polish',
    4514                         pt:'Portuguese',
    4515                         //'pt-pt':'Portuguese (Portugal)',
    4516                         ro:'Romanian',
    4517                         ru:'Russian',
    4518                         sr:'Serbian',
    4519                         sk:'Slovak',
    4520                         sl:'Slovenian',
    4521                         es:'Spanish',
    4522                         sw:'Swahili',
    4523                         sv:'Swedish',
    4524                         tl:'Tagalog',
    4525                         th:'Thai',
    4526                         tr:'Turkish',
    4527                         uk:'Ukrainian',
    4528                         vi:'Vietnamese',
    4529                         cy:'Welsh',
    4530                         yi:'Yiddish'
    4531                 }
    4532         };
    4533 
    4534         /*
    4535         Parses WebVVT format which should be formatted as
    4536         ================================
    4537         WEBVTT
    4538 
    4539         1
    4540         00:00:01,1 --> 00:00:05,000
    4541         A line of text
    4542 
    4543         2
    4544         00:01:15,1 --> 00:02:05,000
    4545         A second line of text
    4546 
    4547         ===============================
    4548 
    4549         Adapted from: http://www.delphiki.com/html5/playr
    4550         */
    4551         mejs.TrackFormatParser = {
    4552                 webvvt: {
    4553                         // match start "chapter-" (or anythingelse)
    4554                         pattern_identifier: /^([a-zA-z]+-)?[0-9]+$/,
    4555                         pattern_timecode: /^([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,
    4556 
    4557                         parse: function(trackText) {
    4558                                 var
    4559                                         i = 0,
    4560                                         lines = mejs.TrackFormatParser.split2(trackText, /\r?\n/),
    4561                                         entries = {text:[], times:[]},
    4562                                         timecode,
    4563                                         text;
    4564                                 for(; i<lines.length; i++) {
    4565                                         // check for the line number
    4566                                         if (this.pattern_identifier.exec(lines[i])){
    4567                                                 // skip to the next line where the start --> end time code should be
    4568                                                 i++;
    4569                                                 timecode = this.pattern_timecode.exec(lines[i]);
    4570 
    4571                                                 if (timecode && i<lines.length){
    4572                                                         i++;
    4573                                                         // grab all the (possibly multi-line) text that follows
    4574                                                         text = lines[i];
    4575                                                         i++;
    4576                                                         while(lines[i] !== '' && i<lines.length){
    4577                                                                 text = text + '\n' + lines[i];
    4578                                                                 i++;
    4579                                                         }
    4580                                                         text = $.trim(text).replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig, "<a href='$1' target='_blank'>$1</a>");
    4581                                                         // Text is in a different array so I can use .join
    4582                                                         entries.text.push(text);
    4583                                                         entries.times.push(
    4584                                                         {
    4585                                                                 start: (mejs.Utility.convertSMPTEtoSeconds(timecode[1]) == 0) ? 0.200 : mejs.Utility.convertSMPTEtoSeconds(timecode[1]),
    4586                                                                 stop: mejs.Utility.convertSMPTEtoSeconds(timecode[3]),
    4587                                                                 settings: timecode[5]
    4588                                                         });
    4589                                                 }
    4590                                         }
    4591                                 }
    4592                                 return entries;
    4593                         }
    4594                 },
    4595                 // Thanks to Justin Capella: https://github.com/johndyer/mediaelement/pull/420
    4596                 dfxp: {
    4597                         parse: function(trackText) {
    4598                                 trackText = $(trackText).filter("tt");
    4599                                 var
    4600                                         i = 0,
    4601                                         container = trackText.children("div").eq(0),
    4602                                         lines = container.find("p"),
    4603                                         styleNode = trackText.find("#" + container.attr("style")),
    4604                                         styles,
    4605                                         begin,
    4606                                         end,
    4607                                         text,
    4608                                         entries = {text:[], times:[]};
    4609 
    4610 
    4611                                 if (styleNode.length) {
    4612                                         var attributes = styleNode.removeAttr("id").get(0).attributes;
    4613                                         if (attributes.length) {
    4614                                                 styles = {};
    4615                                                 for (i = 0; i < attributes.length; i++) {
    4616                                                         styles[attributes[i].name.split(":")[1]] = attributes[i].value;
    4617                                                 }
    4618