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