Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / docs / source / swfobject.html
1 <html>
2 <head>
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
4   <title>The source code</title>
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
7 </head>
8 <body  onload="prettyPrint();">
9     <pre class="prettyprint lang-js">/*!
10  * Ext JS Library 3.3.1
11  * Copyright(c) 2006-2010 Sencha Inc.
12  * licensing@sencha.com
13  * http://www.sencha.com/license
14  */
15 /*! SWFObject v2.2 <http://code.google.com/p/swfobject/> 
16     is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> 
17 */
18
19 var swfobject = function() {
20     
21     var UNDEF = "undefined",
22         OBJECT = "object",
23         SHOCKWAVE_FLASH = "Shockwave Flash",
24         SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
25         FLASH_MIME_TYPE = "application/x-shockwave-flash",
26         EXPRESS_INSTALL_ID = "SWFObjectExprInst",
27         ON_READY_STATE_CHANGE = "onreadystatechange",
28         
29         win = window,
30         doc = document,
31         nav = navigator,
32         
33         plugin = false,
34         domLoadFnArr = [main],
35         regObjArr = [],
36         objIdArr = [],
37         listenersArr = [],
38         storedAltContent,
39         storedAltContentId,
40         storedCallbackFn,
41         storedCallbackObj,
42         isDomLoaded = false,
43         isExpressInstallActive = false,
44         dynamicStylesheet,
45         dynamicStylesheetMedia,
46         autoHideShow = true,
47     
48     /* Centralized function for browser feature detection
49         - User agent string detection is only used when no good alternative is possible
50         - Is executed directly for optimal performance
51     */  
52     ua = function() {
53         var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF,
54             u = nav.userAgent.toLowerCase(),
55             p = nav.platform.toLowerCase(),
56             windows = p ? (/win/).test(p) : /win/.test(u),
57             mac = p ? (/mac/).test(p) : /mac/.test(u),
58             webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit
59             ie = !+"\v1", // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
60             playerVersion = [0,0,0],
61             d = null;
62         if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
63             d = nav.plugins[SHOCKWAVE_FLASH].description;
64             if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
65                 plugin = true;
66                 ie = false; // cascaded feature detection for Internet Explorer
67                 d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
68                 playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10);
69                 playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
70                 playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0;
71             }
72         }
73         else if (typeof win.ActiveXObject != UNDEF) {
74             try {
75                 var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
76                 if (a) { // a will return null when ActiveX is disabled
77                     d = a.GetVariable("$version");
78                     if (d) {
79                         ie = true; // cascaded feature detection for Internet Explorer
80                         d = d.split(" ")[1].split(",");
81                         playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
82                     }
83                 }
84             }
85             catch(e) {}
86         }
87         return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac };
88     }(),
89     
90     /* Cross-browser onDomLoad
91         - Will fire an event as soon as the DOM of a web page is loaded
92         - Internet Explorer workaround based on Diego Perini's solution: http://javascript.nwbox.com/IEContentLoaded/
93         - Regular onload serves as fallback
94     */ 
95     onDomLoad = function() {
96         if (!ua.w3) { return; }
97         if ((typeof doc.readyState != UNDEF && doc.readyState == "complete") || (typeof doc.readyState == UNDEF && (doc.getElementsByTagName("body")[0] || doc.body))) { // function is fired after onload, e.g. when script is inserted dynamically 
98             callDomLoadFunctions();
99         }
100         if (!isDomLoaded) {
101             if (typeof doc.addEventListener != UNDEF) {
102                 doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false);
103             }       
104             if (ua.ie && ua.win) {
105                 doc.attachEvent(ON_READY_STATE_CHANGE, function() {
106                     if (doc.readyState == "complete") {
107                         doc.detachEvent(ON_READY_STATE_CHANGE, arguments.callee);
108                         callDomLoadFunctions();
109                     }
110                 });
111                 if (win == top) { // if not inside an iframe
112                     (function(){
113                         if (isDomLoaded) { return; }
114                         try {
115                             doc.documentElement.doScroll("left");
116                         }
117                         catch(e) {
118                             setTimeout(arguments.callee, 0);
119                             return;
120                         }
121                         callDomLoadFunctions();
122                     })();
123                 }
124             }
125             if (ua.wk) {
126                 (function(){
127                     if (isDomLoaded) { return; }
128                     if (!(/loaded|complete/).test(doc.readyState)) {
129                         setTimeout(arguments.callee, 0);
130                         return;
131                     }
132                     callDomLoadFunctions();
133                 })();
134             }
135             addLoadEvent(callDomLoadFunctions);
136         }
137     }();
138     
139     function callDomLoadFunctions() {
140         if (isDomLoaded) { return; }
141         try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early
142             var t = doc.getElementsByTagName("body")[0].appendChild(createElement("span"));
143             t.parentNode.removeChild(t);
144         }
145         catch (e) { return; }
146         isDomLoaded = true;
147         var dl = domLoadFnArr.length;
148         for (var i = 0; i < dl; i++) {
149             domLoadFnArr[i]();
150         }
151     }
152     
153     function addDomLoadEvent(fn) {
154         if (isDomLoaded) {
155             fn();
156         }
157         else { 
158             domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+
159         }
160     }
161     
162     /* Cross-browser onload
163         - Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/
164         - Will fire an event as soon as a web page including all of its assets are loaded 
165      */
166     function addLoadEvent(fn) {
167         if (typeof win.addEventListener != UNDEF) {
168             win.addEventListener("load", fn, false);
169         }
170         else if (typeof doc.addEventListener != UNDEF) {
171             doc.addEventListener("load", fn, false);
172         }
173         else if (typeof win.attachEvent != UNDEF) {
174             addListener(win, "onload", fn);
175         }
176         else if (typeof win.onload == "function") {
177             var fnOld = win.onload;
178             win.onload = function() {
179                 fnOld();
180                 fn();
181             };
182         }
183         else {
184             win.onload = fn;
185         }
186     }
187     
188     /* Main function
189         - Will preferably execute onDomLoad, otherwise onload (as a fallback)
190     */
191     function main() { 
192         if (plugin) {
193             testPlayerVersion();
194         }
195         else {
196             matchVersions();
197         }
198     }
199     
200     /* Detect the Flash Player version for non-Internet Explorer browsers
201         - Detecting the plug-in version via the object element is more precise than using the plugins collection item's description:
202           a. Both release and build numbers can be detected
203           b. Avoid wrong descriptions by corrupt installers provided by Adobe
204           c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports
205         - Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available
206     */
207     function testPlayerVersion() {
208         var b = doc.getElementsByTagName("body")[0];
209         var o = createElement(OBJECT);
210         o.setAttribute("type", FLASH_MIME_TYPE);
211         var t = b.appendChild(o);
212         if (t) {
213             var counter = 0;
214             (function(){
215                 if (typeof t.GetVariable != UNDEF) {
216                     var d = t.GetVariable("$version");
217                     if (d) {
218                         d = d.split(" ")[1].split(",");
219                         ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
220                     }
221                 }
222                 else if (counter < 10) {
223                     counter++;
224                     setTimeout(arguments.callee, 10);
225                     return;
226                 }
227                 b.removeChild(o);
228                 t = null;
229                 matchVersions();
230             })();
231         }
232         else {
233             matchVersions();
234         }
235     }
236     
237     /* Perform Flash Player and SWF version matching; static publishing only
238     */
239     function matchVersions() {
240         var rl = regObjArr.length;
241         if (rl > 0) {
242             for (var i = 0; i < rl; i++) { // for each registered object element
243                 var id = regObjArr[i].id;
244                 var cb = regObjArr[i].callbackFn;
245                 var cbObj = {success:false, id:id};
246                 if (ua.pv[0] > 0) {
247                     var obj = getElementById(id);
248                     if (obj) {
249                         if (hasPlayerVersion(regObjArr[i].swfVersion) && !(ua.wk && ua.wk < 312)) { // Flash Player version >= published SWF version: Houston, we have a match!
250                             setVisibility(id, true);
251                             if (cb) {
252                                 cbObj.success = true;
253                                 cbObj.ref = getObjectById(id);
254                                 cb(cbObj);
255                             }
256                         }
257                         else if (regObjArr[i].expressInstall && canExpressInstall()) { // show the Adobe Express Install dialog if set by the web page author and if supported
258                             var att = {};
259                             att.data = regObjArr[i].expressInstall;
260                             att.width = obj.getAttribute("width") || "0";
261                             att.height = obj.getAttribute("height") || "0";
262                             if (obj.getAttribute("class")) { att.styleclass = obj.getAttribute("class"); }
263                             if (obj.getAttribute("align")) { att.align = obj.getAttribute("align"); }
264                             // parse HTML object param element's name-value pairs
265                             var par = {};
266                             var p = obj.getElementsByTagName("param");
267                             var pl = p.length;
268                             for (var j = 0; j < pl; j++) {
269                                 if (p[j].getAttribute("name").toLowerCase() != "movie") {
270                                     par[p[j].getAttribute("name")] = p[j].getAttribute("value");
271                                 }
272                             }
273                             showExpressInstall(att, par, id, cb);
274                         }
275                         else { // Flash Player and SWF version mismatch or an older Webkit engine that ignores the HTML object element's nested param elements: display alternative content instead of SWF
276                             displayAltContent(obj);
277                             if (cb) { cb(cbObj); }
278                         }
279                     }
280                 }
281                 else {  // if no Flash Player is installed or the fp version cannot be detected we let the HTML object element do its job (either show a SWF or alternative content)
282                     setVisibility(id, true);
283                     if (cb) {
284                         var o = getObjectById(id); // test whether there is an HTML object element or not
285                         if (o && typeof o.SetVariable != UNDEF) { 
286                             cbObj.success = true;
287                             cbObj.ref = o;
288                         }
289                         cb(cbObj);
290                     }
291                 }
292             }
293         }
294     }
295     
296     function getObjectById(objectIdStr) {
297         var r = null;
298         var o = getElementById(objectIdStr);
299         if (o && o.nodeName == "OBJECT") {
300             if (typeof o.SetVariable != UNDEF) {
301                 r = o;
302             }
303             else {
304                 var n = o.getElementsByTagName(OBJECT)[0];
305                 if (n) {
306                     r = n;
307                 }
308             }
309         }
310         return r;
311     }
312     
313     /* Requirements for Adobe Express Install
314         - only one instance can be active at a time
315         - fp 6.0.65 or higher
316         - Win/Mac OS only
317         - no Webkit engines older than version 312
318     */
319     function canExpressInstall() {
320         return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312);
321     }
322     
323     /* Show the Adobe Express Install dialog
324         - Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75
325     */
326     function showExpressInstall(att, par, replaceElemIdStr, callbackFn) {
327         isExpressInstallActive = true;
328         storedCallbackFn = callbackFn || null;
329         storedCallbackObj = {success:false, id:replaceElemIdStr};
330         var obj = getElementById(replaceElemIdStr);
331         if (obj) {
332             if (obj.nodeName == "OBJECT") { // static publishing
333                 storedAltContent = abstractAltContent(obj);
334                 storedAltContentId = null;
335             }
336             else { // dynamic publishing
337                 storedAltContent = obj;
338                 storedAltContentId = replaceElemIdStr;
339             }
340             att.id = EXPRESS_INSTALL_ID;
341             if (typeof att.width == UNDEF || (!(/%$/).test(att.width) && parseInt(att.width, 10) < 310)) {
342                 att.width = "310";
343             }
344             
345             if (typeof att.height == UNDEF || (!(/%$/).test(att.height) && parseInt(att.height, 10) < 137)) {
346                 att.height = "137";
347             }
348             doc.title = doc.title.slice(0, 47) + " - Flash Player Installation";
349             var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn",
350                 fv = "MMredirectURL=" + win.location.toString().replace(/&/g,"%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title;
351             if (typeof par.flashvars != UNDEF) {
352                 par.flashvars += "&" + fv;
353             }
354             else {
355                 par.flashvars = fv;
356             }
357             // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
358             // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
359             if (ua.ie && ua.win && obj.readyState != 4) {
360                 var newObj = createElement("div");
361                 replaceElemIdStr += "SWFObjectNew";
362                 newObj.setAttribute("id", replaceElemIdStr);
363                 obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf
364                 obj.style.display = "none";
365                 (function(){
366                     if (obj.readyState == 4) {
367                         obj.parentNode.removeChild(obj);
368                     }
369                     else {
370                         setTimeout(arguments.callee, 10);
371                     }
372                 })();
373             }
374             createSWF(att, par, replaceElemIdStr);
375         }
376     }
377     
378     /* Functions to abstract and display alternative content
379     */
380     function displayAltContent(obj) {
381         if (ua.ie && ua.win && obj.readyState != 4) {
382             // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
383             // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
384             var el = createElement("div");
385             obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content
386             el.parentNode.replaceChild(abstractAltContent(obj), el);
387             obj.style.display = "none";
388             (function(){
389                 if (obj.readyState == 4) {
390                     obj.parentNode.removeChild(obj);
391                 }
392                 else {
393                     setTimeout(arguments.callee, 10);
394                 }
395             })();
396         }
397         else {
398             obj.parentNode.replaceChild(abstractAltContent(obj), obj);
399         }
400     } 
401
402     function abstractAltContent(obj) {
403         var ac = createElement("div");
404         if (ua.win && ua.ie) {
405             ac.innerHTML = obj.innerHTML;
406         }
407         else {
408             var nestedObj = obj.getElementsByTagName(OBJECT)[0];
409             if (nestedObj) {
410                 var c = nestedObj.childNodes;
411                 if (c) {
412                     var cl = c.length;
413                     for (var i = 0; i < cl; i++) {
414                         if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) {
415                             ac.appendChild(c[i].cloneNode(true));
416                         }
417                     }
418                 }
419             }
420         }
421         return ac;
422     }
423     
424     /* Cross-browser dynamic SWF creation
425     */
426     function createSWF(attObj, parObj, id) {
427         var r, el = getElementById(id);
428         if (ua.wk && ua.wk < 312) { return r; }
429         if (el) {
430             if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
431                 attObj.id = id;
432             }
433             if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML
434                 var att = "";
435                 for (var i in attObj) {
436                     if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries
437                         if (i.toLowerCase() == "data") {
438                             parObj.movie = attObj[i];
439                         }
440                         else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
441                             att += ' class="' + attObj[i] + '"';
442                         }
443                         else if (i.toLowerCase() != "classid") {
444                             att += ' ' + i + '="' + attObj[i] + '"';
445                         }
446                     }
447                 }
448                 var par = "";
449                 for (var j in parObj) {
450                     if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries
451                         par += '<param name="' + j + '" value="' + parObj[j] + '" />';
452                     }
453                 }
454                 el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>';
455                 objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only)
456                 r = getElementById(attObj.id);  
457             }
458             else { // well-behaving browsers
459                 var o = createElement(OBJECT);
460                 o.setAttribute("type", FLASH_MIME_TYPE);
461                 for (var m in attObj) {
462                     if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries
463                         if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
464                             o.setAttribute("class", attObj[m]);
465                         }
466                         else if (m.toLowerCase() != "classid") { // filter out IE specific attribute
467                             o.setAttribute(m, attObj[m]);
468                         }
469                     }
470                 }
471                 for (var n in parObj) {
472                     if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element
473                         createObjParam(o, n, parObj[n]);
474                     }
475                 }
476                 el.parentNode.replaceChild(o, el);
477                 r = o;
478             }
479         }
480         return r;
481     }
482     
483     function createObjParam(el, pName, pValue) {
484         var p = createElement("param");
485         p.setAttribute("name", pName);  
486         p.setAttribute("value", pValue);
487         el.appendChild(p);
488     }
489     
490     /* Cross-browser SWF removal
491         - Especially needed to safely and completely remove a SWF in Internet Explorer
492     */
493     function removeSWF(id) {
494         var obj = getElementById(id);
495         if (obj && obj.nodeName == "OBJECT") {
496             if (ua.ie && ua.win) {
497                 obj.style.display = "none";
498                 (function(){
499                     if (obj.readyState == 4) {
500                         removeObjectInIE(id);
501                     }
502                     else {
503                         setTimeout(arguments.callee, 10);
504                     }
505                 })();
506             }
507             else {
508                 obj.parentNode.removeChild(obj);
509             }
510         }
511     }
512     
513     function removeObjectInIE(id) {
514         var obj = getElementById(id);
515         if (obj) {
516             for (var i in obj) {
517                 if (typeof obj[i] == "function") {
518                     obj[i] = null;
519                 }
520             }
521             obj.parentNode.removeChild(obj);
522         }
523     }
524     
525     /* Functions to optimize JavaScript compression
526     */
527     function getElementById(id) {
528         var el = null;
529         try {
530             el = doc.getElementById(id);
531         }
532         catch (e) {}
533         return el;
534     }
535     
536     function createElement(el) {
537         return doc.createElement(el);
538     }
539     
540     /* Updated attachEvent function for Internet Explorer
541         - Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks
542     */  
543     function addListener(target, eventType, fn) {
544         target.attachEvent(eventType, fn);
545         listenersArr[listenersArr.length] = [target, eventType, fn];
546     }
547     
548     /* Flash Player and SWF content version matching
549     */
550     function hasPlayerVersion(rv) {
551         var pv = ua.pv, v = rv.split(".");
552         v[0] = parseInt(v[0], 10);
553         v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
554         v[2] = parseInt(v[2], 10) || 0;
555         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;
556     }
557     
558     /* Cross-browser dynamic CSS creation
559         - Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php
560     */  
561     function createCSS(sel, decl, media, newStyle) {
562         if (ua.ie && ua.mac) { return; }
563         var h = doc.getElementsByTagName("head")[0];
564         if (!h) { return; } // to also support badly authored HTML pages that lack a head element
565         var m = (media && typeof media == "string") ? media : "screen";
566         if (newStyle) {
567             dynamicStylesheet = null;
568             dynamicStylesheetMedia = null;
569         }
570         if (!dynamicStylesheet || dynamicStylesheetMedia != m) { 
571             // create dynamic stylesheet + get a global reference to it
572             var s = createElement("style");
573             s.setAttribute("type", "text/css");
574             s.setAttribute("media", m);
575             dynamicStylesheet = h.appendChild(s);
576             if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) {
577                 dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1];
578             }
579             dynamicStylesheetMedia = m;
580         }
581         // add style rule
582         if (ua.ie && ua.win) {
583             if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) {
584                 dynamicStylesheet.addRule(sel, decl);
585             }
586         }
587         else {
588             if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) {
589                 dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}"));
590             }
591         }
592     }
593     
594     function setVisibility(id, isVisible) {
595         if (!autoHideShow) { return; }
596         var v = isVisible ? "visible" : "hidden";
597         if (isDomLoaded && getElementById(id)) {
598             getElementById(id).style.visibility = v;
599         }
600         else {
601             createCSS("#" + id, "visibility:" + v);
602         }
603     }
604
605     /* Filter to avoid XSS attacks
606     */
607     function urlEncodeIfNecessary(s) {
608         var regex = /[\\\"<>\.;]/;
609         var hasBadChars = regex.exec(s) != null;
610         return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s;
611     }
612     
613     /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
614     */
615     var cleanup = function() {
616         if (ua.ie && ua.win) {
617             window.attachEvent("onunload", function() {
618                 // remove listeners to avoid memory leaks
619                 var ll = listenersArr.length;
620                 for (var i = 0; i < ll; i++) {
621                     listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]);
622                 }
623                 // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
624                 var il = objIdArr.length;
625                 for (var j = 0; j < il; j++) {
626                     removeSWF(objIdArr[j]);
627                 }
628                 // cleanup library's main closures to avoid memory leaks
629                 for (var k in ua) {
630                     ua[k] = null;
631                 }
632                 ua = null;
633                 for (var l in swfobject) {
634                     swfobject[l] = null;
635                 }
636                 swfobject = null;
637             });
638         }
639     }();
640     
641     return {
642         /* Public API
643             - Reference: http://code.google.com/p/swfobject/wiki/documentation
644         */ 
645         registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) {
646             if (ua.w3 && objectIdStr && swfVersionStr) {
647                 var regObj = {};
648                 regObj.id = objectIdStr;
649                 regObj.swfVersion = swfVersionStr;
650                 regObj.expressInstall = xiSwfUrlStr;
651                 regObj.callbackFn = callbackFn;
652                 regObjArr[regObjArr.length] = regObj;
653                 setVisibility(objectIdStr, false);
654             }
655             else if (callbackFn) {
656                 callbackFn({success:false, id:objectIdStr});
657             }
658         },
659         
660         getObjectById: function(objectIdStr) {
661             if (ua.w3) {
662                 return getObjectById(objectIdStr);
663             }
664         },
665         
666         embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) {
667             var callbackObj = {success:false, id:replaceElemIdStr};
668             if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) {
669                 setVisibility(replaceElemIdStr, false);
670                 addDomLoadEvent(function() {
671                     widthStr += ""; // auto-convert to string
672                     heightStr += "";
673                     var att = {};
674                     if (attObj && typeof attObj === OBJECT) {
675                         for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs
676                             att[i] = attObj[i];
677                         }
678                     }
679                     att.data = swfUrlStr;
680                     att.width = widthStr;
681                     att.height = heightStr;
682                     var par = {}; 
683                     if (parObj && typeof parObj === OBJECT) {
684                         for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs
685                             par[j] = parObj[j];
686                         }
687                     }
688                     if (flashvarsObj && typeof flashvarsObj === OBJECT) {
689                         for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs
690                             if (typeof par.flashvars != UNDEF) {
691                                 par.flashvars += "&" + k + "=" + flashvarsObj[k];
692                             }
693                             else {
694                                 par.flashvars = k + "=" + flashvarsObj[k];
695                             }
696                         }
697                     }
698                     if (hasPlayerVersion(swfVersionStr)) { // create SWF
699                         var obj = createSWF(att, par, replaceElemIdStr);
700                         if (att.id == replaceElemIdStr) {
701                             setVisibility(replaceElemIdStr, true);
702                         }
703                         callbackObj.success = true;
704                         callbackObj.ref = obj;
705                     }
706                     else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install
707                         att.data = xiSwfUrlStr;
708                         showExpressInstall(att, par, replaceElemIdStr, callbackFn);
709                         return;
710                     }
711                     else { // show alternative content
712                         setVisibility(replaceElemIdStr, true);
713                     }
714                     if (callbackFn) { callbackFn(callbackObj); }
715                 });
716             }
717             else if (callbackFn) { callbackFn(callbackObj); }
718         },
719         
720         switchOffAutoHideShow: function() {
721             autoHideShow = false;
722         },
723         
724         ua: ua,
725         
726         getFlashPlayerVersion: function() {
727             return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };
728         },
729         
730         hasFlashPlayerVersion: hasPlayerVersion,
731         
732         createSWF: function(attObj, parObj, replaceElemIdStr) {
733             if (ua.w3) {
734                 return createSWF(attObj, parObj, replaceElemIdStr);
735             }
736             else {
737                 return undefined;
738             }
739         },
740         
741         showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) {
742             if (ua.w3 && canExpressInstall()) {
743                 showExpressInstall(att, par, replaceElemIdStr, callbackFn);
744             }
745         },
746         
747         removeSWF: function(objElemIdStr) {
748             if (ua.w3) {
749                 removeSWF(objElemIdStr);
750             }
751         },
752         
753         createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) {
754             if (ua.w3) {
755                 createCSS(selStr, declStr, mediaStr, newStyleBoolean);
756             }
757         },
758         
759         addDomLoadEvent: addDomLoadEvent,
760         
761         addLoadEvent: addLoadEvent,
762         
763         getQueryParamValue: function(param) {
764             var q = doc.location.search || doc.location.hash;
765             if (q) {
766                 if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark
767                 if (param == null) {
768                     return urlEncodeIfNecessary(q);
769                 }
770                 var pairs = q.split("&");
771                 for (var i = 0; i < pairs.length; i++) {
772                     if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
773                         return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
774                     }
775                 }
776             }
777             return "";
778         },
779         
780         // For internal usage only
781         expressInstallCallback: function() {
782             if (isExpressInstallActive) {
783                 var obj = getElementById(EXPRESS_INSTALL_ID);
784                 if (obj && storedAltContent) {
785                     obj.parentNode.replaceChild(storedAltContent, obj);
786                     if (storedAltContentId) {
787                         setVisibility(storedAltContentId, true);
788                         if (ua.ie && ua.win) { storedAltContent.style.display = "block"; }
789                     }
790                     if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); }
791                 }
792                 isExpressInstallActive = false;
793             } 
794         }
795     };
796 }();
797 </pre>    
798 </body>
799 </html>