PageSourceSearch

http://picasso.tokyo/_userdata/plugin/jquery-jplayer/jquery.jplayer.js

js picasso.tokyo collected 2026-10-07 03:26:20 UTC 77,228 bytes, 2,195 lines download raw bytes

vendor: 26,969 bytes, lines 1-736
1/*
2 * jPlayer Plugin for jQuery JavaScript Library
3 * http://www.jplayer.org
4 *
5 * Copyright (c) 2009 - 2011 Happyworm Ltd
6 * Dual licensed under the MIT and GPL licenses.
7 *  - http://www.opensource.org/licenses/mit-license.php
8 *  - http://www.gnu.org/copyleft/gpl.html
9 *
10 * Author: Mark J Panaghiston
11 * Version: 2.0.22
12 * Date: 13th July 2011
13 */
14
15/* Code verified using http://www.jshint.com/ */
16/*jshint asi:false, bitwise:false, boss:false, browser:true, curly:true, debug:false, eqeqeq:true, eqnull:false, evil:false, forin:false, immed:false, jquery:true, laxbreak:false, newcap:true, noarg:true, noempty:true, nonew:true, nomem:false, onevar:false, passfail:false, plusplus:false, regexp:false, undef:true, sub:false, strict:false, white:false */
17/*global jQuery:false, ActiveXObject:false, alert:false */
18
19(function($, undefined) {
20
21	// Adapted from jquery.ui.widget.js (1.8.7): $.widget.bridge
22	$.fn.jPlayer = function( options ) {
23		var name = "jPlayer";
24		var isMethodCall = typeof options === "string",
25			args = Array.prototype.slice.call( arguments, 1 ),
26			returnValue = this;
27
28		// allow multiple hashes to be passed on init
29		options = !isMethodCall && args.length ?
30			$.extend.apply( null, [ true, options ].concat(args) ) :
31			options;
32
33		// prevent calls to internal methods
34		if ( isMethodCall && options.charAt( 0 ) === "_" ) {
35			return returnValue;
36		}
37
38		if ( isMethodCall ) {
39			this.each(function() {
40				var instance = $.data( this, name ),
41					methodValue = instance && $.isFunction( instance[options] ) ?
42						instance[ options ].apply( instance, args ) :
43						instance;
44				if ( methodValue !== instance && methodValue !== undefined ) {
45					returnValue = methodValue;
46					return false;
47				}
48			});
49		} else {
50			this.each(function() {
51				var instance = $.data( this, name );
52				if ( instance ) {
53					// instance.option( options || {} )._init(); // Orig jquery.ui.widget.js code: Not recommend for jPlayer. ie., Applying new options to an existing instance (via the jPlayer constructor) and performing the _init(). The _init() is what concerns me. It would leave a lot of event handlers acting on jPlayer instance and the interface.
54					instance.option( options || {} ); // The new constructor only changes the options. Changing options only has basic support atm.
55				} else {
56					$.data( this, name, new $.jPlayer( options, this ) );
57				}
58			});
59		}
60
61		return returnValue;
62	};
63
64	$.jPlayer = function( options, element ) {
65		// allow instantiation without initializing for simple inheritance
66		if ( arguments.length ) {
67			this.element = $(element);
68			this.options = $.extend(true, {},
69				this.options,
70				options
71			);
72			var self = this;
73			this.element.bind( "remove.jPlayer", function() {
74				self.destroy();
75			});
76			this._init();
77		}
78	};
79	// End of: (Adapted from jquery.ui.widget.js (1.8.7))
80
81	// Emulated HTML5 methods and properties
82	$.jPlayer.emulateMethods = "load play pause";
83	$.jPlayer.emulateStatus = "src readyState networkState currentTime duration paused ended playbackRate";
84	$.jPlayer.emulateOptions = "muted volume";
85
86	// Reserved event names generated by jPlayer that are not part of the HTML5 Media element spec
87	$.jPlayer.reservedEvent = "ready flashreset resize repeat error warning";
88
89	// Events generated by jPlayer
90	$.jPlayer.event = {
91		ready: "jPlayer_ready",
92		flashreset: "jPlayer_flashreset", // Similar to the ready event if the Flash solution is set to display:none and then shown again or if it's reloaded for another reason by the browser. For example, using CSS position:fixed on Firefox for the full screen feature.
93		resize: "jPlayer_resize", // Occurs when the size changes through a full/restore screen operation or if the size/sizeFull options are changed.
94		repeat: "jPlayer_repeat", // Occurs when the repeat status changes. Usually through clicks on the repeat button of the interface.
95		error: "jPlayer_error", // Event error code in event.jPlayer.error.type. See $.jPlayer.error
96		warning: "jPlayer_warning", // Event warning code in event.jPlayer.warning.type. See $.jPlayer.warning
97
98		// Other events match HTML5 spec.
99		loadstart: "jPlayer_loadstart",
100		progress: "jPlayer_progress",
101		suspend: "jPlayer_suspend",
102		abort: "jPlayer_abort",
103		emptied: "jPlayer_emptied",
104		stalled: "jPlayer_stalled",
105		play: "jPlayer_play",
106		pause: "jPlayer_pause",
107		loadedmetadata: "jPlayer_loadedmetadata",
108		loadeddata: "jPlayer_loadeddata",
109		waiting: "jPlayer_waiting",
110		playing: "jPlayer_playing",
111		canplay: "jPlayer_canplay",
112		canplaythrough: "jPlayer_canplaythrough",
113		seeking: "jPlayer_seeking",
114		seeked: "jPlayer_seeked",
115		timeupdate: "jPlayer_timeupdate",
116		ended: "jPlayer_ended",
117		ratechange: "jPlayer_ratechange",
118		durationchange: "jPlayer_durationchange",
119		volumechange: "jPlayer_volumechange"
120	};
121
122	$.jPlayer.htmlEvent = [ // These HTML events are bubbled through to the jPlayer event, without any internal action.
123		"loadstart",
124		// "progress", // jPlayer uses internally before bubbling.
125		// "suspend", // jPlayer uses internally before bubbling.
126		"abort",
127		// "error", // jPlayer uses internally before bubbling.
128		"emptied",
129		"stalled",
130		// "play", // jPlayer uses internally before bubbling.
131		// "pause", // jPlayer uses internally before bubbling.
132		"loadedmetadata",
133		"loadeddata",
134		// "waiting", // jPlayer uses internally before bubbling.
135		// "playing", // jPlayer uses internally before bubbling.
136		"canplay",
137		"canplaythrough",
138		// "seeking", // jPlayer uses internally before bubbling.
139		// "seeked", // jPlayer uses internally before bubbling.
140		// "timeupdate", // jPlayer uses internally before bubbling.
141		// "ended", // jPlayer uses internally before bubbling.
142		"ratechange"
143		// "durationchange" // jPlayer uses internally before bubbling.
144		// "volumechange" // jPlayer uses internally before bubbling.
145	];
146
147	$.jPlayer.pause = function() {
148		// $.each($.jPlayer.instances, function(i, element) {
149		$.each($.jPlayer.prototype.instances, function(i, element) {
150			if(element.data("jPlayer").status.srcSet) { // Check that media is set otherwise would cause error event.
151				element.jPlayer("pause");
152			}
153		});
154	};
155	
156	$.jPlayer.timeFormat = {
157		showHour: false,
158		showMin: true,
159		showSec: true,
160		padHour: false,
161		padMin: true,
162		padSec: true,
163		sepHour: ":",
164		sepMin: ":",
165		sepSec: ""
166	};
167
168	$.jPlayer.convertTime = function(s) {
169		var myTime = new Date(s * 1000);
170		var hour = myTime.getUTCHours();
171		var min = myTime.getUTCMinutes();
172		var sec = myTime.getUTCSeconds();
173		var strHour = ($.jPlayer.timeFormat.padHour && hour < 10) ? "0" + hour : hour;
174		var strMin = ($.jPlayer.timeFormat.padMin && min < 10) ? "0" + min : min;
175		var strSec = ($.jPlayer.timeFormat.padSec && sec < 10) ? "0" + sec : sec;
176		return (($.jPlayer.timeFormat.showHour) ? strHour + $.jPlayer.timeFormat.sepHour : "") + (($.jPlayer.timeFormat.showMin) ? strMin + $.jPlayer.timeFormat.sepMin : "") + (($.jPlayer.timeFormat.showSec) ? strSec + $.jPlayer.timeFormat.sepSec : "");
177	};
178
179	// Adapting jQuery 1.4.4 code for jQuery.browser. Required since jQuery 1.3.2 does not detect Chrome as webkit.
180	$.jPlayer.uaBrowser = function( userAgent ) {
181		var ua = userAgent.toLowerCase();
182
183		// Useragent RegExp
184		var rwebkit = /(webkit)[ \/]([\w.]+)/;
185		var ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/;
186		var rmsie = /(msie) ([\w.]+)/;
187		var rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/;
188
189		var match = rwebkit.exec( ua ) ||
190			ropera.exec( ua ) ||
191			rmsie.exec( ua ) ||
192			ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
193			[];
194
195		return { browser: match[1] || "", version: match[2] || "0" };
196	};
197
198	// Platform sniffer for detecting mobile devices
199	$.jPlayer.uaPlatform = function( userAgent ) {
200		var ua = userAgent.toLowerCase();
201
202		// Useragent RegExp
203		var rplatform = /(ipad|iphone|ipod|android|blackberry|playbook|windows ce|webos)/;
204		var rtablet = /(ipad|playbook)/;
205		var randroid = /(android)/;
206		var rmobile = /(mobile)/;
207
208		var platform = rplatform.exec( ua ) || [];
209		var tablet = rtablet.exec( ua ) ||
210			!rmobile.exec( ua ) && randroid.exec( ua ) ||
211			[];
212
213		return { platform: platform[1] || "", tablet: tablet[1] || "" };
214	};
215
216	$.jPlayer.browser = {
217	};
218	$.jPlayer.platform = {
219	};
220
221	var browserMatch = $.jPlayer.uaBrowser(navigator.userAgent);
222	if ( browserMatch.browser ) {
223		$.jPlayer.browser[ browserMatch.browser ] = true;
224		$.jPlayer.browser.version = browserMatch.version;
225	}
226	var platformMatch = $.jPlayer.uaPlatform(navigator.userAgent);
227	if ( platformMatch.platform ) {
228		$.jPlayer.platform[ platformMatch.platform ] = true;
229		$.jPlayer.platform.mobile = !platformMatch.tablet;
230		$.jPlayer.platform.tablet = !!platformMatch.tablet;
231	}
232
233	$.jPlayer.prototype = {
234		count: 0, // Static Variable: Change it via prototype.
235		version: { // Static Object
236			script: "2.0.22",
237			needFlash: "2.0.9",
238			flash: "unknown"
239		},
240		options: { // Instanced in $.jPlayer() constructor
241			swfPath: "js", // Path to Jplayer.swf. Can be relative, absolute or server root relative.
242			solution: "html, flash", // Valid solutions: html, flash. Order defines priority. 1st is highest,
243			supplied: "mp3", // Defines which formats jPlayer will try and support and the priority by the order. 1st is highest,
244			preload: 'metadata',  // HTML5 Spec values: none, metadata, auto.
245			volume: 0.8, // The volume. Number 0 to 1.
246			muted: false,
247			wmode: "opaque", // Valid wmode: window, transparent, opaque, direct, gpu. 
248			backgroundColor: "#000000", // To define the jPlayer div and Flash background color.
249			cssSelectorAncestor: "#jp_container_1",
250			cssSelector: { // * denotes properties that should only be required when video media type required. _cssSelector() would require changes to enable splitting these into Audio and Video defaults.
251				videoPlay: ".jp-video-play", // *
252				play: ".jp-play",
253				pause: ".jp-pause",
254				stop: ".jp-stop",
255				seekBar: ".jp-seek-bar",
256				playBar: ".jp-play-bar",
257				mute: ".jp-mute",
258				unmute: ".jp-unmute",
259				volumeBar: ".jp-volume-bar",
260				volumeBarValue: ".jp-volume-bar-value",
261				volumeMax: ".jp-volume-max",
262				currentTime: ".jp-current-time",
263				duration: ".jp-duration",
264				fullScreen: ".jp-full-screen", // *
265				restoreScreen: ".jp-restore-screen", // *
266				repeat: ".jp-repeat",
267				repeatOff: ".jp-repeat-off",
268				gui: ".jp-gui" // The interface used with autohide feature.
269			},
270			fullScreen: false,
271			autohide: {
272				restored: false, // Controls the interface autohide feature.
273				full: true, // Controls the interface autohide feature.
274				fadeIn: 200, // Milliseconds. The period of the fadeIn anim.
275				fadeOut: 600, // Milliseconds. The period of the fadeOut anim.
276				hold: 1000 // Milliseconds. The period of the pause before autohide beings.
277			},
278			loop: false,
279			repeat: function(event) { // The default jPlayer repeat event handler
280				if(event.jPlayer.options.loop) {
281					$(this).unbind(".jPlayerRepeat").bind($.jPlayer.event.ended + ".jPlayer.jPlayerRepeat", function() {
282						$(this).jPlayer("play");
283					});
284				} else {
285					$(this).unbind(".jPlayerRepeat");
286				}
287			},
288			// globalVolume: false, // Not implemented: Set to make volume changes affect all jPlayer instances
289			// globalMute: false, // Not implemented: Set to make mute changes affect all jPlayer instances
290			idPrefix: "jp", // Prefix for the ids of html elements created by jPlayer. For flash, this must not include characters: . - + * / \
291			noConflict: "jQuery",
292			emulateHtml: false, // Emulates the HTML5 Media element on the jPlayer element.
293			errorAlerts: false,
294			warningAlerts: false
295		},
296		optionsAudio: {
297			size: {
298				width: "0px",
299				height: "0px",
300				cssClass: ""
301			},
302			sizeFull: {
303				width: "0px",
304				height: "0px",
305				cssClass: ""
306			}
307		},
308		optionsVideo: {
309			size: {
310				width: "480px",
311				height: "270px",
312				cssClass: "jp-video-270p"
313			},
314			sizeFull: {
315				width: "100%",
316				height: "100%",
317				cssClass: "jp-video-full"
318			}
319		},
320		instances: {}, // Static Object
321		status: { // Instanced in _init()
322			src: "",
323			media: {},
324			paused: true,
325			format: {},
326			formatType: "",
327			waitForPlay: true, // Same as waitForLoad except in case where preloading.
328			waitForLoad: true,
329			srcSet: false,
330			video: false, // True if playing a video
331			seekPercent: 0,
332			currentPercentRelative: 0,
333			currentPercentAbsolute: 0,
334			currentTime: 0,
335			duration: 0,
336			readyState: 0,
337			networkState: 0,
338			playbackRate: 1,
339			ended: 0
340
341/*		Persistant status properties created dynamically at _init():
342			width
343			height
344			cssClass
345*/
346		},
347
348		internal: { // Instanced in _init()
349			ready: false
350			// instance: undefined,
351			// domNode: undefined,
352			// htmlDlyCmdId: undefined
353			// autohideId: undefined
354		},
355		solution: { // Static Object: Defines the solutions built in jPlayer.
356			html: true,
357			flash: true
358		},
359		// 'MPEG-4 support' : canPlayType('video/mp4; codecs="mp4v.20.8"')
360		format: { // Static Object
361			mp3: {
362				codec: 'audio/mpeg; codecs="mp3"',
363				flashCanPlay: true,
364				media: 'audio'
365			},
366			m4a: { // AAC / MP4
367				codec: 'audio/mp4; codecs="mp4a.40.2"',
368				flashCanPlay: true,
369				media: 'audio'
370			},
371			oga: { // OGG
372				codec: 'audio/ogg; codecs="vorbis"',
373				flashCanPlay: false,
374				media: 'audio'
375			},
376			wav: { // PCM
377				codec: 'audio/wav; codecs="1"',
378				flashCanPlay: false,
379				media: 'audio'
380			},
381			webma: { // WEBM
382				codec: 'audio/webm; codecs="vorbis"',
383				flashCanPlay: false,
384				media: 'audio'
385			},
386			fla: { // FLV / F4A
387				codec: 'audio/x-flv',
388				flashCanPlay: true,
389				media: 'audio'
390			},
391			m4v: { // H.264 / MP4
392				codec: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
393				flashCanPlay: true,
394				media: 'video'
395			},
396			ogv: { // OGG
397				codec: 'video/ogg; codecs="theora, vorbis"',
398				flashCanPlay: false,
399				media: 'video'
400			},
401			webmv: { // WEBM
402				codec: 'video/webm; codecs="vorbis, vp8"',
403				flashCanPlay: false,
404				media: 'video'
405			},
406			flv: { // FLV / F4V
407				codec: 'video/x-flv',
408				flashCanPlay: true,
409				media: 'video'
410			}
411		},
412		_init: function() {
413			var self = this;
414			
415			this.element.empty();
416			
417			this.status = $.extend({}, this.status); // Copy static to unique instance.
418			this.internal = $.extend({}, this.internal); // Copy static to unique instance.
419
420			this.internal.domNode = this.element.get(0);
421
422			this.formats = []; // Array based on supplied string option. Order defines priority.
423			this.solutions = []; // Array based on solution string option. Order defines priority.
424			this.require = {}; // Which media types are required: video, audio.
425			
426			this.htmlElement = {}; // DOM elements created by jPlayer
427			this.html = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
428			this.html.audio = {};
429			this.html.video = {};
430			this.flash = {}; // In _init()'s this.desired code and setmedia(): Accessed via this[solution], where solution from this.solutions array.
431			
432			this.css = {};
433			this.css.cs = {}; // Holds the css selector strings
434			this.css.jq = {}; // Holds jQuery selectors. ie., $(css.cs.method)
435
436			this.ancestorJq = []; // Holds jQuery selector of cssSelectorAncestor. Init would use $() instead of [], but it is only 1.4+
437
438			this.options.volume = this._limitValue(this.options.volume, 0, 1); // Limit volume value's bounds.
439
440			// Create the formats array, with prority based on the order of the supplied formats string
441			$.each(this.options.supplied.toLowerCase().split(","), function(index1, value1) {
442				var format = value1.replace(/^\s+|\s+$/g, ""); //trim
443				if(self.format[format]) { // Check format is valid.
444					var dupFound = false;
445					$.each(self.formats, function(index2, value2) { // Check for duplicates
446						if(format === value2) {
447							dupFound = true;
448							return false;
449						}
450					});
451					if(!dupFound) {
452						self.formats.push(format);
453					}
454				}
455			});
456
457			// Create the solutions array, with prority based on the order of the solution string
458			$.each(this.options.solution.toLowerCase().split(","), function(index1, value1) {
459				var solution = value1.replace(/^\s+|\s+$/g, ""); //trim
460				if(self.solution[solution]) { // Check solution is valid.
461					var dupFound = false;
462					$.each(self.solutions, function(index2, value2) { // Check for duplicates
463						if(solution === value2) {
464							dupFound = true;
465							return false;
466						}
467					});
468					if(!dupFound) {
469						self.solutions.push(solution);
470					}
471				}
472			});
473
474			this.internal.instance = "jp_" + this.count;
475			this.instances[this.internal.instance] = this.element;
476
477			// Check the jPlayer div has an id and create one if required. Important for Flash to know the unique id for comms.
478			if(!this.element.attr("id")) {
479				this.element.attr("id", this.options.idPrefix + "_jplayer_" + this.count);
480			}
481
482			this.internal.self = $.extend({}, {
483				id: this.element.attr("id"),
484				jq: this.element
485			});
486			this.internal.audio = $.extend({}, {
487				id: this.options.idPrefix + "_audio_" + this.count,
488				jq: undefined
489			});
490			this.internal.video = $.extend({}, {
491				id: this.options.idPrefix + "_video_" + this.count,
492				jq: undefined
493			});
494			this.internal.flash = $.extend({}, {
495				id: this.options.idPrefix + "_flash_" + this.count,
496				jq: undefined,
497				swf: this.options.swfPath + ((this.options.swfPath !== "" && this.options.swfPath.slice(-1) !== "/") ? "/" : "") + "Jplayer.swf"
498			});
499			this.internal.poster = $.extend({}, {
500				id: this.options.idPrefix + "_poster_" + this.count,
501				jq: undefined
502			});
503
504			// Register listeners defined in the constructor
505			$.each($.jPlayer.event, function(eventName,eventType) {
506				if(self.options[eventName] !== undefined) {
507					self.element.bind(eventType + ".jPlayer", self.options[eventName]); // With .jPlayer namespace.
508					self.options[eventName] = undefined; // Destroy the handler pointer copy on the options. Reason, events can be added/removed in other ways so this could be obsolete and misleading.
509				}
510			});
511
512			// Determine if we require solutions for audio, video or both media types.
513			this.require.audio = false;
514			this.require.video = false;
515			$.each(this.formats, function(priority, format) {
516				self.require[self.format[format].media] = true;
517			});
518
519			// Now required types are known, finish the options default settings.
520			if(this.require.video) {
521				this.options = $.extend(true, {},
522					this.optionsVideo,
523					this.options
524				);
525			} else {
526				this.options = $.extend(true, {},
527					this.optionsAudio,
528					this.options
529				);
530			}
531			this._setSize(); // update status and jPlayer element size
532
533			// Create the poster image.
534			this.htmlElement.poster = document.createElement('img');
535			this.htmlElement.poster.id = this.internal.poster.id;
536			this.htmlElement.poster.onload = function() { // Note that this did not work on Firefox 3.6: poster.addEventListener("onload", function() {}, false); Did not investigate x-browser.
537				if(!self.status.video || self.status.waitForPlay) {
538					self.internal.poster.jq.show();
539				}
540			};
541			this.element.append(this.htmlElement.poster);
542			this.internal.poster.jq = $("#" + this.internal.poster.id);
543			this.internal.poster.jq.css({'width': this.status.width, 'height': this.status.height});
544			this.internal.poster.jq.hide();
545			
546			// Generate the required media elements
547			this.html.audio.available = false;
548			if(this.require.audio) { // If a supplied format is audio
549				this.htmlElement.audio = document.createElement('audio');
550				this.htmlElement.audio.id = this.internal.audio.id;
551				this.html.audio.available = !!this.htmlElement.audio.canPlayType;
552			}
553			this.html.video.available = false;
554			if(this.require.video) { // If a supplied format is video
555				this.htmlElement.video = document.createElement('video');
556				this.htmlElement.video.id = this.internal.video.id;
557				this.html.video.available = !!this.htmlElement.video.canPlayType;
558			}
559
560			this.flash.available = this._checkForFlash(10);
561
562			this.html.canPlay = {};
563			this.flash.canPlay = {};
564			$.each(this.formats, function(priority, format) {
565				self.html.canPlay[format] = self.html[self.format[format].media].available && "" !== self.htmlElement[self.format[format].media].canPlayType(self.format[format].codec);
566				self.flash.canPlay[format] = self.format[format].flashCanPlay && self.flash.available;
567			});
568			this.html.desired = false;
569			this.flash.desired = false;
570			$.each(this.solutions, function(solutionPriority, solution) {
571				if(solutionPriority === 0) {
572					self[solution].desired = true;
573				} else {
574					var audioCanPlay = false;
575					var videoCanPlay = false;
576					$.each(self.formats, function(formatPriority, format) {
577						if(self[self.solutions[0]].canPlay[format]) { // The other solution can play
578							if(self.format[format].media === 'video') {
579								videoCanPlay = true;
580							} else {
581								audioCanPlay = true;
582							}
583						}
584					});
585					self[solution].desired = (self.require.audio && !audioCanPlay) || (self.require.video && !videoCanPlay);
586				}
587			});
588			// This is what jPlayer will support, based on solution and supplied.
589			this.html.support = {};
590			this.flash.support = {};
591			$.each(this.formats, function(priority, format) {
592				self.html.support[format] = self.html.canPlay[format] && self.html.desired;
593				self.flash.support[format] = self.flash.canPlay[format] && self.flash.desired;
594			});
595			// If jPlayer is supporting any format in a solution, then the solution is used.
596			this.html.used = false;
597			this.flash.used = false;
598			$.each(this.solutions, function(solutionPriority, solution) {
599				$.each(self.formats, function(formatPriority, format) {
600					if(self[solution].support[format]) {
601						self[solution].used = true;
602						return false;
603					}
604				});
605			});
606
607			// Init solution active state and the event gates to false.
608			this.html.active = false;
609			this.html.audio.gate = false;
610			this.html.video.gate = false;
611			this.flash.active = false;
612			this.flash.gate = false;
613
614			// Set up the css selectors for the control and feedback entities.
615			this._cssSelectorAncestor(this.options.cssSelectorAncestor);
616			
617			// If neither html nor flash are being used by this browser, then media playback is not possible. Trigger an error event.
618			if(!(this.html.used || this.flash.used)) {
619				this._error( {
620					type: $.jPlayer.error.NO_SOLUTION, 
621					context: "{solution:'" + this.options.solution + "', supplied:'" + this.options.supplied + "'}",
622					message: $.jPlayer.errorMsg.NO_SOLUTION,
623					hint: $.jPlayer.errorHint.NO_SOLUTION
624				});
625			}
626
627			// Add the flash solution if it is being used.
628			if(this.flash.used) {
629				var htmlObj,
630				flashVars = 'jQuery=' + encodeURI(this.options.noConflict) + '&id=' + encodeURI(this.internal.self.id) + '&vol=' + this.options.volume + '&muted=' + this.options.muted;
631
632				// Code influenced by SWFObject 2.2: http://code.google.com/p/swfobject/
633				// Non IE browsers have an initial Flash size of 1 by 1 otherwise the wmode affected the Flash ready event. 
634
635				if($.browser.msie && Number($.browser.version) <= 8) {
636					var objStr = '<object id="' + this.internal.flash.id + '" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="0" height="0"></object>';
637
638					var paramStr = [
639						'<param name="movie" value="' + this.internal.flash.swf + '" />',
640						'<param name="FlashVars" value="' + flashVars + '" />',
641						'<param name="allowScriptAccess" value="always" />',
642						'<param name="bgcolor" value="' + this.options.backgroundColor + '" />',
643						'<param name="wmode" value="' + this.options.wmode + '" />'
644					];
645
646					htmlObj = document.createElement(objStr);
647					for(var i=0; i < paramStr.length; i++) {
648						htmlObj.appendChild(document.createElement(paramStr[i]));
649					}
650				} else {
651					var createParam = function(el, n, v) {
652						var p = document.createElement("param");
653						p.setAttribute("name", n);	
654						p.setAttribute("value", v);
655						el.appendChild(p);
656					};
657
658					htmlObj = document.createElement("object");
659					htmlObj.setAttribute("id", this.internal.flash.id);
660					htmlObj.setAttribute("data", this.internal.flash.swf);
661					htmlObj.setAttribute("type", "application/x-shockwave-flash");
662					htmlObj.setAttribute("width", "1"); // Non-zero
663					htmlObj.setAttribute("height", "1"); // Non-zero
664					createParam(htmlObj, "flashvars", flashVars);
665					createParam(htmlObj, "allowscriptaccess", "always");
666					createParam(htmlObj, "bgcolor", this.options.backgroundColor);
667					createParam(htmlObj, "wmode", this.options.wmode);
668				}
669
670				this.element.append(htmlObj);
671				this.internal.flash.jq = $(htmlObj);
672			}
673			
674			// Add the HTML solution if being used.
675			if(this.html.used) {
676
677				// The HTML Audio handlers
678				if(this.html.audio.available) {
679					this._addHtmlEventListeners(this.htmlElement.audio, this.html.audio);
680					this.element.append(this.htmlElement.audio);
681					this.internal.audio.jq = $("#" + this.internal.audio.id);
682				}
683
684				// The HTML Video handlers
685				if(this.html.video.available) {
686					this._addHtmlEventListeners(this.htmlElement.video, this.html.video);
687					this.element.append(this.htmlElement.video);
688					this.internal.video.jq = $("#" + this.internal.video.id);
689					this.internal.video.jq.css({'width':'0px', 'height':'0px'}); // Using size 0x0 since a .hide() causes issues in iOS
690				}
691			}
692
693			// Create the bridge that emulates the HTML Media element on the jPlayer DIV
694			if( this.options.emulateHtml ) {
695				this._emulateHtmlBridge();
696			}
697
698			if(this.html.used && !this.flash.used) { // If only HTML, then emulate flash ready() call after 100ms.
699				setTimeout( function() {
700					self.internal.ready = true;
701					self.version.flash = "n/a";
702					self._trigger($.jPlayer.event.repeat); // Trigger the repeat event so its handler can initialize itself with the loop option.
703					self._trigger($.jPlayer.event.ready);
704				}, 100);
705			}
706
707			// Initialize the interface components with the options.
708			this._updateInterface();
709			this._updateButtons(false);
710			this._updateAutohide();
711			this._updateVolume(this.options.volume);
712			this._updateMute(this.options.muted);
713			if(this.css.jq.videoPlay.length) {
714				this.css.jq.videoPlay.hide();
715			}
716
717			$.jPlayer.prototype.count++; // Change static variable via prototype.
718		},
719		destroy: function() {
720			// MJP: The background change remains. Would need to store the original to restore it correctly.
721
722			// Reset the interface, remove seeking effect and times.
723			this._resetStatus();
724			this._updateInterface();
725			this._seeked();
726			if(this.css.jq.currentTime.length) {
727				this.css.jq.currentTime.text("");
728			}
729			if(this.css.jq.duration.length) {
730				this.css.jq.duration.text("");
731			}
732
733			if(this.status.srcSet) { // Or you get a bogus error event
734				this.pause(); // Pauses the media and clears any delayed commands used in the HTML solution.
735			}
736			$.each(this.css.jq, function(fn, jq) { // Remove any bindings from the interface controls.
737				// Check selector is valid before trying to execute method.
738				if(jq.length) {
739					jq.unbind(".jPlayer");
740				}
741			});
742			if( this.options.emulateHtml ) {
743				this._destroyHtmlBridge();
744			}
745			this.element.removeData("jPlayer"); // Remove jPlayer data
746			this.element.unbind(".jPlayer"); // Remove all event handlers created by the jPlayer constructor
747			this.element.empty(); // Remove the inserted child elements
748			
749			this.instances[this.internal.instance] = undefined; // Clear the instance on the static instance object
750		},
751		enable: function() { // Plan to implement
752			// options.disabled = false
753		},
754		disable: function () { // Plan to implement
755			// options.disabled = true
756		},
757		_addHtmlEventListeners: function(mediaElement, entity) {
758			var self = this;
759			mediaElement.preload = this.options.preload;
760			mediaElement.muted = this.options.muted;
761			mediaElement.volume = this.options.volume;
762
763			// Create the event listeners
764			// Only want the active entity to affect jPlayer and bubble events.
765			// Using entity.gate so that object is referenced and gate property always current
766			
767			mediaElement.addEventListener("progress", function() {
768				if(entity.gate && !self.status.waitForLoad) {
769					self._getHtmlStatus(mediaElement);
770					self._updateInterface();
771					self._trigger($.jPlayer.event.progress);
772				}
773			}, false);
774			mediaElement.addEventListener("timeupdate", function() {
775				if(entity.gate && !self.status.waitForLoad) {
776					self._getHtmlStatus(mediaElement);
777					self._updateInterface();
778					self._trigger($.jPlayer.event.timeupdate);
779				}
780			}, false);
781			mediaElement.addEventListener("durationchange", function() {
782				if(entity.gate && !self.status.waitForLoad) {
783					self.status.duration = this.duration;
784					self._getHtmlStatus(mediaElement);
785					self._updateInterface();
786					self._trigger($.jPlayer.event.durationchange);
787				}
788			}, false);
789			mediaElement.addEventListener("play", function() {
790				if(entity.gate && !self.status.waitForLoad) {
791					self._updateButtons(true);
792					self._trigger($.jPlayer.event.play);
793				}
794			}, false);
795			mediaElement.addEventListener("playing", function() {
796				if(entity.gate && !self.status.waitForLoad) {
797					self._updateButtons(true);
798					self._seeked();
799					self._trigger($.jPlayer.event.playing);
800				}
801			}, false);
802			mediaElement.addEventListener("pause", function() {
803				if(entity.gate && !self.status.waitForLoad) {
804					self._updateButtons(false);
805					self._trigger($.jPlayer.event.pause);
806				}
807			}, false);
808			mediaElement.addEventListener("waiting", function() {
809				if(entity.gate && !self.status.waitForLoad) {
810					self._seeking();
811					self._trigger($.jPlayer.event.waiting);
812				}
813			}, false);
814			mediaElement.addEventListener("seeking", function() {
815				if(entity.gate && !self.status.waitForLoad) {
816					self._seeking();
817					self._trigger($.jPlayer.event.seeking);
818				}
819			}, false);
820			mediaElement.addEventListener("seeked", function() {
821				if(entity.gate && !self.status.waitForLoad) {
822					self._seeked();
823					self._trigger($.jPlayer.event.seeked);
824				}
825			}, false);
826			mediaElement.addEventListener("volumechange", function() {
827				if(entity.gate && !self.status.waitForLoad) {
828					// Read the values back from the element as the Blackberry PlayBook shares the volume with the physical buttons master volume control.
829					// However, when tested 6th July 2011, those buttons do not generate an event. The physical play/pause button does though.
830					self.options.volume = mediaElement.volume;
831					self.options.muted = mediaElement.muted;
832					self._updateMute();
833					self._updateVolume();
834					self._trigger($.jPlayer.event.volumechange);
835				}
836			}, false);
837			mediaElement.addEventListener("suspend", function() { // Seems to be the only way of capturing that the iOS4 browser did not actually play the media from the page code. ie., It needs a user gesture.
838				if(entity.gate && !self.status.waitForLoad) {
839					self._seeked();
840					self._trigger($.jPlayer.event.suspend);
841				}
842			}, false);
843			mediaElement.addEventListener("ended", function() {
844				if(entity.gate && !self.status.waitForLoad) {
845					// Order of the next few commands are important. Change the time and then pause.
vendor: 10,510 bytes, lines 846-1126
846					// Solves a bug in Firefox, where issuing pause 1st causes the media to play from the start. ie., The pause is ignored.
847					if(!$.jPlayer.browser.webkit) { // Chrome crashes if you do this in conjunction with a setMedia command in an ended event handler. ie., The playlist demo.
848						self.htmlElement.media.currentTime = 0; // Safari does not care about this command. ie., It works with or without this line. (Both Safari and Chrome are Webkit.)
849					}
850					self.htmlElement.media.pause(); // Pause otherwise a click on the progress bar will play from that point, when it shouldn't, since it stopped playback.
851					self._updateButtons(false);
852					self._getHtmlStatus(mediaElement, true); // With override true. Otherwise Chrome leaves progress at full.
853					self._updateInterface();
854					self._trigger($.jPlayer.event.ended);
855				}
856			}, false);
857			mediaElement.addEventListener("error", function() {
858				if(entity.gate && !self.status.waitForLoad) {
859					self._updateButtons(false);
860					self._seeked();
861					if(self.status.srcSet) { // Deals with case of clearMedia() causing an error event.
862						clearTimeout(self.internal.htmlDlyCmdId); // Clears any delayed commands used in the HTML solution.
863						self.status.waitForLoad = true; // Allows the load operation to try again.
864						self.status.waitForPlay = true; // Reset since a play was captured.
865						if(self.status.video) {
866							self.internal.video.jq.css({'width':'0px', 'height':'0px'});
867						}
868						if(self._validString(self.status.media.poster)) {
869							self.internal.poster.jq.show();
870						}
871						if(self.css.jq.videoPlay.length) {
872							self.css.jq.videoPlay.show();
873						}
874						self._error( {
875							type: $.jPlayer.error.URL,
876							context: self.status.src, // this.src shows absolute urls. Want context to show the url given.
877							message: $.jPlayer.errorMsg.URL,
878							hint: $.jPlayer.errorHint.URL
879						});
880					}
881				}
882			}, false);
883			// Create all the other event listeners that bubble up to a jPlayer event from html, without being used by jPlayer.
884			$.each($.jPlayer.htmlEvent, function(i, eventType) {
885				mediaElement.addEventListener(this, function() {
886					if(entity.gate && !self.status.waitForLoad) {
887						self._trigger($.jPlayer.event[eventType]);
888					}
889				}, false);
890			});
891		},
892		_getHtmlStatus: function(media, override) {
893			var ct = 0, d = 0, cpa = 0, sp = 0, cpr = 0;
894
895			if(media.duration) { // Fixes the duration bug in iOS, where the durationchange event occurs when media.duration is not always correct.
896				this.status.duration = media.duration;
897			}
898			ct = media.currentTime;
899			cpa = (this.status.duration > 0) ? 100 * ct / this.status.duration : 0;
900			if((typeof media.seekable === "object") && (media.seekable.length > 0)) {
901				sp = (this.status.duration > 0) ? 100 * media.seekable.end(media.seekable.length-1) / this.status.duration : 100;
902				cpr = 100 * media.currentTime / media.seekable.end(media.seekable.length-1);
903			} else {
904				sp = 100;
905				cpr = cpa;
906			}
907			
908			if(override) {
909				ct = 0;
910				cpr = 0;
911				cpa = 0;
912			}
913
914			this.status.seekPercent = sp;
915			this.status.currentPercentRelative = cpr;
916			this.status.currentPercentAbsolute = cpa;
917			this.status.currentTime = ct;
918
919			this.status.readyState = media.readyState;
920			this.status.networkState = media.networkState;
921			this.status.playbackRate = media.playbackRate;
922			this.status.ended = media.ended;
923		},
924		_resetStatus: function() {
925			this.status = $.extend({}, this.status, $.jPlayer.prototype.status); // Maintains the status properties that persist through a reset.
926		},
927		_trigger: function(eventType, error, warning) { // eventType always valid as called using $.jPlayer.event.eventType
928			var event = $.Event(eventType);
929			event.jPlayer = {};
930			event.jPlayer.version = $.extend({}, this.version);
931			event.jPlayer.options = $.extend(true, {}, this.options); // Deep copy
932			event.jPlayer.status = $.extend(true, {}, this.status); // Deep copy
933			event.jPlayer.html = $.extend(true, {}, this.html); // Deep copy
934			event.jPlayer.flash = $.extend(true, {}, this.flash); // Deep copy
935			if(error) {
936				event.jPlayer.error = $.extend({}, error);
937			}
938			if(warning) {
939				event.jPlayer.warning = $.extend({}, warning);
940			}
941			this.element.trigger(event);
942		},
943		jPlayerFlashEvent: function(eventType, status) { // Called from Flash
944			if(eventType === $.jPlayer.event.ready) {
945				if(!this.internal.ready) {
946					this.internal.ready = true;
947					this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); // Once Flash generates the ready event, minimise to zero as it is not affected by wmode anymore.
948
949					this.version.flash = status.version;
950					if(this.version.needFlash !== this.version.flash) {
951						this._error( {
952							type: $.jPlayer.error.VERSION,
953							context: this.version.flash,
954							message: $.jPlayer.errorMsg.VERSION + this.version.flash,
955							hint: $.jPlayer.errorHint.VERSION
956						});
957					}
958					this._trigger($.jPlayer.event.repeat); // Trigger the repeat event so its handler can initialize itself with the loop option.
959					this._trigger(eventType);
960				} else {
961					// This condition occurs if the Flash is hidden and then shown again.
962					// Firefox also reloads the Flash if the CSS position changes. position:fixed is used for full screen.
963
964					// Only do this if the Flash is the solution being used at the moment. Affects Media players where both solution may be being used.
965					if(this.flash.gate) {
966
967						// Send the current status to the Flash now that it is ready (available) again.
968						if(this.status.srcSet) {
969
970							// Need to read original status before issuing the setMedia command.
971							var	currentTime = this.status.currentTime,
972								paused = this.status.paused; 
973
974							this.setMedia(this.status.media);
975							if(currentTime > 0) {
976								if(paused) {
977									this.pause(currentTime);
978								} else {
979									this.play(currentTime);
980								}
981							}
982						}
983						this._trigger($.jPlayer.event.flashreset);
984					}
985				}
986			}
987			if(this.flash.gate) {
988				switch(eventType) {
989					case $.jPlayer.event.progress:
990						this._getFlashStatus(status);
991						this._updateInterface();
992						this._trigger(eventType);
993						break;
994					case $.jPlayer.event.timeupdate:
995						this._getFlashStatus(status);
996						this._updateInterface();
997						this._trigger(eventType);
998						break;
999					case $.jPlayer.event.play:
1000						this._seeked();
1001						this._updateButtons(true);
1002						this._trigger(eventType);
1003						break;
1004					case $.jPlayer.event.pause:
1005						this._updateButtons(false);
1006						this._trigger(eventType);
1007						break;
1008					case $.jPlayer.event.ended:
1009						this._updateButtons(false);
1010						this._trigger(eventType);
1011						break;
1012					case $.jPlayer.event.error:
1013						this.status.waitForLoad = true; // Allows the load operation to try again.
1014						this.status.waitForPlay = true; // Reset since a play was captured.
1015						if(this.status.video) {
1016							this.internal.flash.jq.css({'width':'0px', 'height':'0px'});
1017						}
1018						if(this._validString(this.status.media.poster)) {
1019							this.internal.poster.jq.show();
1020						}
1021						if(this.css.jq.videoPlay.length) {
1022							this.css.jq.videoPlay.show();
1023						}
1024						if(this.status.video) { // Set up for another try. Execute before error event.
1025							this._flash_setVideo(this.status.media);
1026						} else {
1027							this._flash_setAudio(this.status.media);
1028						}
1029						this._error( {
1030							type: $.jPlayer.error.URL,
1031							context:status.src,
1032							message: $.jPlayer.errorMsg.URL,
1033							hint: $.jPlayer.errorHint.URL
1034						});
1035						break;
1036					case $.jPlayer.event.seeking:
1037						this._seeking();
1038						this._trigger(eventType);
1039						break;
1040					case $.jPlayer.event.seeked:
1041						this._seeked();
1042						this._trigger(eventType);
1043						break;
1044					case $.jPlayer.event.ready:
1045						// The ready event is handled outside the switch statement.
1046						// Captured here otherwise 2 ready events would be generated if the ready event handler used setMedia.
1047						break;
1048					default:
1049						this._trigger(eventType);
1050				}
1051			}
1052			return false;
1053		},
1054		_getFlashStatus: function(status) {
1055			this.status.seekPercent = status.seekPercent;
1056			this.status.currentPercentRelative = status.currentPercentRelative;
1057			this.status.currentPercentAbsolute = status.currentPercentAbsolute;
1058			this.status.currentTime = status.currentTime;
1059			this.status.duration = status.duration;
1060
1061			// The Flash does not generate this information in this release
1062			this.status.readyState = 4; // status.readyState;
1063			this.status.networkState = 0; // status.networkState;
1064			this.status.playbackRate = 1; // status.playbackRate;
1065			this.status.ended = false; // status.ended;
1066		},
1067		_updateButtons: function(playing) {
1068			if(playing !== undefined) {
1069				this.status.paused = !playing;
1070				if(this.css.jq.play.length && this.css.jq.pause.length) {
1071					if(playing) {
1072						this.css.jq.play.hide();
1073						this.css.jq.pause.show();
1074					} else {
1075						this.css.jq.play.show();
1076						this.css.jq.pause.hide();
1077					}
1078				}
1079			}
1080			if(this.css.jq.restoreScreen.length && this.css.jq.fullScreen.length) {
1081				if(this.options.fullScreen) {
1082					this.css.jq.fullScreen.hide();
1083					this.css.jq.restoreScreen.show();
1084				} else {
1085					this.css.jq.fullScreen.show();
1086					this.css.jq.restoreScreen.hide();
1087				}
1088			}
1089			if(this.css.jq.repeat.length && this.css.jq.repeatOff.length) {
1090				if(this.options.loop) {
1091					this.css.jq.repeat.hide();
1092					this.css.jq.repeatOff.show();
1093				} else {
1094					this.css.jq.repeat.show();
1095					this.css.jq.repeatOff.hide();
1096				}
1097			}
1098		},
1099		_updateInterface: function() {
1100			if(this.css.jq.seekBar.length) {
1101				this.css.jq.seekBar.width(this.status.seekPercent+"%");
1102			}
1103			if(this.css.jq.playBar.length) {
1104				this.css.jq.playBar.width(this.status.currentPercentRelative+"%");
1105			}
1106			if(this.css.jq.currentTime.length) {
1107				this.css.jq.currentTime.text($.jPlayer.convertTime(this.status.currentTime));
1108			}
1109			if(this.css.jq.duration.length) {
1110				this.css.jq.duration.text($.jPlayer.convertTime(this.status.duration));
1111			}
1112		},
1113		_seeking: function() {
1114			if(this.css.jq.seekBar.length) {
1115				this.css.jq.seekBar.addClass("jp-seeking-bg");
1116			}
1117		},
1118		_seeked: function() {
1119			if(this.css.jq.seekBar.length) {
1120				this.css.jq.seekBar.removeClass("jp-seeking-bg");
1121			}
1122		},
1123		setMedia: function(media) {
1124		
1125			/*	media[format] = String: URL of format. Must contain all of the supplied option's video or audio formats.
1126			 *	media.poster = String: Video poster URL.
1127			 *	media.subtitles = String: * NOT IMPLEMENTED * URL of subtitles SRT file
1128			 *	media.chapters = String: * NOT IMPLEMENTED * URL of chapters SRT file
1129			 *	media.stream = Boolean: * NOT IMPLEMENTED * Designating actual media streams. ie., "false/undefined" for files. Plan to refresh the flash every so often.
1130			 */
1131			
1132			var self = this;
1133			
1134			this._seeked();
1135			clearTimeout(this.internal.htmlDlyCmdId); // Clears any delayed commands used in the HTML solution.
1136
1137			// Store the current html gates, since we need for clearMedia() conditions.
1138			var audioGate = this.html.audio.gate;
1139			var videoGate = this.html.video.gate;
1140
1141			var supported = false;
1142			$.each(this.formats, function(formatPriority, format) {
1143				var isVideo = self.format[format].media === 'video';
1144				$.each(self.solutions, function(solutionPriority, solution) {
1145					if(self[solution].support[format] && self._validString(media[format])) { // Format supported in solution and url given for format.
1146						var isHtml = solution === 'html';
1147						
1148						if(isVideo) {
1149							if(isHtml) {
1150								self.html.audio.gate = false;
1151								self.html.video.gate = true;
1152								self.flash.gate = false;
1153							} else {
1154								self.html.audio.gate = false;
1155								self.html.video.gate = false;
1156								self.flash.gate = true;
1157							}
1158						} else {
1159							if(isHtml) {
1160								self.html.audio.gate = true;
1161								self.html.video.gate = false;
1162								self.flash.gate = false;
1163							} else {
1164								self.html.audio.gate = false;
1165								self.html.video.gate = false;
1166								self.flash.gate = true;
1167							}
1168						}
1169
1170						// Clear media of the previous solution if:
1171						//  - it was Flash
1172						//  - changing from HTML to Flash
1173						//  - the HTML solution media type (audio or video) remained the same.
1174						// Note that, we must be careful with clearMedia() on iPhone, otherwise clearing the video when changing to audio corrupts the built in video player.
1175						if(self.flash.active || (self.html.active && self.flash.gate) || (audioGate === self.html.audio.gate && videoGate === self.html.video.gate)) {
1176							self.clearMedia();
1177						} else if(audioGate !== self.html.audio.gate && videoGate !== self.html.video.gate) { // If switching between html elements
1178							self._html_pause();
1179							// Hide the video if it was being used.
1180							if(self.status.video) {
1181								self.internal.video.jq.css({'width':'0px', 'height':'0px'});
1182							}
1183							self._resetStatus(); // Since clearMedia usually does this. Execute after status.video useage.
1184						}
1185
1186						if(isVideo) {
1187							if(isHtml) {
1188								self._html_setVideo(media);
1189								self.html.active = true;
1190								self.flash.active = false;
1191							} else {
1192								self._flash_setVideo(media);
1193								self.html.active = false;
1194								self.flash.active = true;
1195							}
1196							if(self.css.jq.videoPlay.length) {
1197								self.css.jq.videoPlay.show();
1198							}
1199							self.status.video = true;
1200						} else {
1201							if(isHtml) {
1202								self._html_setAudio(media);
1203								self.html.active = true;
1204								self.flash.active = false;
1205							} else {
1206								self._flash_setAudio(media);
1207								self.html.active = false;
1208								self.flash.active = true;
1209							}
1210							if(self.css.jq.videoPlay.length) {
1211								self.css.jq.videoPlay.hide();
1212							}
1213							self.status.video = false;
1214						}
1215						
1216						supported = true;
1217						return false; // Exit $.each
1218					}
1219				});
1220				if(supported) {
1221					return false; // Exit $.each
1222				}
1223			});
1224
1225			if(supported) {
1226				// Set poster after the possible clearMedia() command above. IE had issues since the IMG onload event occurred immediately when cached. ie., The clearMedia() hide the poster.
1227				if(this._validString(media.poster)) {
1228					if(this.htmlElement.poster.src !== media.poster) { // Since some browsers do not generate img onload event.
1229						this.htmlElement.poster.src = media.poster;
1230					} else {
1231						this.internal.poster.jq.show();
1232					}
1233				} else {
1234					this.internal.poster.jq.hide(); // Hide if not used, since clearMedia() does not always occur above. ie., HTML audio <-> video switching.
1235				}
1236				this.status.srcSet = true;
1237				this.status.media = $.extend({}, media);
1238				this._updateButtons(false);
1239				this._updateInterface();
1240			} else { // jPlayer cannot support any formats provided in this browser
1241				// Pause here if old media could be playing. Otherwise, playing media being changed to bad media would leave the old media playing.
1242				if(this.status.srcSet && !this.status.waitForPlay) {
1243					this.pause();
1244				}
1245				// Reset all the control flags
1246				this.html.audio.gate = false;
vendor: 16,364 bytes, lines 1247-1773
1247				this.html.video.gate = false;
1248				this.flash.gate = false;
1249				this.html.active = false;
1250				this.flash.active = false;
1251				// Reset status and interface.
1252				this._resetStatus();
1253				this._updateInterface();
1254				this._updateButtons(false);
1255				// Hide the any old media
1256				this.internal.poster.jq.hide();
1257				if(this.html.used && this.require.video) {
1258					this.internal.video.jq.css({'width':'0px', 'height':'0px'});
1259				}
1260				if(this.flash.used) {
1261					this.internal.flash.jq.css({'width':'0px', 'height':'0px'});
1262				}
1263				// Send an error event
1264				this._error( {
1265					type: $.jPlayer.error.NO_SUPPORT,
1266					context: "{supplied:'" + this.options.supplied + "'}",
1267					message: $.jPlayer.errorMsg.NO_SUPPORT,
1268					hint: $.jPlayer.errorHint.NO_SUPPORT
1269				});
1270			}
1271		},
1272		clearMedia: function() {
1273			this._resetStatus();
1274			this._updateButtons(false);
1275
1276			this.internal.poster.jq.hide();
1277
1278			clearTimeout(this.internal.htmlDlyCmdId);
1279
1280			if(this.html.active) {
1281				this._html_clearMedia();
1282			} else if(this.flash.active) {
1283				this._flash_clearMedia();
1284			}
1285		},
1286		load: function() {
1287			if(this.status.srcSet) {
1288				if(this.html.active) {
1289					this._html_load();
1290				} else if(this.flash.active) {
1291					this._flash_load();
1292				}
1293			} else {
1294				this._urlNotSetError("load");
1295			}
1296		},
1297		play: function(time) {
1298			time = (typeof time === "number") ? time : NaN; // Remove jQuery event from click handler
1299			if(this.status.srcSet) {
1300				if(this.html.active) {
1301					this._html_play(time);
1302				} else if(this.flash.active) {
1303					this._flash_play(time);
1304				}
1305			} else {
1306				this._urlNotSetError("play");
1307			}
1308		},
1309		videoPlay: function(e) { // Handles clicks on the play button over the video poster
1310			this.play();
1311		},
1312		pause: function(time) {
1313			time = (typeof time === "number") ? time : NaN; // Remove jQuery event from click handler
1314			if(this.status.srcSet) {
1315				if(this.html.active) {
1316					this._html_pause(time);
1317				} else if(this.flash.active) {
1318					this._flash_pause(time);
1319				}
1320			} else {
1321				this._urlNotSetError("pause");
1322			}
1323		},
1324		pauseOthers: function() {
1325			var self = this;
1326			$.each(this.instances, function(i, element) {
1327				if(self.element !== element) { // Do not this instance.
1328					if(element.data("jPlayer").status.srcSet) { // Check that media is set otherwise would cause error event.
1329						element.jPlayer("pause");
1330					}
1331				}
1332			});
1333		},
1334		stop: function() {
1335			if(this.status.srcSet) {
1336				if(this.html.active) {
1337					this._html_pause(0);
1338				} else if(this.flash.active) {
1339					this._flash_pause(0);
1340				}
1341			} else {
1342				this._urlNotSetError("stop");
1343			}
1344		},
1345		playHead: function(p) {
1346			p = this._limitValue(p, 0, 100);
1347			if(this.status.srcSet) {
1348				if(this.html.active) {
1349					this._html_playHead(p);
1350				} else if(this.flash.active) {
1351					this._flash_playHead(p);
1352				}
1353			} else {
1354				this._urlNotSetError("playHead");
1355			}
1356		},
1357		_muted: function(muted) {
1358			this.options.muted = muted;
1359			if(this.html.used) {
1360				this._html_mute(muted);
1361			}
1362			if(this.flash.used) {
1363				this._flash_mute(muted);
1364			}
1365
1366			// The HTML solution generates this event from the media element itself.
1367			if(this.flash.gate) {
1368				this._updateMute(muted);
1369				this._updateVolume(this.options.volume);
1370				this._trigger($.jPlayer.event.volumechange);
1371			}
1372		},
1373		mute: function(mute) { // mute is either: undefined (true), an event object (true) or a boolean (muted).
1374			mute = mute === undefined ? true : !!mute;
1375			this._muted(mute);
1376		},
1377		unmute: function(unmute) { // unmute is either: undefined (true), an event object (true) or a boolean (!muted).
1378			unmute = unmute === undefined ? true : !!unmute;
1379			this._muted(!unmute);
1380		},
1381		_updateMute: function(mute) {
1382			if(mute === undefined) {
1383				mute = this.options.muted;
1384			}
1385			if(this.css.jq.mute.length && this.css.jq.unmute.length) {
1386				if(mute) {
1387					this.css.jq.mute.hide();
1388					this.css.jq.unmute.show();
1389				} else {
1390					this.css.jq.mute.show();
1391					this.css.jq.unmute.hide();
1392				}
1393			}
1394		},
1395		volume: function(v) {
1396			v = this._limitValue(v, 0, 1);
1397			this.options.volume = v;
1398
1399			if(this.html.used) {
1400				this._html_volume(v);
1401			}
1402			if(this.flash.used) {
1403				this._flash_volume(v);
1404			}
1405
1406			// The HTML solution generates this event from the media element itself.
1407			if(this.flash.gate) {
1408				this._updateVolume(v);
1409				this._trigger($.jPlayer.event.volumechange);
1410			}
1411		},
1412		volumeBar: function(e) { // Handles clicks on the volumeBar
1413			if(this.css.jq.volumeBar.length) {
1414				var offset = this.css.jq.volumeBar.offset();
1415				var x = e.pageX - offset.left;
1416				var w = this.css.jq.volumeBar.width();
1417				var v = x/w;
1418				this.volume(v);
1419			}
1420			if(this.options.muted) {
1421				this._muted(false);
1422			}
1423		},
1424		volumeBarValue: function(e) { // Handles clicks on the volumeBarValue
1425			this.volumeBar(e);
1426		},
1427		_updateVolume: function(v) {
1428			if(v === undefined) {
1429				v = this.options.volume;
1430			}
1431			v = this.options.muted ? 0 : v;
1432
1433			if(this.css.jq.volumeBarValue.length) {
1434				this.css.jq.volumeBarValue.width((v*100)+"%");
1435			}
1436		},
1437		volumeMax: function() { // Handles clicks on the volume max
1438			this.volume(1);
1439			if(this.options.muted) {
1440				this._muted(false);
1441			}
1442		},
1443		_cssSelectorAncestor: function(ancestor) {
1444			var self = this;
1445			this.options.cssSelectorAncestor = ancestor;
1446			this._removeUiClass();
1447			this.ancestorJq = ancestor ? $(ancestor) : []; // Would use $() instead of [], but it is only 1.4+
1448			if(ancestor && this.ancestorJq.length !== 1) { // So empty strings do not generate the warning.
1449				this._warning( {
1450					type: $.jPlayer.warning.CSS_SELECTOR_COUNT,
1451					context: ancestor,
1452					message: $.jPlayer.warningMsg.CSS_SELECTOR_COUNT + this.ancestorJq.length + " found for cssSelectorAncestor.",
1453					hint: $.jPlayer.warningHint.CSS_SELECTOR_COUNT
1454				});
1455			}
1456			this._addUiClass();
1457			$.each(this.options.cssSelector, function(fn, cssSel) {
1458				self._cssSelector(fn, cssSel);
1459			});
1460		},
1461		_cssSelector: function(fn, cssSel) {
1462			var self = this;
1463			if(typeof cssSel === 'string') {
1464				if($.jPlayer.prototype.options.cssSelector[fn]) {
1465					if(this.css.jq[fn] && this.css.jq[fn].length) {
1466						this.css.jq[fn].unbind(".jPlayer");
1467					}
1468					this.options.cssSelector[fn] = cssSel;
1469					this.css.cs[fn] = this.options.cssSelectorAncestor + " " + cssSel;
1470
1471					if(cssSel) { // Checks for empty string
1472						this.css.jq[fn] = $(this.css.cs[fn]);
1473					} else {
1474						this.css.jq[fn] = []; // To comply with the css.jq[fn].length check before its use. As of jQuery 1.4 could have used $() for an empty set. 
1475					}
1476
1477					if(this.css.jq[fn].length) {
1478						var handler = function(e) {
1479							self[fn](e);
1480							$(this).blur();
1481							return false;
1482						};
1483						this.css.jq[fn].bind("click.jPlayer", handler); // Using jPlayer namespace
1484					}
1485
1486					if(cssSel && this.css.jq[fn].length !== 1) { // So empty strings do not generate the warning. ie., they just remove the old one.
1487						this._warning( {
1488							type: $.jPlayer.warning.CSS_SELECTOR_COUNT,
1489							context: this.css.cs[fn],
1490							message: $.jPlayer.warningMsg.CSS_SELECTOR_COUNT + this.css.jq[fn].length + " found for " + fn + " method.",
1491							hint: $.jPlayer.warningHint.CSS_SELECTOR_COUNT
1492						});
1493					}
1494				} else {
1495					this._warning( {
1496						type: $.jPlayer.warning.CSS_SELECTOR_METHOD,
1497						context: fn,
1498						message: $.jPlayer.warningMsg.CSS_SELECTOR_METHOD,
1499						hint: $.jPlayer.warningHint.CSS_SELECTOR_METHOD
1500					});
1501				}
1502			} else {
1503				this._warning( {
1504					type: $.jPlayer.warning.CSS_SELECTOR_STRING,
1505					context: cssSel,
1506					message: $.jPlayer.warningMsg.CSS_SELECTOR_STRING,
1507					hint: $.jPlayer.warningHint.CSS_SELECTOR_STRING
1508				});
1509			}
1510		},
1511		seekBar: function(e) { // Handles clicks on the seekBar
1512			if(this.css.jq.seekBar) {
1513				var offset = this.css.jq.seekBar.offset();
1514				var x = e.pageX - offset.left;
1515				var w = this.css.jq.seekBar.width();
1516				var p = 100*x/w;
1517				this.playHead(p);
1518			}
1519		},
1520		playBar: function(e) { // Handles clicks on the playBar
1521			this.seekBar(e);
1522		},
1523		repeat: function() { // Handle clicks on the repeat button
1524			this._loop(true);
1525		},
1526		repeatOff: function() { // Handle clicks on the repeatOff button
1527			this._loop(false);
1528		},
1529		_loop: function(loop) {
1530			if(this.options.loop !== loop) {
1531				this.options.loop = loop;
1532				this._updateButtons();
1533				this._trigger($.jPlayer.event.repeat);
1534			}
1535		},
1536
1537		// Plan to review the cssSelector method to cope with missing associated functions accordingly.
1538
1539		currentTime: function(e) { // Handles clicks on the text
1540			// Added to avoid errors using cssSelector system for the text
1541		},
1542		duration: function(e) { // Handles clicks on the text
1543			// Added to avoid errors using cssSelector system for the text
1544		},
1545		gui: function(e) { // Handles clicks on the gui
1546			// Added to avoid errors using cssSelector system for the gui
1547		},
1548
1549		// Options code adapted from ui.widget.js (1.8.7).  Made changes so the key can use dot notation. To match previous getData solution in jPlayer 1.
1550		option: function(key, value) {
1551			var options = key;
1552
1553			 // Enables use: options().  Returns a copy of options object
1554			if ( arguments.length === 0 ) {
1555				return $.extend( true, {}, this.options );
1556			}
1557
1558			if(typeof key === "string") {
1559				var keys = key.split(".");
1560
1561				 // Enables use: options("someOption")  Returns a copy of the option. Supports dot notation.
1562				if(value === undefined) {
1563
1564					var opt = $.extend(true, {}, this.options);
1565					for(var i = 0; i < keys.length; i++) {
1566						if(opt[keys[i]] !== undefined) {
1567							opt = opt[keys[i]];
1568						} else {
1569							this._warning( {
1570								type: $.jPlayer.warning.OPTION_KEY,
1571								context: key,
1572								message: $.jPlayer.warningMsg.OPTION_KEY,
1573								hint: $.jPlayer.warningHint.OPTION_KEY
1574							});
1575							return undefined;
1576						}
1577					}
1578					return opt;
1579				}
1580
1581				 // Enables use: options("someOptionObject", someObject}).  Creates: {someOptionObject:someObject}
1582				 // Enables use: options("someOption", someValue).  Creates: {someOption:someValue}
1583				 // Enables use: options("someOptionObject.someOption", someValue).  Creates: {someOptionObject:{someOption:someValue}}
1584
1585				options = {};
1586				var opts = options;
1587
1588				for(var j = 0; j < keys.length; j++) {
1589					if(j < keys.length - 1) {
1590						opts[keys[j]] = {};
1591						opts = opts[keys[j]];
1592					} else {
1593						opts[keys[j]] = value;
1594					}
1595				}
1596			}
1597
1598			 // Otherwise enables use: options(optionObject).  Uses original object (the key)
1599
1600			this._setOptions(options);
1601
1602			return this;
1603		},
1604		_setOptions: function(options) {
1605			var self = this;
1606			$.each(options, function(key, value) { // This supports the 2 level depth that the options of jPlayer has. Would review if we ever need more depth.
1607				self._setOption(key, value);
1608			});
1609
1610			return this;
1611		},
1612		_setOption: function(key, value) {
1613			var self = this;
1614
1615			// The ability to set options is limited at this time.
1616
1617			switch(key) {
1618				case "volume" :
1619					this.volume(value);
1620					break;
1621				case "muted" :
1622					this._muted(value);
1623					break;
1624				case "cssSelectorAncestor" :
1625					this._cssSelectorAncestor(value); // Set and refresh all associations for the new ancestor.
1626					break;
1627				case "cssSelector" :
1628					$.each(value, function(fn, cssSel) {
1629						self._cssSelector(fn, cssSel); // NB: The option is set inside this function, after further validity checks.
1630					});
1631					break;
1632				case "fullScreen" :
1633					if(this.options[key] !== value) { // if changed
1634						this._removeUiClass();
1635						this.options[key] = value;
1636						this._refreshSize();
1637					}
1638					break;
1639				case "size" :
1640					if(!this.options.fullScreen && this.options[key].cssClass !== value.cssClass) {
1641						this._removeUiClass();
1642					}
1643					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
1644					this._refreshSize();
1645					break;
1646				case "sizeFull" :
1647					if(this.options.fullScreen && this.options[key].cssClass !== value.cssClass) {
1648						this._removeUiClass();
1649					}
1650					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
1651					this._refreshSize();
1652					break;
1653				case "autohide" :
1654					this.options[key] = $.extend({}, this.options[key], value); // store a merged copy of it, incase not all properties changed.
1655					this._updateAutohide();
1656					break;
1657				case "loop" :
1658					this._loop(value);
1659					break;
1660				case "emulateHtml" :
1661					if(this.options[key] !== value) { // To avoid multiple event handlers being created, if true already.
1662						this.options[key] = value;
1663						if(value) {
1664							this._emulateHtmlBridge();
1665						} else {
1666							this._destroyHtmlBridge();
1667						}
1668					}
1669					break;
1670			}
1671
1672			return this;
1673		},
1674		// End of: (Options code adapted from ui.widget.js)
1675
1676		_refreshSize: function() {
1677			this._setSize(); // update status and jPlayer element size
1678			this._addUiClass(); // update the ui class
1679			this._updateSize(); // update internal sizes
1680			this._updateButtons();
1681			this._updateAutohide();
1682			this._trigger($.jPlayer.event.resize);
1683		},
1684		_setSize: function() {
1685			// Determine the current size from the options
1686			if(this.options.fullScreen) {
1687				this.status.width = this.options.sizeFull.width;
1688				this.status.height = this.options.sizeFull.height;
1689				this.status.cssClass = this.options.sizeFull.cssClass;
1690			} else {
1691				this.status.width = this.options.size.width;
1692				this.status.height = this.options.size.height;
1693				this.status.cssClass = this.options.size.cssClass;
1694			}
1695
1696			// Set the size of the jPlayer area.
1697			this.element.css({'width': this.status.width, 'height': this.status.height});
1698		},
1699		_addUiClass: function() {
1700			if(this.ancestorJq.length) {
1701				this.ancestorJq.addClass(this.status.cssClass);
1702			}
1703		},
1704		_removeUiClass: function() {
1705			if(this.ancestorJq.length) {
1706				this.ancestorJq.removeClass(this.status.cssClass);
1707			}
1708		},
1709		_updateSize: function() {
1710			// The poster uses show/hide so can simply resize it.
1711			this.internal.poster.jq.css({'width': this.status.width, 'height': this.status.height});
1712
1713			// Video html or flash resized if necessary at this time.
1714			if(!this.status.waitForPlay) {
1715				if(this.html.active && this.status.video) { // Only if video media
1716					this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
1717				}
1718				else if(this.flash.active) {
1719					this.internal.flash.jq.css({'width': this.status.width, 'height': this.status.height});
1720				}
1721			}
1722		},
1723		_updateAutohide: function() {
1724			var	self = this,
1725				event = "mousemove.jPlayer",
1726				namespace = ".jPlayerAutohide",
1727				eventType = event + namespace,
1728				handler = function() {
1729					self.css.jq.gui.fadeIn(self.options.autohide.fadeIn, function() {
1730						clearTimeout(self.internal.autohideId);
1731						self.internal.autohideId = setTimeout( function() {
1732							self.css.jq.gui.fadeOut(self.options.autohide.fadeOut);
1733						}, self.options.autohide.hold);
1734					});
1735				};
1736
1737			clearTimeout(this.internal.autohideId);
1738			this.element.unbind(namespace);
1739			if(this.css.jq.gui.length) {
1740				this.css.jq.gui.unbind(namespace);
1741				if(this.options.fullScreen && this.options.autohide.full || !this.options.fullScreen && this.options.autohide.restored) {
1742					this.element.bind(eventType, handler);
1743					this.css.jq.gui.bind(eventType, handler);
1744					this.css.jq.gui.hide();
1745				} else {
1746					this.css.jq.gui.stop(true, true).show(); // Need the stop() otherwise a change screen mode during the GUI fade out hides the GUI in the other mode.
1747				}
1748			}
1749		},
1750		fullScreen: function() {
1751			this._setOption("fullScreen", true);
1752		},
1753		restoreScreen: function() {
1754			this._setOption("fullScreen", false);
1755		},
1756		_html_initMedia: function() {
1757			if(this.status.srcSet  && !this.status.waitForPlay) {
1758				this.htmlElement.media.pause();
1759			}
1760			if(this.options.preload !== 'none') {
1761				this._html_load();
1762			}
1763			this._trigger($.jPlayer.event.timeupdate); // The flash generates this event for its solution.
1764		},
1765		_html_setAudio: function(media) {
1766			var self = this;
1767			// Always finds a format due to checks in setMedia()
1768			$.each(this.formats, function(priority, format) {
1769				if(self.html.support[format] && media[format]) {
1770					self.status.src = media[format];
1771					self.status.format[format] = true;
1772					self.status.formatType = format;
1773					return false;
1774				}
1775			});
1776			this.htmlElement.media = this.htmlElement.audio;
1777			this._html_initMedia();
1778		},
1779		_html_setVideo: function(media) {
1780			var self = this;
1781			// Always finds a format due to checks in setMedia()
1782			$.each(this.formats, function(priority, format) {
1783				if(self.html.support[format] && media[format]) {
1784					self.status.src = media[format];
1785					self.status.format[format] = true;
1786					self.status.formatType = format;
1787					return false;
1788				}
1789			});
1790			this.htmlElement.media = this.htmlElement.video;
1791			this._html_initMedia();
1792		},
1793		_html_clearMedia: function() {
1794			if(this.htmlElement.media) {
1795				if(this.htmlElement.media.id === this.internal.video.id) {
1796					this.internal.video.jq.css({'width':'0px', 'height':'0px'});
1797				}
1798				this.htmlElement.media.pause();
1799				this.htmlElement.media.src = "";
1800				this.htmlElement.media.load(); // Stops an old, "in progress" download from continuing the download. Triggers the loadstart, error and emptied events, due to the empty src. Also an abort event if a download was in progress.
1801			}
1802		},
1803		_html_load: function() {
1804			if(this.status.waitForLoad) {
1805				this.status.waitForLoad = false;
1806				this.htmlElement.media.src = this.status.src;
1807				this.htmlElement.media.load();
1808			}
1809			clearTimeout(this.internal.htmlDlyCmdId);
1810		},
1811		_html_play: function(time) {
1812			var self = this;
1813			this._html_load(); // Loads if required and clears any delayed commands.
1814
1815			this.htmlElement.media.play(); // Before currentTime attempt otherwise Firefox 4 Beta never loads.
1816
1817			if(!isNaN(time)) {
1818				try {
1819					this.htmlElement.media.currentTime = time;
1820				} catch(err) {
1821					this.internal.htmlDlyCmdId = setTimeout(function() {
1822						self.play(time);
1823					}, 100);
1824					return; // Cancel execution and wait for the delayed command.
1825				}
1826			}
1827			this._html_checkWaitForPlay();
1828		},
1829		_html_pause: function(time) {
1830			var self = this;
1831			
1832			if(time > 0) { // We do not want the stop() command, which does pause(0), causing a load operation.
1833				this._html_load(); // Loads if required and clears any delayed commands.
1834			} else {
1835				clearTimeout(this.internal.htmlDlyCmdId);
1836			}
1837
1838			// Order of these commands is important for Safari (Win) and IE9. Pause then change currentTime.
1839			this.htmlElement.media.pause();
1840
1841			if(!isNaN(time)) {
1842				try {
1843					this.htmlElement.media.currentTime = time;
1844				} catch(err) {
1845					this.internal.htmlDlyCmdId = setTimeout(function() {
1846						self.pause(time);
1847					}, 100);
1848					return; // Cancel execution and wait for the delayed command.
1849				}
1850			}
1851			if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
1852				this._html_checkWaitForPlay();
1853			}
1854		},
1855		_html_playHead: function(percent) {
1856			var self = this;
1857			this._html_load(); // Loads if required and clears any delayed commands.
1858			try {
1859				if((typeof this.htmlElement.media.seekable === "object") && (this.htmlElement.media.seekable.length > 0)) {
1860					this.htmlElement.media.currentTime = percent * this.htmlElement.media.seekable.end(this.htmlElement.media.seekable.length-1) / 100;
1861				} else if(this.htmlElement.media.duration > 0 && !isNaN(this.htmlElement.media.duration)) {
1862					this.htmlElement.media.currentTime = percent * this.htmlElement.media.duration / 100;
1863				} else {
1864					throw "e";
1865				}
1866			} catch(err) {
1867				this.internal.htmlDlyCmdId = setTimeout(function() {
1868					self.playHead(percent);
1869				}, 100);
1870				return; // Cancel execution and wait for the delayed command.
1871			}
1872			if(!this.status.waitForLoad) {
1873				this._html_checkWaitForPlay();
1874			}
1875		},
1876		_html_checkWaitForPlay: function() {
1877			if(this.status.waitForPlay) {
1878				this.status.waitForPlay = false;
1879				if(this.css.jq.videoPlay.length) {
1880					this.css.jq.videoPlay.hide();
1881				}
1882				if(this.status.video) {
1883					this.internal.poster.jq.hide();
1884					this.internal.video.jq.css({'width': this.status.width, 'height': this.status.height});
1885				}
1886			}
1887		},
1888		_html_volume: function(v) {
1889			if(this.html.audio.available) {
1890				this.htmlElement.audio.volume = v;
1891			}
1892			if(this.html.video.available) {
1893				this.htmlElement.video.volume = v;
1894			}
1895		},
1896		_html_mute: function(m) {
1897			if(this.html.audio.available) {
1898				this.htmlElement.audio.muted = m;
1899			}
1900			if(this.html.video.available) {
1901				this.htmlElement.video.muted = m;
1902			}
1903		},
1904		_flash_setAudio: function(media) {
1905			var self = this;
1906			try {
1907				// Always finds a format due to checks in setMedia()
1908				$.each(this.formats, function(priority, format) {
1909					if(self.flash.support[format] && media[format]) {
1910						switch (format) {
1911							case "m4a" :
1912							case "fla" :
1913								self._getMovie().fl_setAudio_m4a(media[format]);
1914								break;
1915							case "mp3" :
1916								self._getMovie().fl_setAudio_mp3(media[format]);
1917								break;
1918						}
1919						self.status.src = media[format];
1920						self.status.format[format] = true;
1921						self.status.formatType = format;
1922						return false;
vendor: 9,623 bytes, lines 1923-2195
1923					}
1924				});
1925
1926				if(this.options.preload === 'auto') {
1927					this._flash_load();
1928					this.status.waitForLoad = false;
1929				}
1930			} catch(err) { this._flashError(err); }
1931		},
1932		_flash_setVideo: function(media) {
1933			var self = this;
1934			try {
1935				// Always finds a format due to checks in setMedia()
1936				$.each(this.formats, function(priority, format) {
1937					if(self.flash.support[format] && media[format]) {
1938						switch (format) {
1939							case "m4v" :
1940							case "flv" :
1941								self._getMovie().fl_setVideo_m4v(media[format]);
1942								break;
1943						}
1944						self.status.src = media[format];
1945						self.status.format[format] = true;
1946						self.status.formatType = format;
1947						return false;
1948					}
1949				});
1950
1951				if(this.options.preload === 'auto') {
1952					this._flash_load();
1953					this.status.waitForLoad = false;
1954				}
1955			} catch(err) { this._flashError(err); }
1956		},
1957		_flash_clearMedia: function() {
1958			this.internal.flash.jq.css({'width':'0px', 'height':'0px'}); // Must do via CSS as setting attr() to zero causes a jQuery error in IE.
1959			try {
1960				this._getMovie().fl_clearMedia();
1961			} catch(err) { this._flashError(err); }
1962		},
1963		_flash_load: function() {
1964			try {
1965				this._getMovie().fl_load();
1966			} catch(err) { this._flashError(err); }
1967			this.status.waitForLoad = false;
1968		},
1969		_flash_play: function(time) {
1970			try {
1971				this._getMovie().fl_play(time);
1972			} catch(err) { this._flashError(err); }
1973			this.status.waitForLoad = false;
1974			this._flash_checkWaitForPlay();
1975		},
1976		_flash_pause: function(time) {
1977			try {
1978				this._getMovie().fl_pause(time);
1979			} catch(err) { this._flashError(err); }
1980			if(time > 0) { // Avoids a setMedia() followed by stop() or pause(0) hiding the video play button.
1981				this.status.waitForLoad = false;
1982				this._flash_checkWaitForPlay();
1983			}
1984		},
1985		_flash_playHead: function(p) {
1986			try {
1987				this._getMovie().fl_play_head(p);
1988			} catch(err) { this._flashError(err); }
1989			if(!this.status.waitForLoad) {
1990				this._flash_checkWaitForPlay();
1991			}
1992		},
1993		_flash_checkWaitForPlay: function() {
1994			if(this.status.waitForPlay) {
1995				this.status.waitForPlay = false;
1996				if(this.css.jq.videoPlay.length) {
1997					this.css.jq.videoPlay.hide();
1998				}
1999				if(this.status.video) {
2000					this.internal.poster.jq.hide();
2001					this.internal.flash.jq.css({'width': this.status.width, 'height': this.status.height});
2002				}
2003			}
2004		},
2005		_flash_volume: function(v) {
2006			try {
2007				this._getMovie().fl_volume(v);
2008			} catch(err) { this._flashError(err); }
2009		},
2010		_flash_mute: function(m) {
2011			try {
2012				this._getMovie().fl_mute(m);
2013			} catch(err) { this._flashError(err); }
2014		},
2015		_getMovie: function() {
2016			return document[this.internal.flash.id];
2017		},
2018		_checkForFlash: function (version) {
2019			// Function checkForFlash adapted from FlashReplace by Robert Nyman
2020			// http://code.google.com/p/flashreplace/
2021			var flashIsInstalled = false;
2022			var flash;
2023			if(window.ActiveXObject){
2024				try{
2025					flash = new ActiveXObject(("ShockwaveFlash.ShockwaveFlash." + version));
2026					flashIsInstalled = true;
2027				}
2028				catch(e){
2029					// Throws an error if the version isn't available			
2030				}
2031			}
2032			else if(navigator.plugins && navigator.mimeTypes.length > 0){
2033				flash = navigator.plugins["Shockwave Flash"];
2034				if(flash){
2035					var flashVersion = navigator.plugins["Shockwave Flash"].description.replace(/.*\s(\d+\.\d+).*/, "$1");
2036					if(flashVersion >= version){
2037						flashIsInstalled = true;
2038					}
2039				}
2040			}
2041			return flashIsInstalled;
2042		},
2043		_validString: function(url) {
2044			return (url && typeof url === "string"); // Empty strings return false
2045		},
2046		_limitValue: function(value, min, max) {
2047			return (value < min) ? min : ((value > max) ? max : value);
2048		},
2049		_urlNotSetError: function(context) {
2050			this._error( {
2051				type: $.jPlayer.error.URL_NOT_SET,
2052				context: context,
2053				message: $.jPlayer.errorMsg.URL_NOT_SET,
2054				hint: $.jPlayer.errorHint.URL_NOT_SET
2055			});
2056		},
2057		_flashError: function(error) {
2058			var errorType;
2059			if(!this.internal.ready) {
2060				errorType = "FLASH";
2061			} else {
2062				errorType = "FLASH_DISABLED";
2063			}
2064			this._error( {
2065				type: $.jPlayer.error[errorType],
2066				context: this.internal.flash.swf,
2067				message: $.jPlayer.errorMsg[errorType] + error.message,
2068				hint: $.jPlayer.errorHint[errorType]
2069			});
2070
2071		},
2072		_error: function(error) {
2073			this._trigger($.jPlayer.event.error, error);
2074			if(this.options.errorAlerts) {
2075				this._alert("Error!" + (error.message ? "\n\n" + error.message : "") + (error.hint ? "\n\n" + error.hint : "") + "\n\nContext: " + error.context);
2076			}
2077		},
2078		_warning: function(warning) {
2079			this._trigger($.jPlayer.event.warning, undefined, warning);
2080			if(this.options.warningAlerts) {
2081				this._alert("Warning!" + (warning.message ? "\n\n" + warning.message : "") + (warning.hint ? "\n\n" + warning.hint : "") + "\n\nContext: " + warning.context);
2082			}
2083		},
2084		_alert: function(message) {
2085			alert("jPlayer " + this.version.script + " : id='" + this.internal.self.id +"' : " + message);
2086		},
2087		_emulateHtmlBridge: function() {
2088			var self = this,
2089			methods = $.jPlayer.emulateMethods;
2090
2091			// Emulate methods on jPlayer's DOM element.
2092			$.each( $.jPlayer.emulateMethods.split(/\s+/g), function(i, name) {
2093				self.internal.domNode[name] = function(arg) {
2094					self[name](arg);
2095				};
2096
2097			});
2098
2099			// Bubble jPlayer events to its DOM element.
2100			$.each($.jPlayer.event, function(eventName,eventType) {
2101				var nativeEvent = true;
2102				$.each( $.jPlayer.reservedEvent.split(/\s+/g), function(i, name) {
2103					if(name === eventName) {
2104						nativeEvent = false;
2105						return false;
2106					}
2107				});
2108				if(nativeEvent) {
2109					self.element.bind(eventType + ".jPlayer.jPlayerHtml", function() { // With .jPlayer & .jPlayerHtml namespaces.
2110						self._emulateHtmlUpdate();
2111						var domEvent = document.createEvent("Event");
2112						domEvent.initEvent(eventName, false, true);
2113						self.internal.domNode.dispatchEvent(domEvent);
2114					});
2115				}
2116				// The error event would require a special case
2117			});
2118
2119			// IE9 has a readyState property on all elements. The document should have it, but all (except media) elements inherit it in IE9. This conflicts with Popcorn, which polls the readyState.
2120		},
2121		_emulateHtmlUpdate: function() {
2122			var self = this;
2123
2124			$.each( $.jPlayer.emulateStatus.split(/\s+/g), function(i, name) {
2125				self.internal.domNode[name] = self.status[name];
2126			});
2127			$.each( $.jPlayer.emulateOptions.split(/\s+/g), function(i, name) {
2128				self.internal.domNode[name] = self.options[name];
2129			});
2130		},
2131		_destroyHtmlBridge: function() {
2132			var self = this;
2133
2134			// Bridge event handlers are also removed by destroy() through .jPlayer namespace.
2135			this.element.unbind(".jPlayerHtml"); // Remove all event handlers created by the jPlayer bridge. So you can change the emulateHtml option.
2136
2137			// Remove the methods and properties
2138			var emulated = $.jPlayer.emulateMethods + " " + $.jPlayer.emulateStatus + " " + $.jPlayer.emulateOptions;
2139			$.each( emulated.split(/\s+/g), function(i, name) {
2140				delete self.internal.domNode[name];
2141			});
2142		}
2143	};
2144
2145	$.jPlayer.error = {
2146		FLASH: "e_flash",
2147		FLASH_DISABLED: "e_flash_disabled",
2148		NO_SOLUTION: "e_no_solution",
2149		NO_SUPPORT: "e_no_support",
2150		URL: "e_url",
2151		URL_NOT_SET: "e_url_not_set",
2152		VERSION: "e_version"
2153	};
2154
2155	$.jPlayer.errorMsg = {
2156		FLASH: "jPlayer's Flash fallback is not configured correctly, or a command was issued before the jPlayer Ready event. Details: ", // Used in: _flashError()
2157		FLASH_DISABLED: "jPlayer's Flash fallback has been disabled by the browser due to the CSS rules you have used. Details: ", // Used in: _flashError()
2158		NO_SOLUTION: "No solution can be found by jPlayer in this browser. Neither HTML nor Flash can be used.", // Used in: _init()
2159		NO_SUPPORT: "It is not possible to play any media format provided in setMedia() on this browser using your current options.", // Used in: setMedia()
2160		URL: "Media URL could not be loaded.", // Used in: jPlayerFlashEvent() and _addHtmlEventListeners()
2161		URL_NOT_SET: "Attempt to issue media playback commands, while no media url is set.", // Used in: load(), play(), pause(), stop() and playHead()
2162		VERSION: "jPlayer " + $.jPlayer.prototype.version.script + " needs Jplayer.swf version " + $.jPlayer.prototype.version.needFlash + " but found " // Used in: jPlayerReady()
2163	};
2164
2165	$.jPlayer.errorHint = {
2166		FLASH: "Check your swfPath option and that Jplayer.swf is there.",
2167		FLASH_DISABLED: "Check that you have not display:none; the jPlayer entity or any ancestor.",
2168		NO_SOLUTION: "Review the jPlayer options: support and supplied.",
2169		NO_SUPPORT: "Video or audio formats defined in the supplied option are missing.",
2170		URL: "Check media URL is valid.",
2171		URL_NOT_SET: "Use setMedia() to set the media URL.",
2172		VERSION: "Update jPlayer files."
2173	};
2174
2175	$.jPlayer.warning = {
2176		CSS_SELECTOR_COUNT: "e_css_selector_count",
2177		CSS_SELECTOR_METHOD: "e_css_selector_method",
2178		CSS_SELECTOR_STRING: "e_css_selector_string",
2179		OPTION_KEY: "e_option_key"
2180	};
2181
2182	$.jPlayer.warningMsg = {
2183		CSS_SELECTOR_COUNT: "The number of css selectors found did not equal one: ",
2184		CSS_SELECTOR_METHOD: "The methodName given in jPlayer('cssSelector') is not a valid jPlayer method.",
2185		CSS_SELECTOR_STRING: "The methodCssSelector given in jPlayer('cssSelector') is not a String or is empty.",
2186		OPTION_KEY: "The option requested in jPlayer('option') is undefined."
2187	};
2188
2189	$.jPlayer.warningHint = {
2190		CSS_SELECTOR_COUNT: "Check your css selector and the ancestor.",
2191		CSS_SELECTOR_METHOD: "Check your method name.",
2192		CSS_SELECTOR_STRING: "Check your css selector is a string.",
2193		OPTION_KEY: "Check your option name."
2194	};
2195})(jQuery);

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.