1/*! 2* MediaElement.js 3* HTML5 <video> and <audio> shim and player 4* http://mediaelementjs.com/ 5* 6* Creates a JavaScript object that mimics HTML5 MediaElement API 7* for browsers that don't understand HTML5 or can't play the provided codec 8* Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3 9* 10* Copyright 2010-2012, John Dyer (http://j.hn) 11* Dual licensed under the MIT or GPL Version 2 licenses. 12* 13*/ 14// Namespace 15var mejs = mejs || {}; 16 17// version number 18mejs.version = '2.9.1'; 19 20// player number (for missing, same id attr) 21mejs.meIndex = 0; 22 23// media types accepted by plugins 24mejs.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/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']} 34 ], 35 vimeo: [ 36 {version: null, types: ['video/vimeo']} 37 ] 38}; 39 40/* 41Utility methods 42*/ 43mejs.Utility = { 44 encodeUrl: function(url) { 45 return encodeURIComponent(url); //.replace(/\?/gi,'%3F').replace(/=/gi,'%3D').replace(/&/gi,'%26'); 46 }, 47 escapeHTML: function(s) { 48 return s.toString().split('&').join('&').split('<').join('<').split('"').join('"'); 49 }, 50 absolutizeUrl: function(url) { 51 var el = document.createElement('div'); 52 el.innerHTML = '<a href="' + this.escapeHTML(url) + '">x</a>'; 53 return el.firstChild.href; 54 }, 55 getScriptPath: function(scriptNames) { 56 var 57 i = 0, 58 j, 59 path = '', 60 name = '', 61 script, 62 scripts = document.getElementsByTagName('script'), 63 il = scripts.length, 64 jl = scriptNames.length; 65 66 for (; i < il; i++) { 67 script = scripts[i].src; 68 for (j = 0; j < jl; j++) { 69 name = scriptNames[j]; 70 if (script.indexOf(name) > -1) { 71 path = script.substring(0, script.indexOf(name)); 72 break; 73 } 74 } 75 if (path !== '') { 76 break; 77 } 78 } 79 return path; 80 }, 81 secondsToTimeCode: function(time, forceHours, showFrameCount, fps) { 82 //add framecount 83 if (typeof showFrameCount == 'undefined') { 84 showFrameCount=false; 85 } else if(typeof fps == 'undefined') { 86 fps = 25; 87 } 88 89 var hours = Math.floor(time / 3600) % 24, 90 minutes = Math.floor(time / 60) % 60, 91 seconds = Math.floor(time % 60), 92 frames = Math.floor(((time % 1)*fps).toFixed(3)), 93 result = 94 ( (forceHours || hours > 0) ? (hours < 10 ? '0' + hours : hours) + ':' : '') 95 + (minutes < 10 ? '0' + minutes : minutes) + ':' 96 + (seconds < 10 ? '0' + seconds : seconds) 97 + ((showFrameCount) ? ':' + (frames < 10 ? '0' + frames : frames) : ''); 98 99 return result; 100 }, 101 102 timeCodeToSeconds: function(hh_mm_ss_ff, forceHours, showFrameCount, fps){ 103 if (typeof showFrameCount == 'undefined') { 104 showFrameCount=false; 105 } else if(typeof fps == 'undefined') { 106 fps = 25; 107 } 108 109 var tc_array = hh_mm_ss_ff.split(":"), 110 tc_hh = parseInt(tc_array[0], 10), 111 tc_mm = parseInt(tc_array[1], 10), 112 tc_ss = parseInt(tc_array[2], 10), 113 tc_ff = 0, 114 tc_in_seconds = 0; 115 116 if (showFrameCount) { 117 tc_ff = parseInt(tc_array[3])/fps; 118 } 119 120 tc_in_seconds = ( tc_hh * 3600 ) + ( tc_mm * 60 ) + tc_ss + tc_ff; 121 122 return tc_in_seconds; 123 }, 124 125 /* borrowed from SWFObject: http://code.google.com/p/swfobject/source/browse/trunk/swfobject/src/swfobject.js#474 */ 126 removeSwf: function(id) { 127 var obj = document.getElementById(id); 128 if (obj && obj.nodeName == "OBJECT") { 129 if (mejs.MediaFeatures.isIE) { 130 obj.style.display = "none"; 131 (function(){ 132 if (obj.readyState == 4) { 133 mejs.Utility.removeObjectInIE(id); 134 } else { 135 setTimeout(arguments.callee, 10); 136 } 137 })(); 138 } else { 139 obj.parentNode.removeChild(obj); 140 } 141 } 142 }, 143 removeObjectInIE: function(id) { 144 var obj = document.getElementById(id); 145 if (obj) { 146 for (var i in obj) { 147 if (typeof obj[i] == "function") { 148 obj[i] = null; 149 } 150 } 151 obj.parentNode.removeChild(obj); 152 } 153 } 154}; 155 156 157// Core detector, plugins are added below 158mejs.PluginDetector = { 159 160 // main public function to test a plug version number PluginDetector.hasPluginVersion('flash',[9,0,125]); 161 hasPluginVersion: function(plugin, v) { 162 var pv = this.plugins[plugin]; 163 v[1] = v[1] || 0; 164 v[2] = v[2] || 0; 165 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;
166 }, 167 168 // cached values 169 nav: window.navigator, 170 ua: window.navigator.userAgent.toLowerCase(), 171 172 // stored version numbers 173 plugins: [], 174 175 // runs detectPlugin() and stores the version number 176 addPlugin: function(p, pluginName, mimeType, activeX, axDetect) { 177 this.plugins[p] = this.detectPlugin(pluginName, mimeType, activeX, axDetect); 178 }, 179 180 // get the version number from the mimetype (all but IE) or ActiveX (IE) 181 detectPlugin: function(pluginName, mimeType, activeX, axDetect) { 182 183 var version = [0,0,0], 184 description, 185 i, 186 ax; 187 188 // Firefox, Webkit, Opera 189 if (typeof(this.nav.plugins) != 'undefined' && typeof this.nav.plugins[pluginName] == 'object') { 190 description = this.nav.plugins[pluginName].description; 191 if (description && !(typeof this.nav.mimeTypes != 'undefined' && this.nav.mimeTypes[mimeType] && !this.nav.mimeTypes[mimeType].enabledPlugin)) { 192 version = description.replace(pluginName, '').replace(/^\s+/,'').replace(/\sr/gi,'.').split('.'); 193 for (i=0; i<version.length; i++) { 194 version[i] = parseInt(version[i].match(/\d+/), 10); 195 } 196 } 197 // Internet Explorer / ActiveX 198 } else if (typeof(window.ActiveXObject) != 'undefined') { 199 try { 200 ax = new ActiveXObject(activeX); 201 if (ax) { 202 version = axDetect(ax); 203 } 204 } 205 catch (e) { } 206 } 207 return version; 208 } 209}; 210 211// Add Flash detection 212mejs.PluginDetector.addPlugin('flash','Shockwave Flash','application/x-shockwave-flash','ShockwaveFlash.ShockwaveFlash', function(ax) { 213 // adapted from SWFObject 214 var version = [], 215 d = ax.GetVariable("$version"); 216 if (d) { 217 d = d.split(" ")[1].split(","); 218 version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; 219 } 220 return version; 221}); 222 223// Add Silverlight detection 224mejs.PluginDetector.addPlugin('silverlight','Silverlight Plug-In','application/x-silverlight-2','AgControl.AgControl', function (ax) { 225 // Silverlight cannot report its version number to IE 226 // but it does have a isVersionSupported function, so we have to loop through it to get a version number. 227 // adapted from http://www.silverlightversion.com/ 228 var v = [0,0,0,0], 229 loopMatch = function(ax, v, i, n) { 230 while(ax.isVersionSupported(v[0]+ "."+ v[1] + "." + v[2] + "." + v[3])){ 231 v[i]+=n; 232 } 233 v[i] -= n; 234 }; 235 loopMatch(ax, v, 0, 1); 236 loopMatch(ax, v, 1, 1); 237 loopMatch(ax, v, 2, 10000); // the third place in the version number is usually 5 digits (4.0.xxxxx) 238 loopMatch(ax, v, 2, 1000); 239 loopMatch(ax, v, 2, 100); 240 loopMatch(ax, v, 2, 10); 241 loopMatch(ax, v, 2, 1); 242 loopMatch(ax, v, 3, 1); 243 244 return v; 245}); 246// add adobe acrobat 247/* 248PluginDetector.addPlugin('acrobat','Adobe Acrobat','application/pdf','AcroPDF.PDF', function (ax) { 249 var version = [], 250 d = ax.GetVersions().split(',')[0].split('=')[1].split('.'); 251 252 if (d) { 253 version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)]; 254 } 255 return version; 256}); 257*/ 258// necessary detection (fixes for <IE9) 259mejs.MediaFeatures = { 260 init: function() { 261 var 262 t = this, 263 d = document, 264 nav = mejs.PluginDetector.nav, 265 ua = mejs.PluginDetector.ua.toLowerCase(), 266 i, 267 v, 268 html5Elements = ['source','track','audio','video']; 269 270 // detect browsers (only the ones that have some kind of quirk we need to work around) 271 t.isiPad = (ua.match(/ipad/i) !== null); 272 t.isiPhone = (ua.match(/iphone/i) !== null); 273 t.isiOS = t.isiPhone || t.isiPad; 274 t.isAndroid = (ua.match(/android/i) !== null); 275 t.isBustedAndroid = (ua.match(/android 2\.[12]/) !== null); 276 t.isIE = (nav.appName.toLowerCase().indexOf("microsoft") != -1); 277 t.isChrome = (ua.match(/chrome/gi) !== null); 278 t.isFirefox = (ua.match(/firefox/gi) !== null); 279 t.isWebkit = (ua.match(/webkit/gi) !== null); 280 t.isGecko = (ua.match(/gecko/gi) !== null) && !t.isWebkit; 281 t.isOpera = (ua.match(/opera/gi) !== null); 282 t.hasTouch = ('ontouchstart' in window); 283 284 // create HTML5 media elements for IE before 9, get a <video> element for fullscreen detection 285 for (i=0; i<html5Elements.length; i++) { 286 v = document.createElement(html5Elements[i]); 287 } 288 289 t.supportsMediaTag = (typeof v.canPlayType !== 'undefined' || t.isBustedAndroid); 290 291 // detect native JavaScript fullscreen (Safari/Firefox only, Chrome still fails) 292 293 // iOS 294 t.hasSemiNativeFullScreen = (typeof v.webkitEnterFullscreen !== 'undefined'); 295 296 // Webkit/firefox 297 t.hasWebkitNativeFullScreen = (typeof v.webkitRequestFullScreen !== 'undefined'); 298 t.hasMozNativeFullScreen = (typeof v.mozRequestFullScreen !== 'undefined'); 299 300 t.hasTrueNativeFullScreen = (t.hasWebkitNativeFullScreen || t.hasMozNativeFullScreen); 301 t.nativeFullScreenEnabled = t.hasTrueNativeFullScreen; 302 if (t.hasMozNativeFullScreen) { 303 t.nativeFullScreenEnabled = v.mozFullScreenEnabled; 304 } 305 306 307 if (this.isChrome) { 308 t.hasSemiNativeFullScreen = false;
309 } 310 311 if (t.hasTrueNativeFullScreen) { 312 t.fullScreenEventName = (t.hasWebkitNativeFullScreen) ? 'webkitfullscreenchange' : 'mozfullscreenchange'; 313 314 315 t.isFullScreen = function() { 316 if (v.mozRequestFullScreen) { 317 return d.mozFullScreen; 318 } else if (v.webkitRequestFullScreen) { 319 return d.webkitIsFullScreen; 320 } 321 } 322 323 t.requestFullScreen = function(el) { 324 325 if (t.hasWebkitNativeFullScreen) { 326 el.webkitRequestFullScreen(); 327 } else if (t.hasMozNativeFullScreen) { 328 el.mozRequestFullScreen(); 329 } 330 } 331 332 t.cancelFullScreen = function() { 333 if (t.hasWebkitNativeFullScreen) { 334 document.webkitCancelFullScreen(); 335 } else if (t.hasMozNativeFullScreen) { 336 document.mozCancelFullScreen(); 337 } 338 } 339 340 } 341 342 343 // OS X 10.5 can't do this even if it says it can :( 344 if (t.hasSemiNativeFullScreen && ua.match(/mac os x 10_5/i)) { 345 t.hasNativeFullScreen = false; 346 t.hasSemiNativeFullScreen = false; 347 } 348 349 } 350}; 351mejs.MediaFeatures.init(); 352 353 354/* 355extension methods to <video> or <audio> object to bring it into parity with PluginMediaElement (see below) 356*/ 357mejs.HtmlMediaElement = { 358 pluginType: 'native', 359 isFullScreen: false, 360 361 setCurrentTime: function (time) { 362 this.currentTime = time; 363 }, 364 365 setMuted: function (muted) { 366 this.muted = muted; 367 }, 368 369 setVolume: function (volume) { 370 this.volume = volume; 371 }, 372 373 // for parity with the plugin versions 374 stop: function () { 375 this.pause(); 376 }, 377 378 // This can be a url string 379 // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}] 380 setSrc: function (url) { 381 382 // Fix for IE9 which can't set .src when there are <source> elements. Awesome, right? 383 var 384 existingSources = this.getElementsByTagName('source'); 385 while (existingSources.length > 0){ 386 this.removeChild(existingSources[0]); 387 } 388 389 if (typeof url == 'string') { 390 this.src = url; 391 } else { 392 var i, media; 393 394 for (i=0; i<url.length; i++) { 395 media = url[i]; 396 if (this.canPlayType(media.type)) { 397 this.src = media.src; 398 } 399 } 400 } 401 }, 402 403 setVideoSize: function (width, height) { 404 this.width = width; 405 this.height = height; 406 } 407}; 408 409/* 410Mimics the <video/audio> element by calling Flash's External Interface or Silverlights [ScriptableMember] 411*/ 412mejs.PluginMediaElement = function (pluginid, pluginType, mediaUrl) { 413 this.id = pluginid; 414 this.pluginType = pluginType; 415 this.src = mediaUrl; 416 this.events = {}; 417}; 418 419// JavaScript values and ExternalInterface methods that match HTML5 video properties methods 420// http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/fl/video/FLVPlayback.html 421// http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html 422mejs.PluginMediaElement.prototype = { 423 424 // special 425 pluginElement: null, 426 pluginType: '', 427 isFullScreen: false, 428 429 // not implemented :( 430 playbackRate: -1, 431 defaultPlaybackRate: -1, 432 seekable: [], 433 played: [], 434 435 // HTML5 read-only properties 436 paused: true, 437 ended: false, 438 seeking: false, 439 duration: 0, 440 error: null, 441 tagName: '', 442 443 // HTML5 get/set properties, but only set (updated by event handlers) 444 muted: false, 445 volume: 1, 446 currentTime: 0, 447 448 // HTML5 methods 449 play: function () { 450 if (this.pluginApi != null) { 451 if (this.pluginType == 'youtube') { 452 this.pluginApi.playVideo(); 453 } else { 454 this.pluginApi.playMedia(); 455 } 456 this.paused = false; 457 } 458 }, 459 load: function () { 460 if (this.pluginApi != null) { 461 if (this.pluginType == 'youtube') { 462 } else { 463 this.pluginApi.loadMedia(); 464 } 465 466 this.paused = false; 467 } 468 }, 469 pause: function () { 470 if (this.pluginApi != null) { 471 if (this.pluginType == 'youtube') { 472 this.pluginApi.pauseVideo(); 473 } else { 474 this.pluginApi.pauseMedia(); 475 } 476 477 478 this.paused = true; 479 } 480 }, 481 stop: function () { 482 if (this.pluginApi != null) { 483 if (this.pluginType == 'youtube') { 484 this.pluginApi.stopVideo(); 485 } else { 486 this.pluginApi.stopMedia(); 487 } 488 this.paused = true; 489 } 490 }, 491 canPlayType: function(type) { 492 var i, 493 j, 494 pluginInfo, 495 pluginVersions = mejs.plugins[this.pluginType]; 496 497 for (i=0; i<pluginVersions.length; i++) { 498 pluginInfo = pluginVersions[i]; 499 500 // test if user has the correct plugin version 501 if (mejs.PluginDetector.hasPluginVersion(this.pluginType, pluginInfo.version)) { 502 503 // test for plugin playback types 504 for (j=0; j<pluginInfo.types.length; j++) { 505 // find plugin that can play the type 506 if (type == pluginInfo.types[j]) { 507 return true; 508 } 509 } 510 } 511 } 512 513 return false;
514 }, 515 516 positionFullscreenButton: function(x,y,visibleAndAbove) { 517 if (this.pluginApi != null && this.pluginApi.positionFullscreenButton) { 518 this.pluginApi.positionFullscreenButton(x,y,visibleAndAbove); 519 } 520 }, 521 522 hideFullscreenButton: function() { 523 if (this.pluginApi != null && this.pluginApi.hideFullscreenButton) { 524 this.pluginApi.hideFullscreenButton(); 525 } 526 }, 527 528 529 // custom methods since not all JavaScript implementations support get/set 530 531 // This can be a url string 532 // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}] 533 setSrc: function (url) { 534 if (typeof url == 'string') { 535 this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(url)); 536 this.src = mejs.Utility.absolutizeUrl(url); 537 } else { 538 var i, media; 539 540 for (i=0; i<url.length; i++) { 541 media = url[i]; 542 if (this.canPlayType(media.type)) { 543 this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(media.src)); 544 this.src = mejs.Utility.absolutizeUrl(url); 545 } 546 } 547 } 548 549 }, 550 setCurrentTime: function (time) { 551 if (this.pluginApi != null) { 552 if (this.pluginType == 'youtube') { 553 this.pluginApi.seekTo(time); 554 } else { 555 this.pluginApi.setCurrentTime(time); 556 } 557 558 559 560 this.currentTime = time; 561 } 562 }, 563 setVolume: function (volume) { 564 if (this.pluginApi != null) { 565 // same on YouTube and MEjs 566 if (this.pluginType == 'youtube') { 567 this.pluginApi.setVolume(volume * 100); 568 } else { 569 this.pluginApi.setVolume(volume); 570 } 571 this.volume = volume; 572 } 573 }, 574 setMuted: function (muted) { 575 if (this.pluginApi != null) { 576 if (this.pluginType == 'youtube') { 577 if (muted) { 578 this.pluginApi.mute(); 579 } else { 580 this.pluginApi.unMute(); 581 } 582 this.muted = muted; 583 this.dispatchEvent('volumechange'); 584 } else { 585 this.pluginApi.setMuted(muted); 586 } 587 this.muted = muted; 588 } 589 }, 590 591 // additional non-HTML5 methods 592 setVideoSize: function (width, height) { 593 594 //if (this.pluginType == 'flash' || this.pluginType == 'silverlight') { 595 if ( this.pluginElement.style) { 596 this.pluginElement.style.width = width + 'px'; 597 this.pluginElement.style.height = height + 'px'; 598 } 599 if (this.pluginApi != null && this.pluginApi.setVideoSize) { 600 this.pluginApi.setVideoSize(width, height); 601 } 602 //} 603 }, 604 605 setFullscreen: function (fullscreen) { 606 if (this.pluginApi != null && this.pluginApi.setFullscreen) { 607 this.pluginApi.setFullscreen(fullscreen); 608 } 609 }, 610 611 enterFullScreen: function() { 612 if (this.pluginApi != null && this.pluginApi.setFullscreen) { 613 this.setFullscreen(true); 614 } 615 616 }, 617 618 exitFullScreen: function() { 619 if (this.pluginApi != null && this.pluginApi.setFullscreen) { 620 this.setFullscreen(false); 621 } 622 }, 623 624 // start: fake events 625 addEventListener: function (eventName, callback, bubble) { 626 this.events[eventName] = this.events[eventName] || []; 627 this.events[eventName].push(callback); 628 }, 629 removeEventListener: function (eventName, callback) { 630 if (!eventName) { this.events = {}; return true; } 631 var callbacks = this.events[eventName]; 632 if (!callbacks) return true; 633 if (!callback) { this.events[eventName] = []; return true; } 634 for (i = 0; i < callbacks.length; i++) { 635 if (callbacks[i] === callback) { 636 this.events[eventName].splice(i, 1); 637 return true; 638 } 639 } 640 return false; 641 }, 642 dispatchEvent: function (eventName) { 643 var i, 644 args, 645 callbacks = this.events[eventName]; 646 647 if (callbacks) { 648 args = Array.prototype.slice.call(arguments, 1); 649 for (i = 0; i < callbacks.length; i++) { 650 callbacks[i].apply(null, args); 651 } 652 } 653 }, 654 // end: fake events 655 656 // fake DOM attribute methods 657 attributes: {}, 658 hasAttribute: function(name){ 659 return (name in this.attributes); 660 }, 661 removeAttribute: function(name){ 662 delete this.attributes[name]; 663 }, 664 getAttribute: function(name){ 665 if (this.hasAttribute(name)) { 666 return this.attributes[name]; 667 } 668 return ''; 669 }, 670 setAttribute: function(name, value){ 671 this.attributes[name] = value; 672 }, 673 674 remove: function() { 675 mejs.Utility.removeSwf(this.pluginElement.id); 676 } 677}; 678 679// Handles calls from Flash/Silverlight and reports them as native <video/audio> events and properties 680mejs.MediaPluginBridge = { 681 682 pluginMediaElements:{}, 683 htmlMediaElements:{}, 684 685 registerPluginElement: function (id, pluginMediaElement, htmlMediaElement) { 686 this.pluginMediaElements[id] = pluginMediaElement; 687 this.htmlMediaElements[id] = htmlMediaElement; 688 }, 689 690 // when Flash/Silverlight is ready, it calls out to this method 691 initPlugin: function (id) { 692 693 var pluginMediaElement = this.pluginMediaElements[id], 694 htmlMediaElement = this.htmlMediaElements[id]; 695 696 if (pluginMediaElement) { 697 // find the javascript bridge 698 switch (pluginMediaElement.pluginType) { 699 case "flash": 700 pluginMediaElement.pluginElement = pluginMediaElement.pluginApi = document.getElementById(id); 701 break; 702 case "silverlight": 703 pluginMediaElement.pluginElement = document.getElementById(pluginMediaElement.id); 704 pluginMediaElement.pluginApi = pluginMediaElement.pluginElement.Content.MediaElementJS; 705 break; 706 } 707 708 if (pluginMediaElement.pluginApi != null && pluginMediaElement.success) { 709 pluginMediaElement.success(pluginMediaElement, htmlMediaElement); 710 } 711 } 712 }, 713 714 // receives events from Flash/Silverlight and sends them out as HTML5 media events 715 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html 716 fireEvent: function (id, eventName, values) { 717 718 var 719 e, 720 i, 721 bufferedTime, 722 pluginMediaElement = this.pluginMediaElements[id]; 723 724 pluginMediaElement.ended = false;
725 pluginMediaElement.paused = true; 726 727 // fake event object to mimic real HTML media event. 728 e = { 729 type: eventName, 730 target: pluginMediaElement 731 }; 732 733 // attach all values to element and event object 734 for (i in values) { 735 pluginMediaElement[i] = values[i]; 736 e[i] = values[i]; 737 } 738 739 // fake the newer W3C buffered TimeRange (loaded and total have been removed) 740 bufferedTime = values.bufferedTime || 0; 741 742 e.target.buffered = e.buffered = { 743 start: function(index) { 744 return 0; 745 }, 746 end: function (index) { 747 return bufferedTime; 748 }, 749 length: 1 750 }; 751 752 pluginMediaElement.dispatchEvent(e.type, e); 753 } 754}; 755 756/* 757Default options 758*/ 759mejs.MediaElementDefaults = { 760 // allows testing on HTML5, flash, silverlight 761 // auto: attempts to detect what the browser can do 762 // native: forces HTML5 playback 763 // shim: disallows HTML5, will attempt either Flash or Silverlight 764 // none: forces fallback view 765 mode: 'auto', 766 // remove or reorder to change plugin priority and availability 767 plugins: ['flash','silverlight','youtube','vimeo'], 768 // shows debug errors on screen 769 enablePluginDebug: false, 770 // overrides the type specified, useful for dynamic instantiation 771 type: '', 772 // path to Flash and Silverlight plugins 773 pluginPath: mejs.Utility.getScriptPath(['mediaelement.js','mediaelement.min.js','mediaelement-and-player.js','mediaelement-and-player.min.js']), 774 // name of flash file 775 flashName: 'flashmediaelement.swf', 776 // turns on the smoothing filter in Flash 777 enablePluginSmoothing: false, 778 // name of silverlight file 779 silverlightName: 'silverlightmediaelement.xap', 780 // default if the <video width> is not specified 781 defaultVideoWidth: 480, 782 // default if the <video height> is not specified 783 defaultVideoHeight: 270, 784 // overrides <video width> 785 pluginWidth: -1, 786 // overrides <video height> 787 pluginHeight: -1, 788 // additional plugin variables in 'key=value' form 789 pluginVars: [], 790 // rate in milliseconds for Flash and Silverlight to fire the timeupdate event 791 // larger number is less accurate, but less strain on plugin->JavaScript bridge 792 timerRate: 250, 793 // initial volume for player 794 startVolume: 0.8, 795 success: function () { }, 796 error: function () { } 797}; 798 799/* 800Determines if a browser supports the <video> or <audio> element 801and returns either the native element or a Flash/Silverlight version that 802mimics HTML5 MediaElement 803*/ 804mejs.MediaElement = function (el, o) { 805 return mejs.HtmlMediaElementShim.create(el,o); 806}; 807 808mejs.HtmlMediaElementShim = { 809 810 create: function(el, o) { 811 var 812 options = mejs.MediaElementDefaults, 813 htmlMediaElement = (typeof(el) == 'string') ? document.getElementById(el) : el, 814 tagName = htmlMediaElement.tagName.toLowerCase(), 815 isMediaTag = (tagName === 'audio' || tagName === 'video'), 816 src = (isMediaTag) ? htmlMediaElement.getAttribute('src') : htmlMediaElement.getAttribute('href'), 817 poster = htmlMediaElement.getAttribute('poster'), 818 autoplay = htmlMediaElement.getAttribute('autoplay'), 819 preload = htmlMediaElement.getAttribute('preload'), 820 controls = htmlMediaElement.getAttribute('controls'), 821 playback, 822 prop; 823 824 // extend options 825 for (prop in o) { 826 options[prop] = o[prop]; 827 } 828 829 // clean up attributes 830 src = (typeof src == 'undefined' || src === null || src == '') ? null : src; 831 poster = (typeof poster == 'undefined' || poster === null) ? '' : poster; 832 preload = (typeof preload == 'undefined' || preload === null || preload === 'false') ? 'none' : preload; 833 autoplay = !(typeof autoplay == 'undefined' || autoplay === null || autoplay === 'false'); 834 controls = !(typeof controls == 'undefined' || controls === null || controls === 'false'); 835 836 // test for HTML5 and plugin capabilities 837 playback = this.determinePlayback(htmlMediaElement, options, mejs.MediaFeatures.supportsMediaTag, isMediaTag, src); 838 playback.url = (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : ''; 839 840 if (playback.method == 'native') { 841 // second fix for android 842 if (mejs.MediaFeatures.isBustedAndroid) { 843 htmlMediaElement.src = playback.url; 844 htmlMediaElement.addEventListener('click', function() { 845 htmlMediaElement.play(); 846 }, false); 847 } 848 849 // add methods to native HTMLMediaElement 850 return this.updateNative(playback, options, autoplay, preload); 851 } else if (playback.method !== '') { 852 // create plugin to mimic HTMLMediaElement 853 854 return this.createPlugin( playback, options, poster, autoplay, preload, controls); 855 } else { 856 // boo, no HTML5, no Flash, no Silverlight. 857 this.createErrorMessage( playback, options, poster ); 858 859 return this; 860 } 861 }, 862 863 determinePlayback: function(htmlMediaElement, options, supportsMediaTag, isMediaTag, src) { 864 var 865 mediaFiles = [], 866 i, 867 j, 868 k, 869 l, 870 n, 871 type, 872 result = { method: '', url: '', htmlMediaElement: htmlMediaElement, isVideo: (htmlMediaElement.tagName.toLowerCase() != 'audio')}, 873 pluginName, 874 pluginVersions, 875 pluginInfo, 876 dummy; 877 878 // STEP 1: Get URL and type from <video src> or <source src> 879 880 // supplied type overrides <video type> and <source type> 881 if (typeof options.type != 'undefined' && options.type !== '') { 882 883 // accept either string or array of types 884 if (typeof options.type == 'string') { 885 mediaFiles.push({type:options.type, url:src}); 886 } else { 887 888 for (i=0; i<options.type.length; i++) { 889 mediaFiles.push({type:options.type[i], url:src}); 890 } 891 } 892 893 // test for src attribute first 894 } else if (src !== null) { 895 type = this.formatType(src, htmlMediaElement.getAttribute('type')); 896 mediaFiles.push({type:type, url:src}); 897 898 // then test for <source> elements 899 } else { 900 // test <source> types to see if they are usable 901 for (i = 0; i < htmlMediaElement.childNodes.length; i++) { 902 n = htmlMediaElement.childNodes[i]; 903 if (n.nodeType == 1 && n.tagName.toLowerCase() == 'source') { 904 src = n.getAttribute('src'); 905 type = this.formatType(src, n.getAttribute('type')); 906 mediaFiles.push({type:type, url:src}); 907 } 908 } 909 } 910 911 // in the case of dynamicly created players 912 // check for audio types 913 if (!isMediaTag && mediaFiles.length > 0 && mediaFiles[0].url !== null && this.getTypeFromFile(mediaFiles[0].url).indexOf('audio') > -1) { 914 result.isVideo = false;
915 } 916 917 918 // STEP 2: Test for playback method 919 920 // special case for Android which sadly doesn't implement the canPlayType function (always returns '') 921 if (mejs.MediaFeatures.isBustedAndroid) { 922 htmlMediaElement.canPlayType = function(type) { 923 return (type.match(/video\/(mp4|m4v)/gi) !== null) ? 'maybe' : ''; 924 }; 925 } 926 927 928 // test for native playback first 929 if (supportsMediaTag && (options.mode === 'auto' || options.mode === 'native')) { 930 931 if (!isMediaTag) { 932 933 // create a real HTML5 Media Element 934 dummy = document.createElement( result.isVideo ? 'video' : 'audio'); 935 htmlMediaElement.parentNode.insertBefore(dummy, htmlMediaElement); 936 htmlMediaElement.style.display = 'none'; 937 938 // use this one from now on 939 result.htmlMediaElement = htmlMediaElement = dummy; 940 } 941 942 for (i=0; i<mediaFiles.length; i++) { 943 // normal check 944 if (htmlMediaElement.canPlayType(mediaFiles[i].type).replace(/no/, '') !== '' 945 // special case for Mac/Safari 5.0.3 which answers '' to canPlayType('audio/mp3') but 'maybe' to canPlayType('audio/mpeg') 946 || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/,'mpeg')).replace(/no/, '') !== '') { 947 result.method = 'native'; 948 result.url = mediaFiles[i].url; 949 break; 950 } 951 } 952 953 if (result.method === 'native') { 954 if (result.url !== null) { 955 htmlMediaElement.src = result.url; 956 } 957 958 return result; 959 } 960 } 961 962 // if native playback didn't work, then test plugins 963 if (options.mode === 'auto' || options.mode === 'shim') { 964 for (i=0; i<mediaFiles.length; i++) { 965 type = mediaFiles[i].type; 966 967 // test all plugins in order of preference [silverlight, flash] 968 for (j=0; j<options.plugins.length; j++) { 969 970 pluginName = options.plugins[j]; 971 972 // test version of plugin (for future features) 973 pluginVersions = mejs.plugins[pluginName]; 974 975 for (k=0; k<pluginVersions.length; k++) { 976 pluginInfo = pluginVersions[k]; 977 978 // test if user has the correct plugin version 979 980 // for youtube/vimeo 981 if (pluginInfo.version == null || 982 983 mejs.PluginDetector.hasPluginVersion(pluginName, pluginInfo.version)) { 984 985 // test for plugin playback types 986 for (l=0; l<pluginInfo.types.length; l++) { 987 // find plugin that can play the type 988 if (type == pluginInfo.types[l]) { 989 result.method = pluginName; 990 result.url = mediaFiles[i].url; 991 return result; 992 } 993 } 994 } 995 } 996 } 997 } 998 } 999 1000 // what if there's nothing to play? just grab the first available 1001 if (result.method === '' && mediaFiles.length > 0) { 1002 result.url = mediaFiles[0].url; 1003 } 1004 1005 return result; 1006 }, 1007 1008 formatType: function(url, type) { 1009 var ext; 1010 1011 // if no type is supplied, fake it with the extension 1012 if (url && !type) { 1013 return this.getTypeFromFile(url); 1014 } else { 1015 // only return the mime part of the type in case the attribute contains the codec 1016 // see http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-source-element 1017 // `video/mp4; codecs="avc1.42E01E, mp4a.40.2"` becomes `video/mp4` 1018 1019 if (type && ~type.indexOf(';')) { 1020 return type.substr(0, type.indexOf(';')); 1021 } else { 1022 return type; 1023 } 1024 } 1025 }, 1026 1027 getTypeFromFile: function(url) { 1028 var ext = url.substring(url.lastIndexOf('.') + 1); 1029 return (/(mp4|m4v|ogg|ogv|webm|flv|wmv|mpeg|mov)/gi.test(ext) ? 'video' : 'audio') + '/' + ext; 1030 }, 1031 1032 createErrorMessage: function(playback, options, poster) { 1033 var 1034 htmlMediaElement = playback.htmlMediaElement, 1035 errorContainer = document.createElement('div'); 1036 1037 errorContainer.className = 'me-cannotplay'; 1038 1039 try { 1040 errorContainer.style.width = htmlMediaElement.width + 'px'; 1041 errorContainer.style.height = htmlMediaElement.height + 'px'; 1042 } catch (e) {} 1043 1044 errorContainer.innerHTML = (poster !== '') ? 1045 '<a href="' + playback.url + '"><img src="' + poster + '" width="100%" height="100%" /></a>' : 1046 '<a href="' + playback.url + '"><span>Download File</span></a>'; 1047 1048 htmlMediaElement.parentNode.insertBefore(errorContainer, htmlMediaElement); 1049 htmlMediaElement.style.display = 'none'; 1050 1051 options.error(htmlMediaElement); 1052 }, 1053 1054 createPlugin:function(playback, options, poster, autoplay, preload, controls) { 1055 var 1056 htmlMediaElement = playback.htmlMediaElement, 1057 width = 1, 1058 height = 1, 1059 pluginid = 'me_' + playback.method + '_' + (mejs.meIndex++), 1060 pluginMediaElement = new mejs.PluginMediaElement(pluginid, playback.method, playback.url), 1061 container = document.createElement('div'), 1062 specialIEContainer, 1063 node, 1064 initVars; 1065 1066 // copy tagName from html media element 1067 pluginMediaElement.tagName = htmlMediaElement.tagName 1068 1069 // copy attributes from html media element to plugin media element 1070 for (var i = 0; i < htmlMediaElement.attributes.length; i++) { 1071 var attribute = htmlMediaElement.attributes[i]; 1072 if (attribute.specified == true) { 1073 pluginMediaElement.setAttribute(attribute.name, attribute.value); 1074 } 1075 } 1076 1077 // check for placement inside a <p> tag (sometimes WYSIWYG editors do this) 1078 node = htmlMediaElement.parentNode; 1079 while (node !== null && node.tagName.toLowerCase() != 'body') { 1080 if (node.parentNode.tagName.toLowerCase() == 'p') { 1081 node.parentNode.parentNode.insertBefore(node, node.parentNode); 1082 break; 1083 } 1084 node = node.parentNode; 1085 } 1086 1087 if (playback.isVideo) { 1088 width = (options.videoWidth > 0) ? options.videoWidth : (htmlMediaElement.getAttribute('width') !== null) ? htmlMediaElement.getAttribute('width') : options.defaultVideoWidth; 1089 height = (options.videoHeight > 0) ? options.videoHeight : (htmlMediaElement.getAttribute('height') !== null) ? htmlMediaElement.getAttribute('height') : options.defaultVideoHeight; 1090 1091 // in case of '%' make sure it's encoded 1092 width = mejs.Utility.encodeUrl(width); 1093 height = mejs.Utility.encodeUrl(height); 1094 1095 } else { 1096 if (options.enablePluginDebug) { 1097 width = 320; 1098 height = 240; 1099 } 1100 } 1101 1102 // register plugin 1103 pluginMediaElement.success = options.success; 1104 mejs.MediaPluginBridge.registerPluginElement(pluginid, pluginMediaElement, htmlMediaElement); 1105 1106 // add container (must be added to DOM before inserting HTML for IE) 1107 container.className = 'me-plugin'; 1108 container.id = pluginid + '_container'; 1109 1110 if (playback.isVideo) { 1111 htmlMediaElement.parentNode.insertBefore(container, htmlMediaElement); 1112 } else { 1113 document.body.insertBefore(container, document.body.childNodes[0]); 1114 } 1115 1116 // flash/silverlight vars 1117 initVars = [
1118 'id=' + pluginid, 1119 'isvideo=' + ((playback.isVideo) ? "true" : "false"), 1120 'autoplay=' + ((autoplay) ? "true" : "false"), 1121 'preload=' + preload, 1122 'width=' + width, 1123 'startvolume=' + options.startVolume, 1124 'timerrate=' + options.timerRate, 1125 'height=' + height]; 1126 1127 if (playback.url !== null) { 1128 if (playback.method == 'flash') { 1129 initVars.push('file=' + mejs.Utility.encodeUrl(playback.url)); 1130 } else { 1131 initVars.push('file=' + playback.url); 1132 } 1133 } 1134 if (options.enablePluginDebug) { 1135 initVars.push('debug=true'); 1136 } 1137 if (options.enablePluginSmoothing) { 1138 initVars.push('smoothing=true'); 1139 } 1140 if (controls) { 1141 initVars.push('controls=true'); // shows controls in the plugin if desired 1142 } 1143 if (options.pluginVars) { 1144 initVars = initVars.concat(options.pluginVars); 1145 } 1146 1147 switch (playback.method) { 1148 case 'silverlight': 1149 container.innerHTML = 1150'<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '">' + 1151'<param name="initParams" value="' + initVars.join(',') + '" />' + 1152'<param name="windowless" value="true" />' + 1153'<param name="background" value="black" />' + 1154'<param name="minRuntimeVersion" value="3.0.0.0" />' + 1155'<param name="autoUpgrade" value="true" />' + 1156'<param name="source" value="' + options.pluginPath + options.silverlightName + '" />' + 1157'</object>'; 1158 break; 1159 1160 case 'flash': 1161 1162 if (mejs.MediaFeatures.isIE) { 1163 specialIEContainer = document.createElement('div'); 1164 container.appendChild(specialIEContainer); 1165 specialIEContainer.outerHTML = 1166'<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' + 1167'id="' + pluginid + '" width="' + width + '" height="' + height + '">' + 1168'<param name="movie" value="' + options.pluginPath + options.flashName + '?x=' + (new Date()) + '" />' + 1169'<param name="flashvars" value="' + initVars.join('&') + '" />' + 1170'<param name="quality" value="high" />' + 1171'<param name="bgcolor" value="#000000" />' + 1172'<param name="wmode" value="transparent" />' + 1173'<param name="allowScriptAccess" value="always" />' + 1174'<param name="allowFullScreen" value="true" />' + 1175'</object>'; 1176 1177 } else { 1178 1179 container.innerHTML = 1180'<embed id="' + pluginid + '" name="' + pluginid + '" ' + 1181'play="true" ' + 1182'loop="false" ' + 1183'quality="high" ' + 1184'bgcolor="#000000" ' + 1185'wmode="transparent" ' + 1186'allowScriptAccess="always" ' + 1187'allowFullScreen="true" ' + 1188'type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" ' + 1189'src="' + options.pluginPath + options.flashName + '" ' + 1190'flashvars="' + initVars.join('&') + '" ' + 1191'width="' + width + '" ' + 1192'height="' + height + '"></embed>'; 1193 } 1194 break; 1195 1196 case 'youtube': 1197 1198 1199 var 1200 videoId = playback.url.substr(playback.url.lastIndexOf('=')+1); 1201 youtubeSettings = { 1202 container: container, 1203 containerId: container.id, 1204 pluginMediaElement: pluginMediaElement, 1205 pluginId: pluginid, 1206 videoId: videoId, 1207 height: height, 1208 width: width 1209 }; 1210 1211 if (mejs.PluginDetector.hasPluginVersion('flash', [10,0,0]) ) { 1212 mejs.YouTubeApi.createFlash(youtubeSettings); 1213 } else { 1214 mejs.YouTubeApi.enqueueIframe(youtubeSettings); 1215 } 1216 1217 break; 1218 1219 // DEMO Code. Does NOT work. 1220 case 'vimeo': 1221 console.log('vimeoid'); 1222 1223 pluginMediaElement.vimeoid = playback.url.substr(playback.url.lastIndexOf('/')+1); 1224 1225 container.innerHTML = 1226 '<object width="' + width + '" height="' + height + '">' + 1227 '<param name="allowfullscreen" value="true" />' + 1228 '<param name="allowscriptaccess" value="always" />' + 1229 '<param name="flashvars" value="api=1" />' + 1230 '<param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=' + pluginMediaElement.vimeoid + '&server=vimeo.com&show_title=0&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&loop=0" />' + 1231 '<embed src="//vimeo.com/moogaloop.swf?api=1&clip_id=' + pluginMediaElement.vimeoid + '&server=vimeo.com&show_title=0&show_byline=0&show_portrait=0&color=00adef&fullscreen=1&autoplay=0&loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="' + width + '" height="' + height + '"></embed>' + 1232 '</object>'; 1233 1234 break; 1235 } 1236 // hide original element 1237 htmlMediaElement.style.display = 'none'; 1238 1239 // FYI: options.success will be fired by the MediaPluginBridge 1240 1241 return pluginMediaElement; 1242 }, 1243 1244 updateNative: function(playback, options, autoplay, preload) { 1245 1246 var htmlMediaElement = playback.htmlMediaElement, 1247 m; 1248 1249 1250 // add methods to video object to bring it into parity with Flash Object 1251 for (m in mejs.HtmlMediaElement) { 1252 htmlMediaElement[m] = mejs.HtmlMediaElement[m]; 1253 } 1254 1255 /* 1256 Chrome now supports preload="none" 1257 if (mejs.MediaFeatures.isChrome) { 1258 1259 // special case to enforce preload attribute (Chrome doesn't respect this) 1260 if (preload === 'none' && !autoplay) { 1261 1262 // forces the browser to stop loading (note: fails in IE9) 1263 htmlMediaElement.src = ''; 1264 htmlMediaElement.load(); 1265 htmlMediaElement.canceledPreload = true; 1266 1267 htmlMediaElement.addEventListener('play',function() { 1268 if (htmlMediaElement.canceledPreload) { 1269 htmlMediaElement.src = playback.url; 1270 htmlMediaElement.load(); 1271 htmlMediaElement.play(); 1272 htmlMediaElement.canceledPreload = false;
1273 } 1274 }, false); 1275 // for some reason Chrome forgets how to autoplay sometimes. 1276 } else if (autoplay) { 1277 htmlMediaElement.load(); 1278 htmlMediaElement.play(); 1279 } 1280 } 1281 */ 1282 1283 // fire success code 1284 options.success(htmlMediaElement, htmlMediaElement); 1285 1286 return htmlMediaElement; 1287 } 1288}; 1289 1290/* 1291 - test on IE (object vs. embed) 1292 - determine when to use iframe (Firefox, Safari, Mobile) vs. Flash (Chrome, IE) 1293 - fullscreen? 1294*/ 1295 1296// YouTube Flash and Iframe API 1297mejs.YouTubeApi = { 1298 isIframeStarted: false, 1299 isIframeLoaded: false, 1300 loadIframeApi: function() { 1301 if (!this.isIframeStarted) { 1302 var tag = document.createElement('script'); 1303 tag.src = "http://www.youtube.com/player_api"; 1304 var firstScriptTag = document.getElementsByTagName('script')[0]; 1305 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 1306 this.isIframeStarted = true; 1307 } 1308 }, 1309 iframeQueue: [], 1310 enqueueIframe: function(yt) { 1311 1312 if (this.isLoaded) { 1313 this.createIframe(yt); 1314 } else { 1315 this.loadIframeApi(); 1316 this.iframeQueue.push(yt); 1317 } 1318 }, 1319 createIframe: function(settings) { 1320 1321 var 1322 pluginMediaElement = settings.pluginMediaElement, 1323 player = new YT.Player(settings.containerId, { 1324 height: settings.height, 1325 width: settings.width, 1326 videoId: settings.videoId, 1327 playerVars: {controls:0}, 1328 events: { 1329 'onReady': function() { 1330 1331 // hook up iframe object to MEjs 1332 settings.pluginMediaElement.pluginApi = player; 1333 1334 // init mejs 1335 mejs.MediaPluginBridge.initPlugin(settings.pluginId); 1336 1337 // create timer 1338 setInterval(function() { 1339 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate'); 1340 }, 250); 1341 }, 1342 'onStateChange': function(e) { 1343 1344 mejs.YouTubeApi.handleStateChange(e.data, player, pluginMediaElement); 1345 1346 } 1347 } 1348 }); 1349 }, 1350 1351 createEvent: function (player, pluginMediaElement, eventName) { 1352 var obj = { 1353 type: eventName, 1354 target: pluginMediaElement 1355 }; 1356 1357 if (player && player.getDuration) { 1358 1359 // time 1360 pluginMediaElement.currentTime = obj.currentTime = player.getCurrentTime(); 1361 pluginMediaElement.duration = obj.duration = player.getDuration(); 1362 1363 // state 1364 obj.paused = pluginMediaElement.paused; 1365 obj.ended = pluginMediaElement.ended; 1366 1367 // sound 1368 obj.muted = player.isMuted(); 1369 obj.volume = player.getVolume() / 100; 1370 1371 // progress 1372 obj.bytesTotal = player.getVideoBytesTotal(); 1373 obj.bufferedBytes = player.getVideoBytesLoaded(); 1374 1375 // fake the W3C buffered TimeRange 1376 var bufferedTime = obj.bufferedBytes / obj.bytesTotal * obj.duration; 1377 1378 obj.target.buffered = obj.buffered = { 1379 start: function(index) { 1380 return 0; 1381 }, 1382 end: function (index) { 1383 return bufferedTime; 1384 }, 1385 length: 1 1386 }; 1387 1388 } 1389 1390 // send event up the chain 1391 pluginMediaElement.dispatchEvent(obj.type, obj); 1392 }, 1393 1394 iFrameReady: function() { 1395 1396 this.isLoaded = true; 1397 this.isIframeLoaded = true; 1398 1399 while (this.iframeQueue.length > 0) { 1400 var settings = this.iframeQueue.pop(); 1401 this.createIframe(settings); 1402 } 1403 }, 1404 1405 // FLASH! 1406 flashPlayers: {}, 1407 createFlash: function(settings) { 1408 1409 this.flashPlayers[settings.pluginId] = settings; 1410 1411 /* 1412 settings.container.innerHTML = 1413 '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="//www.youtube.com/apiplayer?enablejsapi=1&playerapiid=' + settings.pluginId + '&version=3&autoplay=0&controls=0&modestbranding=1&loop=0" ' + 1414 'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; ">' + 1415 '<param name="allowScriptAccess" value="always">' + 1416 '<param name="wmode" value="transparent">' + 1417 '</object>'; 1418 */ 1419 1420 var specialIEContainer, 1421 youtubeUrl = 'http://www.youtube.com/apiplayer?enablejsapi=1&playerapiid=' + settings.pluginId + '&version=3&autoplay=0&controls=0&modestbranding=1&loop=0'; 1422 1423 if (mejs.MediaFeatures.isIE) { 1424 1425 specialIEContainer = document.createElement('div'); 1426 settings.container.appendChild(specialIEContainer); 1427 specialIEContainer.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/s
1427hockwave/cabs/flash/swflash.cab" ' + 1428'id="' + settings.pluginId + '" width="' + settings.width + '" height="' + settings.height + '">' + 1429 '<param name="movie" value="' + youtubeUrl + '" />' + 1430 '<param name="wmode" value="transparent" />' + 1431 '<param name="allowScriptAccess" value="always" />' + 1432 '<param name="allowFullScreen" value="true" />' + 1433'</object>'; 1434 } else { 1435 settings.container.innerHTML = 1436 '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="' + youtubeUrl + '" ' + 1437 'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; ">' + 1438 '<param name="allowScriptAccess" value="always">' + 1439 '<param name="wmode" value="transparent">' + 1440 '</object>'; 1441 } 1442 1443 }, 1444 1445 flashReady: function(id) { 1446 var 1447 settings = this.flashPlayers[id], 1448 player = document.getElementById(id), 1449 pluginMediaElement = settings.pluginMediaElement; 1450 1451 // hook up and return to MediaELementPlayer.success 1452 pluginMediaElement.pluginApi = 1453 pluginMediaElement.pluginElement = player; 1454 mejs.MediaPluginBridge.initPlugin(id); 1455 1456 // load the youtube video 1457 player.cueVideoById(settings.videoId); 1458 1459 var callbackName = settings.containerId + '_callback' 1460 1461 window[callbackName] = function(e) { 1462 mejs.YouTubeApi.handleStateChange(e, player, pluginMediaElement); 1463 } 1464 1465 player.addEventListener('onStateChange', callbackName); 1466 1467 setInterval(function() { 1468 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate'); 1469 }, 250); 1470 }, 1471 1472 handleStateChange: function(youTubeState, player, pluginMediaElement) { 1473 switch (youTubeState) { 1474 case -1: // not started 1475 pluginMediaElement.paused = true; 1476 pluginMediaElement.ended = true; 1477 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'loadedmetadata'); 1478 //createYouTubeEvent(player, pluginMediaElement, 'loadeddata'); 1479 break; 1480 case 0: 1481 pluginMediaElement.paused = false; 1482 pluginMediaElement.ended = true; 1483 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'ended'); 1484 break; 1485 case 1: 1486 pluginMediaElement.paused = false; 1487 pluginMediaElement.ended = false; 1488 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'play'); 1489 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'playing'); 1490 break; 1491 case 2: 1492 pluginMediaElement.paused = true; 1493 pluginMediaElement.ended = false; 1494 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'pause'); 1495 break; 1496 case 3: // buffering 1497 mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'progress'); 1498 break; 1499 case 5: 1500 // cued? 1501 break; 1502 1503 } 1504 1505 } 1506} 1507// IFRAME 1508function onYouTubePlayerAPIReady() { 1509 mejs.YouTubeApi.iFrameReady(); 1510} 1511// FLASH 1512function onYouTubePlayerReady(id) { 1513 mejs.YouTubeApi.flashReady(id); 1514} 1515 1516window.mejs = mejs; 1517window.MediaElement = mejs.MediaElement;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.