PageSourceSearch

http://www.sunriseoceanbender.com/wp-content/themes/montreal/player/lib/mediaelement.js?ver=6.2.13

js sunriseoceanbender.com collected 2026-10-02 11:30:19 UTC 44,994 bytes, 1,517 lines download raw bytes

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('&amp;').split('<').join('&lt;').split('"').join('&quot;');
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('&amp;') + '" />' +
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  + '&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" />' +
1231						'<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 + '"></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&amp;playerapiid=' + settings.pluginId  + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;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&amp;playerapiid=' + settings.pluginId  + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;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.