Upgrade to ExtJS 3.2.0 - Released 03/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.2.0
11  * Copyright(c) 2006-2010 Ext JS, Inc.
12  * licensing@extjs.com
13  * http://www.extjs.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)) { att.width = "310"; }
342             if (typeof att.height == UNDEF || (!/%$/.test(att.height) && parseInt(att.height, 10) < 137)) { att.height = "137"; }
343             doc.title = doc.title.slice(0, 47) + " - Flash Player Installation";
344             var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn",
345                 fv = "MMredirectURL=" + win.location.toString().replace(/&/g,"%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title;
346             if (typeof par.flashvars != UNDEF) {
347                 par.flashvars += "&" + fv;
348             }
349             else {
350                 par.flashvars = fv;
351             }
352             // 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,
353             // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
354             if (ua.ie && ua.win && obj.readyState != 4) {
355                 var newObj = createElement("div");
356                 replaceElemIdStr += "SWFObjectNew";
357                 newObj.setAttribute("id", replaceElemIdStr);
358                 obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf
359                 obj.style.display = "none";
360                 (function(){
361                     if (obj.readyState == 4) {
362                         obj.parentNode.removeChild(obj);
363                     }
364                     else {
365                         setTimeout(arguments.callee, 10);
366                     }
367                 })();
368             }
369             createSWF(att, par, replaceElemIdStr);
370         }
371     }
372     
373     /* Functions to abstract and display alternative content
374     */
375     function displayAltContent(obj) {
376         if (ua.ie && ua.win && obj.readyState != 4) {
377             // 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,
378             // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
379             var el = createElement("div");
380             obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content
381             el.parentNode.replaceChild(abstractAltContent(obj), el);
382             obj.style.display = "none";
383             (function(){
384                 if (obj.readyState == 4) {
385                     obj.parentNode.removeChild(obj);
386                 }
387                 else {
388                     setTimeout(arguments.callee, 10);
389                 }
390             })();
391         }
392         else {
393             obj.parentNode.replaceChild(abstractAltContent(obj), obj);
394         }
395     } 
396
397     function abstractAltContent(obj) {
398         var ac = createElement("div");
399         if (ua.win && ua.ie) {
400             ac.innerHTML = obj.innerHTML;
401         }
402         else {
403             var nestedObj = obj.getElementsByTagName(OBJECT)[0];
404             if (nestedObj) {
405                 var c = nestedObj.childNodes;
406                 if (c) {
407                     var cl = c.length;
408                     for (var i = 0; i < cl; i++) {
409                         if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) {
410                             ac.appendChild(c[i].cloneNode(true));
411                         }
412                     }
413                 }
414             }
415         }
416         return ac;
417     }
418     
419     /* Cross-browser dynamic SWF creation
420     */
421     function createSWF(attObj, parObj, id) {
422         var r, el = getElementById(id);
423         if (ua.wk && ua.wk < 312) { return r; }
424         if (el) {
425             if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
426                 attObj.id = id;
427             }
428             if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML
429                 var att = "";
430                 for (var i in attObj) {
431                     if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries
432                         if (i.toLowerCase() == "data") {
433                             parObj.movie = attObj[i];
434                         }
435                         else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
436                             att += ' class="' + attObj[i] + '"';
437                         }
438                         else if (i.toLowerCase() != "classid") {
439                             att += ' ' + i + '="' + attObj[i] + '"';
440                         }
441                     }
442                 }
443                 var par = "";
444                 for (var j in parObj) {
445                     if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries
446                         par += '<param name="' + j + '" value="' + parObj[j] + '" />';
447                     }
448                 }
449                 el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>';
450                 objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only)
451                 r = getElementById(attObj.id);  
452             }
453             else { // well-behaving browsers
454                 var o = createElement(OBJECT);
455                 o.setAttribute("type", FLASH_MIME_TYPE);
456                 for (var m in attObj) {
457                     if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries
458                         if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
459                             o.setAttribute("class", attObj[m]);
460                         }
461                         else if (m.toLowerCase() != "classid") { // filter out IE specific attribute
462                             o.setAttribute(m, attObj[m]);
463                         }
464                     }
465                 }
466                 for (var n in parObj) {
467                     if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element
468                         createObjParam(o, n, parObj[n]);
469                     }
470                 }
471                 el.parentNode.replaceChild(o, el);
472                 r = o;
473             }
474         }
475         return r;
476     }
477     
478     function createObjParam(el, pName, pValue) {
479         var p = createElement("param");
480         p.setAttribute("name", pName);  
481         p.setAttribute("value", pValue);
482         el.appendChild(p);
483     }
484     
485     /* Cross-browser SWF removal
486         - Especially needed to safely and completely remove a SWF in Internet Explorer
487     */
488     function removeSWF(id) {
489         var obj = getElementById(id);
490         if (obj && obj.nodeName == "OBJECT") {
491             if (ua.ie && ua.win) {
492                 obj.style.display = "none";
493                 (function(){
494                     if (obj.readyState == 4) {
495                         removeObjectInIE(id);
496                     }
497                     else {
498                         setTimeout(arguments.callee, 10);
499                     }
500                 })();
501             }
502             else {
503                 obj.parentNode.removeChild(obj);
504             }
505         }
506     }
507     
508     function removeObjectInIE(id) {
509         var obj = getElementById(id);
510         if (obj) {
511             for (var i in obj) {
512                 if (typeof obj[i] == "function") {
513                     obj[i] = null;
514                 }
515             }
516             obj.parentNode.removeChild(obj);
517         }
518     }
519     
520     /* Functions to optimize JavaScript compression
521     */
522     function getElementById(id) {
523         var el = null;
524         try {
525             el = doc.getElementById(id);
526         }
527         catch (e) {}
528         return el;
529     }
530     
531     function createElement(el) {
532         return doc.createElement(el);
533     }
534     
535     /* Updated attachEvent function for Internet Explorer
536         - Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks
537     */  
538     function addListener(target, eventType, fn) {
539         target.attachEvent(eventType, fn);
540         listenersArr[listenersArr.length] = [target, eventType, fn];
541     }
542     
543     /* Flash Player and SWF content version matching
544     */
545     function hasPlayerVersion(rv) {
546         var pv = ua.pv, v = rv.split(".");
547         v[0] = parseInt(v[0], 10);
548         v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
549         v[2] = parseInt(v[2], 10) || 0;
550         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;
551     }
552     
553     /* Cross-browser dynamic CSS creation
554         - Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php
555     */  
556     function createCSS(sel, decl, media, newStyle) {
557         if (ua.ie && ua.mac) { return; }
558         var h = doc.getElementsByTagName("head")[0];
559         if (!h) { return; } // to also support badly authored HTML pages that lack a head element
560         var m = (media && typeof media == "string") ? media : "screen";
561         if (newStyle) {
562             dynamicStylesheet = null;
563             dynamicStylesheetMedia = null;
564         }
565         if (!dynamicStylesheet || dynamicStylesheetMedia != m) { 
566             // create dynamic stylesheet + get a global reference to it
567             var s = createElement("style");
568             s.setAttribute("type", "text/css");
569             s.setAttribute("media", m);
570             dynamicStylesheet = h.appendChild(s);
571             if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) {
572                 dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1];
573             }
574             dynamicStylesheetMedia = m;
575         }
576         // add style rule
577         if (ua.ie && ua.win) {
578             if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) {
579                 dynamicStylesheet.addRule(sel, decl);
580             }
581         }
582         else {
583             if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) {
584                 dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}"));
585             }
586         }
587     }
588     
589     function setVisibility(id, isVisible) {
590         if (!autoHideShow) { return; }
591         var v = isVisible ? "visible" : "hidden";
592         if (isDomLoaded && getElementById(id)) {
593             getElementById(id).style.visibility = v;
594         }
595         else {
596             createCSS("#" + id, "visibility:" + v);
597         }
598     }
599
600     /* Filter to avoid XSS attacks
601     */
602     function urlEncodeIfNecessary(s) {
603         var regex = /[\\\"<>\.;]/;
604         var hasBadChars = regex.exec(s) != null;
605         return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s;
606     }
607     
608     /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
609     */
610     var cleanup = function() {
611         if (ua.ie && ua.win) {
612             window.attachEvent("onunload", function() {
613                 // remove listeners to avoid memory leaks
614                 var ll = listenersArr.length;
615                 for (var i = 0; i < ll; i++) {
616                     listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]);
617                 }
618                 // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
619                 var il = objIdArr.length;
620                 for (var j = 0; j < il; j++) {
621                     removeSWF(objIdArr[j]);
622                 }
623                 // cleanup library's main closures to avoid memory leaks
624                 for (var k in ua) {
625                     ua[k] = null;
626                 }
627                 ua = null;
628                 for (var l in swfobject) {
629                     swfobject[l] = null;
630                 }
631                 swfobject = null;
632             });
633         }
634     }();
635     
636     return {
637         /* Public API
638             - Reference: http://code.google.com/p/swfobject/wiki/documentation
639         */ 
640         registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) {
641             if (ua.w3 && objectIdStr && swfVersionStr) {
642                 var regObj = {};
643                 regObj.id = objectIdStr;
644                 regObj.swfVersion = swfVersionStr;
645                 regObj.expressInstall = xiSwfUrlStr;
646                 regObj.callbackFn = callbackFn;
647                 regObjArr[regObjArr.length] = regObj;
648                 setVisibility(objectIdStr, false);
649             }
650             else if (callbackFn) {
651                 callbackFn({success:false, id:objectIdStr});
652             }
653         },
654         
655         getObjectById: function(objectIdStr) {
656             if (ua.w3) {
657                 return getObjectById(objectIdStr);
658             }
659         },
660         
661         embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) {
662             var callbackObj = {success:false, id:replaceElemIdStr};
663             if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) {
664                 setVisibility(replaceElemIdStr, false);
665                 addDomLoadEvent(function() {
666                     widthStr += ""; // auto-convert to string
667                     heightStr += "";
668                     var att = {};
669                     if (attObj && typeof attObj === OBJECT) {
670                         for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs
671                             att[i] = attObj[i];
672                         }
673                     }
674                     att.data = swfUrlStr;
675                     att.width = widthStr;
676                     att.height = heightStr;
677                     var par = {}; 
678                     if (parObj && typeof parObj === OBJECT) {
679                         for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs
680                             par[j] = parObj[j];
681                         }
682                     }
683                     if (flashvarsObj && typeof flashvarsObj === OBJECT) {
684                         for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs
685                             if (typeof par.flashvars != UNDEF) {
686                                 par.flashvars += "&" + k + "=" + flashvarsObj[k];
687                             }
688                             else {
689                                 par.flashvars = k + "=" + flashvarsObj[k];
690                             }
691                         }
692                     }
693                     if (hasPlayerVersion(swfVersionStr)) { // create SWF
694                         var obj = createSWF(att, par, replaceElemIdStr);
695                         if (att.id == replaceElemIdStr) {
696                             setVisibility(replaceElemIdStr, true);
697                         }
698                         callbackObj.success = true;
699                         callbackObj.ref = obj;
700                     }
701                     else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install
702                         att.data = xiSwfUrlStr;
703                         showExpressInstall(att, par, replaceElemIdStr, callbackFn);
704                         return;
705                     }
706                     else { // show alternative content
707                         setVisibility(replaceElemIdStr, true);
708                     }
709                     if (callbackFn) { callbackFn(callbackObj); }
710                 });
711             }
712             else if (callbackFn) { callbackFn(callbackObj); }
713         },
714         
715         switchOffAutoHideShow: function() {
716             autoHideShow = false;
717         },
718         
719         ua: ua,
720         
721         getFlashPlayerVersion: function() {
722             return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };
723         },
724         
725         hasFlashPlayerVersion: hasPlayerVersion,
726         
727         createSWF: function(attObj, parObj, replaceElemIdStr) {
728             if (ua.w3) {
729                 return createSWF(attObj, parObj, replaceElemIdStr);
730             }
731             else {
732                 return undefined;
733             }
734         },
735         
736         showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) {
737             if (ua.w3 && canExpressInstall()) {
738                 showExpressInstall(att, par, replaceElemIdStr, callbackFn);
739             }
740         },
741         
742         removeSWF: function(objElemIdStr) {
743             if (ua.w3) {
744                 removeSWF(objElemIdStr);
745             }
746         },
747         
748         createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) {
749             if (ua.w3) {
750                 createCSS(selStr, declStr, mediaStr, newStyleBoolean);
751             }
752         },
753         
754         addDomLoadEvent: addDomLoadEvent,
755         
756         addLoadEvent: addLoadEvent,
757         
758         getQueryParamValue: function(param) {
759             var q = doc.location.search || doc.location.hash;
760             if (q) {
761                 if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark
762                 if (param == null) {
763                     return urlEncodeIfNecessary(q);
764                 }
765                 var pairs = q.split("&");
766                 for (var i = 0; i < pairs.length; i++) {
767                     if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
768                         return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
769                     }
770                 }
771             }
772             return "";
773         },
774         
775         // For internal usage only
776         expressInstallCallback: function() {
777             if (isExpressInstallActive) {
778                 var obj = getElementById(EXPRESS_INSTALL_ID);
779                 if (obj && storedAltContent) {
780                     obj.parentNode.replaceChild(storedAltContent, obj);
781                     if (storedAltContentId) {
782                         setVisibility(storedAltContentId, true);
783                         if (ua.ie && ua.win) { storedAltContent.style.display = "block"; }
784                     }
785                     if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); }
786                 }
787                 isExpressInstallActive = false;
788             } 
789         }
790     };
791 }();
792 </pre>    
793 </body>
794 </html>