3 * Copyright(c) 2006-2009 Ext JS, LLC
5 * http://www.extjs.com/license
7 /*! SWFObject v2.2 <http://code.google.com/p/swfobject/>
\r
8 is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
\r
11 var swfobject = function() {
\r
13 var UNDEF = "undefined",
\r
15 SHOCKWAVE_FLASH = "Shockwave Flash",
\r
16 SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
\r
17 FLASH_MIME_TYPE = "application/x-shockwave-flash",
\r
18 EXPRESS_INSTALL_ID = "SWFObjectExprInst",
\r
19 ON_READY_STATE_CHANGE = "onreadystatechange",
\r
26 domLoadFnArr = [main],
\r
34 isDomLoaded = false,
\r
35 isExpressInstallActive = false,
\r
37 dynamicStylesheetMedia,
\r
38 autoHideShow = true,
\r
40 /* Centralized function for browser feature detection
\r
41 - User agent string detection is only used when no good alternative is possible
\r
42 - Is executed directly for optimal performance
\r
45 var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF,
\r
46 u = nav.userAgent.toLowerCase(),
\r
47 p = nav.platform.toLowerCase(),
\r
48 windows = p ? /win/.test(p) : /win/.test(u),
\r
49 mac = p ? /mac/.test(p) : /mac/.test(u),
\r
50 webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit
\r
51 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
\r
52 playerVersion = [0,0,0],
\r
54 if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
\r
55 d = nav.plugins[SHOCKWAVE_FLASH].description;
\r
56 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+
\r
58 ie = false; // cascaded feature detection for Internet Explorer
\r
59 d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
\r
60 playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10);
\r
61 playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
\r
62 playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0;
\r
65 else if (typeof win.ActiveXObject != UNDEF) {
\r
67 var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
\r
68 if (a) { // a will return null when ActiveX is disabled
\r
69 d = a.GetVariable("$version");
\r
71 ie = true; // cascaded feature detection for Internet Explorer
\r
72 d = d.split(" ")[1].split(",");
\r
73 playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
\r
79 return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac };
\r
82 /* Cross-browser onDomLoad
\r
83 - Will fire an event as soon as the DOM of a web page is loaded
\r
84 - Internet Explorer workaround based on Diego Perini's solution: http://javascript.nwbox.com/IEContentLoaded/
\r
85 - Regular onload serves as fallback
\r
87 onDomLoad = function() {
\r
88 if (!ua.w3) { return; }
\r
89 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
\r
90 callDomLoadFunctions();
\r
93 if (typeof doc.addEventListener != UNDEF) {
\r
94 doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false);
\r
96 if (ua.ie && ua.win) {
\r
97 doc.attachEvent(ON_READY_STATE_CHANGE, function() {
\r
98 if (doc.readyState == "complete") {
\r
99 doc.detachEvent(ON_READY_STATE_CHANGE, arguments.callee);
\r
100 callDomLoadFunctions();
\r
103 if (win == top) { // if not inside an iframe
\r
105 if (isDomLoaded) { return; }
\r
107 doc.documentElement.doScroll("left");
\r
110 setTimeout(arguments.callee, 0);
\r
113 callDomLoadFunctions();
\r
119 if (isDomLoaded) { return; }
\r
120 if (!/loaded|complete/.test(doc.readyState)) {
\r
121 setTimeout(arguments.callee, 0);
\r
124 callDomLoadFunctions();
\r
127 addLoadEvent(callDomLoadFunctions);
\r
131 function callDomLoadFunctions() {
\r
132 if (isDomLoaded) { return; }
\r
133 try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early
\r
134 var t = doc.getElementsByTagName("body")[0].appendChild(createElement("span"));
\r
135 t.parentNode.removeChild(t);
\r
137 catch (e) { return; }
\r
138 isDomLoaded = true;
\r
139 var dl = domLoadFnArr.length;
\r
140 for (var i = 0; i < dl; i++) {
\r
145 function addDomLoadEvent(fn) {
\r
150 domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+
\r
154 /* Cross-browser onload
\r
155 - Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/
\r
156 - Will fire an event as soon as a web page including all of its assets are loaded
\r
158 function addLoadEvent(fn) {
\r
159 if (typeof win.addEventListener != UNDEF) {
\r
160 win.addEventListener("load", fn, false);
\r
162 else if (typeof doc.addEventListener != UNDEF) {
\r
163 doc.addEventListener("load", fn, false);
\r
165 else if (typeof win.attachEvent != UNDEF) {
\r
166 addListener(win, "onload", fn);
\r
168 else if (typeof win.onload == "function") {
\r
169 var fnOld = win.onload;
\r
170 win.onload = function() {
\r
181 - Will preferably execute onDomLoad, otherwise onload (as a fallback)
\r
185 testPlayerVersion();
\r
192 /* Detect the Flash Player version for non-Internet Explorer browsers
\r
193 - Detecting the plug-in version via the object element is more precise than using the plugins collection item's description:
\r
194 a. Both release and build numbers can be detected
\r
195 b. Avoid wrong descriptions by corrupt installers provided by Adobe
\r
196 c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports
\r
197 - Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available
\r
199 function testPlayerVersion() {
\r
200 var b = doc.getElementsByTagName("body")[0];
\r
201 var o = createElement(OBJECT);
\r
202 o.setAttribute("type", FLASH_MIME_TYPE);
\r
203 var t = b.appendChild(o);
\r
207 if (typeof t.GetVariable != UNDEF) {
\r
208 var d = t.GetVariable("$version");
\r
210 d = d.split(" ")[1].split(",");
\r
211 ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
\r
214 else if (counter < 10) {
\r
216 setTimeout(arguments.callee, 10);
\r
229 /* Perform Flash Player and SWF version matching; static publishing only
\r
231 function matchVersions() {
\r
232 var rl = regObjArr.length;
\r
234 for (var i = 0; i < rl; i++) { // for each registered object element
\r
235 var id = regObjArr[i].id;
\r
236 var cb = regObjArr[i].callbackFn;
\r
237 var cbObj = {success:false, id:id};
\r
238 if (ua.pv[0] > 0) {
\r
239 var obj = getElementById(id);
\r
241 if (hasPlayerVersion(regObjArr[i].swfVersion) && !(ua.wk && ua.wk < 312)) { // Flash Player version >= published SWF version: Houston, we have a match!
\r
242 setVisibility(id, true);
\r
244 cbObj.success = true;
\r
245 cbObj.ref = getObjectById(id);
\r
249 else if (regObjArr[i].expressInstall && canExpressInstall()) { // show the Adobe Express Install dialog if set by the web page author and if supported
\r
251 att.data = regObjArr[i].expressInstall;
\r
252 att.width = obj.getAttribute("width") || "0";
\r
253 att.height = obj.getAttribute("height") || "0";
\r
254 if (obj.getAttribute("class")) { att.styleclass = obj.getAttribute("class"); }
\r
255 if (obj.getAttribute("align")) { att.align = obj.getAttribute("align"); }
\r
256 // parse HTML object param element's name-value pairs
\r
258 var p = obj.getElementsByTagName("param");
\r
260 for (var j = 0; j < pl; j++) {
\r
261 if (p[j].getAttribute("name").toLowerCase() != "movie") {
\r
262 par[p[j].getAttribute("name")] = p[j].getAttribute("value");
\r
265 showExpressInstall(att, par, id, cb);
\r
267 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
\r
268 displayAltContent(obj);
\r
269 if (cb) { cb(cbObj); }
\r
273 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)
\r
274 setVisibility(id, true);
\r
276 var o = getObjectById(id); // test whether there is an HTML object element or not
\r
277 if (o && typeof o.SetVariable != UNDEF) {
\r
278 cbObj.success = true;
\r
288 function getObjectById(objectIdStr) {
\r
290 var o = getElementById(objectIdStr);
\r
291 if (o && o.nodeName == "OBJECT") {
\r
292 if (typeof o.SetVariable != UNDEF) {
\r
296 var n = o.getElementsByTagName(OBJECT)[0];
\r
305 /* Requirements for Adobe Express Install
\r
306 - only one instance can be active at a time
\r
307 - fp 6.0.65 or higher
\r
309 - no Webkit engines older than version 312
\r
311 function canExpressInstall() {
\r
312 return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312);
\r
315 /* Show the Adobe Express Install dialog
\r
316 - Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75
\r
318 function showExpressInstall(att, par, replaceElemIdStr, callbackFn) {
\r
319 isExpressInstallActive = true;
\r
320 storedCallbackFn = callbackFn || null;
\r
321 storedCallbackObj = {success:false, id:replaceElemIdStr};
\r
322 var obj = getElementById(replaceElemIdStr);
\r
324 if (obj.nodeName == "OBJECT") { // static publishing
\r
325 storedAltContent = abstractAltContent(obj);
\r
326 storedAltContentId = null;
\r
328 else { // dynamic publishing
\r
329 storedAltContent = obj;
\r
330 storedAltContentId = replaceElemIdStr;
\r
332 att.id = EXPRESS_INSTALL_ID;
\r
333 if (typeof att.width == UNDEF || (!/%$/.test(att.width) && parseInt(att.width, 10) < 310)) { att.width = "310"; }
\r
334 if (typeof att.height == UNDEF || (!/%$/.test(att.height) && parseInt(att.height, 10) < 137)) { att.height = "137"; }
\r
335 doc.title = doc.title.slice(0, 47) + " - Flash Player Installation";
\r
336 var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn",
\r
337 fv = "MMredirectURL=" + win.location.toString().replace(/&/g,"%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title;
\r
338 if (typeof par.flashvars != UNDEF) {
\r
339 par.flashvars += "&" + fv;
\r
342 par.flashvars = fv;
\r
344 // 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,
\r
345 // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
\r
346 if (ua.ie && ua.win && obj.readyState != 4) {
\r
347 var newObj = createElement("div");
\r
348 replaceElemIdStr += "SWFObjectNew";
\r
349 newObj.setAttribute("id", replaceElemIdStr);
\r
350 obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf
\r
351 obj.style.display = "none";
\r
353 if (obj.readyState == 4) {
\r
354 obj.parentNode.removeChild(obj);
\r
357 setTimeout(arguments.callee, 10);
\r
361 createSWF(att, par, replaceElemIdStr);
\r
365 /* Functions to abstract and display alternative content
\r
367 function displayAltContent(obj) {
\r
368 if (ua.ie && ua.win && obj.readyState != 4) {
\r
369 // 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,
\r
370 // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
\r
371 var el = createElement("div");
\r
372 obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content
\r
373 el.parentNode.replaceChild(abstractAltContent(obj), el);
\r
374 obj.style.display = "none";
\r
376 if (obj.readyState == 4) {
\r
377 obj.parentNode.removeChild(obj);
\r
380 setTimeout(arguments.callee, 10);
\r
385 obj.parentNode.replaceChild(abstractAltContent(obj), obj);
\r
389 function abstractAltContent(obj) {
\r
390 var ac = createElement("div");
\r
391 if (ua.win && ua.ie) {
\r
392 ac.innerHTML = obj.innerHTML;
\r
395 var nestedObj = obj.getElementsByTagName(OBJECT)[0];
\r
397 var c = nestedObj.childNodes;
\r
400 for (var i = 0; i < cl; i++) {
\r
401 if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) {
\r
402 ac.appendChild(c[i].cloneNode(true));
\r
411 /* Cross-browser dynamic SWF creation
\r
413 function createSWF(attObj, parObj, id) {
\r
414 var r, el = getElementById(id);
\r
415 if (ua.wk && ua.wk < 312) { return r; }
\r
417 if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
\r
420 if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML
\r
422 for (var i in attObj) {
\r
423 if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries
\r
424 if (i.toLowerCase() == "data") {
\r
425 parObj.movie = attObj[i];
\r
427 else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
\r
428 att += ' class="' + attObj[i] + '"';
\r
430 else if (i.toLowerCase() != "classid") {
\r
431 att += ' ' + i + '="' + attObj[i] + '"';
\r
436 for (var j in parObj) {
\r
437 if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries
\r
438 par += '<param name="' + j + '" value="' + parObj[j] + '" />';
\r
441 el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>';
\r
442 objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only)
\r
443 r = getElementById(attObj.id);
\r
445 else { // well-behaving browsers
\r
446 var o = createElement(OBJECT);
\r
447 o.setAttribute("type", FLASH_MIME_TYPE);
\r
448 for (var m in attObj) {
\r
449 if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries
\r
450 if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
\r
451 o.setAttribute("class", attObj[m]);
\r
453 else if (m.toLowerCase() != "classid") { // filter out IE specific attribute
\r
454 o.setAttribute(m, attObj[m]);
\r
458 for (var n in parObj) {
\r
459 if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element
\r
460 createObjParam(o, n, parObj[n]);
\r
463 el.parentNode.replaceChild(o, el);
\r
470 function createObjParam(el, pName, pValue) {
\r
471 var p = createElement("param");
\r
472 p.setAttribute("name", pName);
\r
473 p.setAttribute("value", pValue);
\r
477 /* Cross-browser SWF removal
\r
478 - Especially needed to safely and completely remove a SWF in Internet Explorer
\r
480 function removeSWF(id) {
\r
481 var obj = getElementById(id);
\r
482 if (obj && obj.nodeName == "OBJECT") {
\r
483 if (ua.ie && ua.win) {
\r
484 obj.style.display = "none";
\r
486 if (obj.readyState == 4) {
\r
487 removeObjectInIE(id);
\r
490 setTimeout(arguments.callee, 10);
\r
495 obj.parentNode.removeChild(obj);
\r
500 function removeObjectInIE(id) {
\r
501 var obj = getElementById(id);
\r
503 for (var i in obj) {
\r
504 if (typeof obj[i] == "function") {
\r
508 obj.parentNode.removeChild(obj);
\r
512 /* Functions to optimize JavaScript compression
\r
514 function getElementById(id) {
\r
517 el = doc.getElementById(id);
\r
523 function createElement(el) {
\r
524 return doc.createElement(el);
\r
527 /* Updated attachEvent function for Internet Explorer
\r
528 - Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks
\r
530 function addListener(target, eventType, fn) {
\r
531 target.attachEvent(eventType, fn);
\r
532 listenersArr[listenersArr.length] = [target, eventType, fn];
\r
535 /* Flash Player and SWF content version matching
\r
537 function hasPlayerVersion(rv) {
\r
538 var pv = ua.pv, v = rv.split(".");
\r
539 v[0] = parseInt(v[0], 10);
\r
540 v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
\r
541 v[2] = parseInt(v[2], 10) || 0;
\r
542 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;
\r
545 /* Cross-browser dynamic CSS creation
\r
546 - Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php
\r
548 function createCSS(sel, decl, media, newStyle) {
\r
549 if (ua.ie && ua.mac) { return; }
\r
550 var h = doc.getElementsByTagName("head")[0];
\r
551 if (!h) { return; } // to also support badly authored HTML pages that lack a head element
\r
552 var m = (media && typeof media == "string") ? media : "screen";
\r
554 dynamicStylesheet = null;
\r
555 dynamicStylesheetMedia = null;
\r
557 if (!dynamicStylesheet || dynamicStylesheetMedia != m) {
\r
558 // create dynamic stylesheet + get a global reference to it
\r
559 var s = createElement("style");
\r
560 s.setAttribute("type", "text/css");
\r
561 s.setAttribute("media", m);
\r
562 dynamicStylesheet = h.appendChild(s);
\r
563 if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) {
\r
564 dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1];
\r
566 dynamicStylesheetMedia = m;
\r
569 if (ua.ie && ua.win) {
\r
570 if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) {
\r
571 dynamicStylesheet.addRule(sel, decl);
\r
575 if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) {
\r
576 dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}"));
\r
581 function setVisibility(id, isVisible) {
\r
582 if (!autoHideShow) { return; }
\r
583 var v = isVisible ? "visible" : "hidden";
\r
584 if (isDomLoaded && getElementById(id)) {
\r
585 getElementById(id).style.visibility = v;
\r
588 createCSS("#" + id, "visibility:" + v);
\r
592 /* Filter to avoid XSS attacks
\r
594 function urlEncodeIfNecessary(s) {
\r
595 var regex = /[\\\"<>\.;]/;
\r
596 var hasBadChars = regex.exec(s) != null;
\r
597 return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s;
\r
600 /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
\r
602 var cleanup = function() {
\r
603 if (ua.ie && ua.win) {
\r
604 window.attachEvent("onunload", function() {
\r
605 // remove listeners to avoid memory leaks
\r
606 var ll = listenersArr.length;
\r
607 for (var i = 0; i < ll; i++) {
\r
608 listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]);
\r
610 // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
\r
611 var il = objIdArr.length;
\r
612 for (var j = 0; j < il; j++) {
\r
613 removeSWF(objIdArr[j]);
\r
615 // cleanup library's main closures to avoid memory leaks
\r
616 for (var k in ua) {
\r
620 for (var l in swfobject) {
\r
621 swfobject[l] = null;
\r
630 - Reference: http://code.google.com/p/swfobject/wiki/documentation
\r
632 registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) {
\r
633 if (ua.w3 && objectIdStr && swfVersionStr) {
\r
635 regObj.id = objectIdStr;
\r
636 regObj.swfVersion = swfVersionStr;
\r
637 regObj.expressInstall = xiSwfUrlStr;
\r
638 regObj.callbackFn = callbackFn;
\r
639 regObjArr[regObjArr.length] = regObj;
\r
640 setVisibility(objectIdStr, false);
\r
642 else if (callbackFn) {
\r
643 callbackFn({success:false, id:objectIdStr});
\r
647 getObjectById: function(objectIdStr) {
\r
649 return getObjectById(objectIdStr);
\r
653 embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) {
\r
654 var callbackObj = {success:false, id:replaceElemIdStr};
\r
655 if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) {
\r
656 setVisibility(replaceElemIdStr, false);
\r
657 addDomLoadEvent(function() {
\r
658 widthStr += ""; // auto-convert to string
\r
661 if (attObj && typeof attObj === OBJECT) {
\r
662 for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs
\r
663 att[i] = attObj[i];
\r
666 att.data = swfUrlStr;
\r
667 att.width = widthStr;
\r
668 att.height = heightStr;
\r
670 if (parObj && typeof parObj === OBJECT) {
\r
671 for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs
\r
672 par[j] = parObj[j];
\r
675 if (flashvarsObj && typeof flashvarsObj === OBJECT) {
\r
676 for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs
\r
677 if (typeof par.flashvars != UNDEF) {
\r
678 par.flashvars += "&" + k + "=" + flashvarsObj[k];
\r
681 par.flashvars = k + "=" + flashvarsObj[k];
\r
685 if (hasPlayerVersion(swfVersionStr)) { // create SWF
\r
686 var obj = createSWF(att, par, replaceElemIdStr);
\r
687 if (att.id == replaceElemIdStr) {
\r
688 setVisibility(replaceElemIdStr, true);
\r
690 callbackObj.success = true;
\r
691 callbackObj.ref = obj;
\r
693 else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install
\r
694 att.data = xiSwfUrlStr;
\r
695 showExpressInstall(att, par, replaceElemIdStr, callbackFn);
\r
698 else { // show alternative content
\r
699 setVisibility(replaceElemIdStr, true);
\r
701 if (callbackFn) { callbackFn(callbackObj); }
\r
704 else if (callbackFn) { callbackFn(callbackObj); }
\r
707 switchOffAutoHideShow: function() {
\r
708 autoHideShow = false;
\r
713 getFlashPlayerVersion: function() {
\r
714 return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };
\r
717 hasFlashPlayerVersion: hasPlayerVersion,
\r
719 createSWF: function(attObj, parObj, replaceElemIdStr) {
\r
721 return createSWF(attObj, parObj, replaceElemIdStr);
\r
728 showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) {
\r
729 if (ua.w3 && canExpressInstall()) {
\r
730 showExpressInstall(att, par, replaceElemIdStr, callbackFn);
\r
734 removeSWF: function(objElemIdStr) {
\r
736 removeSWF(objElemIdStr);
\r
740 createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) {
\r
742 createCSS(selStr, declStr, mediaStr, newStyleBoolean);
\r
746 addDomLoadEvent: addDomLoadEvent,
\r
748 addLoadEvent: addLoadEvent,
\r
750 getQueryParamValue: function(param) {
\r
751 var q = doc.location.search || doc.location.hash;
\r
753 if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark
\r
754 if (param == null) {
\r
755 return urlEncodeIfNecessary(q);
\r
757 var pairs = q.split("&");
\r
758 for (var i = 0; i < pairs.length; i++) {
\r
759 if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
\r
760 return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
\r
767 // For internal usage only
\r
768 expressInstallCallback: function() {
\r
769 if (isExpressInstallActive) {
\r
770 var obj = getElementById(EXPRESS_INSTALL_ID);
\r
771 if (obj && storedAltContent) {
\r
772 obj.parentNode.replaceChild(storedAltContent, obj);
\r
773 if (storedAltContentId) {
\r
774 setVisibility(storedAltContentId, true);
\r
775 if (ua.ie && ua.win) { storedAltContent.style.display = "block"; }
\r
777 if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); }
\r
779 isExpressInstallActive = false;
\r
785 * @class Ext.FlashComponent
786 * @extends Ext.BoxComponent
790 Ext.FlashComponent = Ext.extend(Ext.BoxComponent, {
792 * @cfg {String} flashVersion
793 * Indicates the version the flash content was published for. Defaults to <tt>'9.0.45'</tt>.
795 flashVersion : '9.0.45',
798 * @cfg {String} backgroundColor
799 * The background color of the chart. Defaults to <tt>'#ffffff'</tt>.
801 backgroundColor: '#ffffff',
804 * @cfg {String} wmode
805 * The wmode of the flash object. This can be used to control layering. Defaults to <tt>'opaque'</tt>.
810 * @cfg {Object} flashVars
811 * A set of key value pairs to be passed to the flash object as flash variables. Defaults to <tt>undefined</tt>.
813 flashVars: undefined,
816 * @cfg {Object} flashParams
817 * A set of key value pairs to be passed to the flash object as parameters. Possible parameters can be found here:
818 * http://kb2.adobe.com/cps/127/tn_12701.html Defaults to <tt>undefined</tt>.
820 flashParams: undefined,
824 * The URL of the chart to include. Defaults to <tt>undefined</tt>.
832 * @cfg {Boolean} expressInstall
833 * True to prompt the user to install flash if not installed. Note that this uses
834 * Ext.FlashComponent.EXPRESS_INSTALL_URL, which should be set to the local resource. Defaults to <tt>false</tt>.
836 expressInstall: false,
838 initComponent : function(){
839 Ext.FlashComponent.superclass.initComponent.call(this);
841 this.addEvents('initialize');
844 onRender : function(){
845 Ext.FlashComponent.superclass.onRender.apply(this, arguments);
847 var params = Ext.apply({
848 allowScriptAccess: 'always',
849 bgcolor: this.backgroundColor,
851 }, this.flashParams), vars = Ext.apply({
852 allowedDomain: document.location.hostname,
853 elementID: this.getId(),
854 eventHandler: 'Ext.FlashEventProxy.onEvent'
857 new swfobject.embedSWF(this.url, this.id, this.swfWidth, this.swfHeight, this.flashVersion,
858 this.expressInstall ? Ext.FlashComponent.EXPRESS_INSTALL_URL : undefined, vars, params);
860 this.swf = Ext.getDom(this.id);
861 this.el = Ext.get(this.swf);
864 getSwfId : function(){
865 return this.swfId || (this.swfId = "extswf" + (++Ext.Component.AUTO_ID));
869 return this.id || (this.id = "extflashcmp" + (++Ext.Component.AUTO_ID));
872 onFlashEvent : function(e){
881 this.fireEvent(e.type.toLowerCase().replace(/event$/, ''), e);
884 initSwf : function(){
885 this.onSwfReady(!!this.isInitialized);
886 this.isInitialized = true;
887 this.fireEvent('initialize', this);
890 beforeDestroy: function(){
892 swfobject.removeSWF(this.swf.id);
894 Ext.FlashComponent.superclass.beforeDestroy.call(this);
897 onSwfReady : Ext.emptyFn
901 * Sets the url for installing flash if it doesn't exist. This should be set to a local resource.
905 Ext.FlashComponent.EXPRESS_INSTALL_URL = 'http:/' + '/swfobject.googlecode.com/svn/trunk/swfobject/expressInstall.swf';
907 Ext.reg('flash', Ext.FlashComponent);/**
\r
908 * @class Ext.FlashProxy
\r
911 Ext.FlashEventProxy = {
\r
912 onEvent : function(id, e){
\r
913 var fp = Ext.getCmp(id);
\r
915 fp.onFlashEvent(e);
\r
917 arguments.callee.defer(10, this, [id, e]);
\r
921 * @class Ext.chart.Chart
\r
922 * @extends Ext.FlashComponent
\r
923 * The Ext.chart package provides the capability to visualize data with flash based charting.
\r
924 * Each chart binds directly to an Ext.data.Store enabling automatic updates of the chart.
\r
929 Ext.chart.Chart = Ext.extend(Ext.FlashComponent, {
\r
930 refreshBuffer: 100,
\r
933 * @cfg {Object} chartStyle
\r
934 * Sets styles for this chart. Contains a number of default values. Modifying this property will override
\r
935 * the base styles on the chart.
\r
939 animationEnabled: true,
\r
965 * @cfg {String} url
\r
966 * The url to load the chart from. This defaults to Ext.chart.Chart.CHART_URL, which should
\r
967 * be modified to point to the local charts resource.
\r
971 * @cfg {Object} extraStyle
\r
972 * Contains extra styles that will be added or overwritten to the default chartStyle. Defaults to <tt>null</tt>.
\r
977 * @cfg {Boolean} disableCaching
\r
978 * True to add a "cache buster" to the end of the chart url. Defaults to true for Opera and IE.
\r
980 disableCaching: Ext.isIE || Ext.isOpera,
\r
981 disableCacheParam: '_dc',
\r
983 initComponent : function(){
\r
984 Ext.chart.Chart.superclass.initComponent.call(this);
\r
986 this.url = Ext.chart.Chart.CHART_URL;
\r
988 if(this.disableCaching){
\r
989 this.url = Ext.urlAppend(this.url, String.format('{0}={1}', this.disableCacheParam, new Date().getTime()));
\r
1000 this.store = Ext.StoreMgr.lookup(this.store);
\r
1004 * Sets a single style value on the Chart instance.
\r
1006 * @param name {String} Name of the Chart style value to change.
\r
1007 * @param value {Object} New value to pass to the Chart style.
\r
1009 setStyle: function(name, value){
\r
1010 this.swf.setStyle(name, Ext.encode(value));
\r
1014 * Resets all styles on the Chart instance.
\r
1016 * @param styles {Object} Initializer for all Chart styles.
\r
1018 setStyles: function(styles){
\r
1019 this.swf.setStyles(Ext.encode(styles));
\r
1023 * Sets the styles on all series in the Chart.
\r
1025 * @param styles {Array} Initializer for all Chart series styles.
\r
1027 setSeriesStyles: function(styles){
\r
1029 Ext.each(styles, function(style){
\r
1030 s.push(Ext.encode(style));
\r
1032 this.swf.setSeriesStyles(s);
\r
1035 setCategoryNames : function(names){
\r
1036 this.swf.setCategoryNames(names);
\r
1039 setTipRenderer : function(fn){
\r
1041 this.tipFnName = this.createFnProxy(function(item, index, series){
\r
1042 var record = chart.store.getAt(index);
\r
1043 return fn(chart, record, index, series);
\r
1044 }, this.tipFnName);
\r
1045 this.swf.setDataTipFunction(this.tipFnName);
\r
1048 setSeries : function(series){
\r
1049 this.series = series;
\r
1054 * Changes the data store bound to this chart and refreshes it.
\r
1055 * @param {Store} store The store to bind to this chart
\r
1057 bindStore : function(store, initial){
\r
1058 if(!initial && this.store){
\r
1059 if(store !== this.store && this.store.autoDestroy){
\r
1060 this.store.destroy();
\r
1062 this.store.un("datachanged", this.refresh, this);
\r
1063 this.store.un("add", this.delayRefresh, this);
\r
1064 this.store.un("remove", this.delayRefresh, this);
\r
1065 this.store.un("update", this.delayRefresh, this);
\r
1066 this.store.un("clear", this.refresh, this);
\r
1070 store = Ext.StoreMgr.lookup(store);
\r
1073 datachanged: this.refresh,
\r
1074 add: this.delayRefresh,
\r
1075 remove: this.delayRefresh,
\r
1076 update: this.delayRefresh,
\r
1077 clear: this.refresh
\r
1080 this.store = store;
\r
1081 if(store && !initial){
\r
1086 onSwfReady : function(isReset){
\r
1087 Ext.chart.Chart.superclass.onSwfReady.call(this, isReset);
\r
1088 this.swf.setType(this.type);
\r
1090 if(this.chartStyle){
\r
1091 this.setStyles(Ext.apply({}, this.extraStyle, this.chartStyle));
\r
1094 if(this.categoryNames){
\r
1095 this.setCategoryNames(this.categoryNames);
\r
1098 if(this.tipRenderer){
\r
1099 this.setTipRenderer(this.tipRenderer);
\r
1102 this.bindStore(this.store, true);
\r
1104 this.refresh.defer(10, this);
\r
1107 delayRefresh : function(){
\r
1108 if(!this.refreshTask){
\r
1109 this.refreshTask = new Ext.util.DelayedTask(this.refresh, this);
\r
1111 this.refreshTask.delay(this.refreshBuffer);
\r
1114 refresh : function(){
\r
1115 var styleChanged = false;
\r
1116 // convert the store data into something YUI charts can understand
\r
1117 var data = [], rs = this.store.data.items;
\r
1118 for(var j = 0, len = rs.length; j < len; j++){
\r
1119 data[j] = rs[j].data;
\r
1121 //make a copy of the series definitions so that we aren't
\r
1122 //editing them directly.
\r
1123 var dataProvider = [];
\r
1124 var seriesCount = 0;
\r
1125 var currentSeries = null;
\r
1128 seriesCount = this.series.length;
\r
1129 for(i = 0; i < seriesCount; i++){
\r
1130 currentSeries = this.series[i];
\r
1131 var clonedSeries = {};
\r
1132 for(var prop in currentSeries){
\r
1133 if(prop == "style" && currentSeries.style !== null){
\r
1134 clonedSeries.style = Ext.encode(currentSeries.style);
\r
1135 styleChanged = true;
\r
1136 //we don't want to modify the styles again next time
\r
1137 //so null out the style property.
\r
1138 // this causes issues
\r
1139 // currentSeries.style = null;
\r
1141 clonedSeries[prop] = currentSeries[prop];
\r
1144 dataProvider.push(clonedSeries);
\r
1148 if(seriesCount > 0){
\r
1149 for(i = 0; i < seriesCount; i++){
\r
1150 currentSeries = dataProvider[i];
\r
1151 if(!currentSeries.type){
\r
1152 currentSeries.type = this.type;
\r
1154 currentSeries.dataProvider = data;
\r
1157 dataProvider.push({type: this.type, dataProvider: data});
\r
1159 this.swf.setDataProvider(dataProvider);
\r
1162 createFnProxy : function(fn, old){
\r
1164 delete window[old];
\r
1166 var fnName = "extFnProxy" + (++Ext.chart.Chart.PROXY_FN_ID);
\r
1167 window[fnName] = fn;
\r
1171 onDestroy: function(){
\r
1172 Ext.chart.Chart.superclass.onDestroy.call(this);
\r
1173 this.bindStore(null);
\r
1174 var tip = this.tipFnName;
\r
1175 if(!Ext.isEmpty(tip)){
\r
1176 delete window[tip];
\r
1180 Ext.reg('chart', Ext.chart.Chart);
\r
1181 Ext.chart.Chart.PROXY_FN_ID = 0;
\r
1184 * Sets the url to load the chart from. This should be set to a local resource.
\r
1188 Ext.chart.Chart.CHART_URL = 'http:/' + '/yui.yahooapis.com/2.7.0/build/charts/assets/charts.swf';
\r
1191 * @class Ext.chart.PieChart
\r
1192 * @extends Ext.chart.Chart
\r
1196 Ext.chart.PieChart = Ext.extend(Ext.chart.Chart, {
\r
1199 onSwfReady : function(isReset){
\r
1200 Ext.chart.PieChart.superclass.onSwfReady.call(this, isReset);
\r
1202 this.setDataField(this.dataField);
\r
1203 this.setCategoryField(this.categoryField);
\r
1206 setDataField : function(field){
\r
1207 this.dataField = field;
\r
1208 this.swf.setDataField(field);
\r
1211 setCategoryField : function(field){
\r
1212 this.categoryField = field;
\r
1213 this.swf.setCategoryField(field);
\r
1216 Ext.reg('piechart', Ext.chart.PieChart);
\r
1219 * @class Ext.chart.CartesianChart
\r
1220 * @extends Ext.chart.Chart
\r
1222 * @xtype cartesianchart
\r
1224 Ext.chart.CartesianChart = Ext.extend(Ext.chart.Chart, {
\r
1225 onSwfReady : function(isReset){
\r
1226 Ext.chart.CartesianChart.superclass.onSwfReady.call(this, isReset);
\r
1229 this.setXField(this.xField);
\r
1232 this.setYField(this.yField);
\r
1235 this.setXAxis(this.xAxis);
\r
1238 this.setYAxis(this.yAxis);
\r
1242 setXField : function(value){
\r
1243 this.xField = value;
\r
1244 this.swf.setHorizontalField(value);
\r
1247 setYField : function(value){
\r
1248 this.yField = value;
\r
1249 this.swf.setVerticalField(value);
\r
1252 setXAxis : function(value){
\r
1253 this.xAxis = this.createAxis('xAxis', value);
\r
1254 this.swf.setHorizontalAxis(this.xAxis);
\r
1257 setYAxis : function(value){
\r
1258 this.yAxis = this.createAxis('yAxis', value);
\r
1259 this.swf.setVerticalAxis(this.yAxis);
\r
1262 createAxis : function(axis, value){
\r
1263 var o = Ext.apply({}, value), oldFn = null;
\r
1265 oldFn = this[axis].labelFunction;
\r
1267 if(o.labelRenderer){
\r
1268 var fn = o.labelRenderer;
\r
1269 o.labelFunction = this.createFnProxy(function(v){
\r
1272 delete o.labelRenderer;
\r
1277 Ext.reg('cartesianchart', Ext.chart.CartesianChart);
\r
1280 * @class Ext.chart.LineChart
\r
1281 * @extends Ext.chart.CartesianChart
\r
1283 * @xtype linechart
\r
1285 Ext.chart.LineChart = Ext.extend(Ext.chart.CartesianChart, {
\r
1288 Ext.reg('linechart', Ext.chart.LineChart);
\r
1291 * @class Ext.chart.ColumnChart
\r
1292 * @extends Ext.chart.CartesianChart
\r
1294 * @xtype columnchart
\r
1296 Ext.chart.ColumnChart = Ext.extend(Ext.chart.CartesianChart, {
\r
1299 Ext.reg('columnchart', Ext.chart.ColumnChart);
\r
1302 * @class Ext.chart.StackedColumnChart
\r
1303 * @extends Ext.chart.CartesianChart
\r
1305 * @xtype stackedcolumnchart
\r
1307 Ext.chart.StackedColumnChart = Ext.extend(Ext.chart.CartesianChart, {
\r
1308 type: 'stackcolumn'
\r
1310 Ext.reg('stackedcolumnchart', Ext.chart.StackedColumnChart);
\r
1313 * @class Ext.chart.BarChart
\r
1314 * @extends Ext.chart.CartesianChart
\r
1318 Ext.chart.BarChart = Ext.extend(Ext.chart.CartesianChart, {
\r
1321 Ext.reg('barchart', Ext.chart.BarChart);
\r
1324 * @class Ext.chart.StackedBarChart
\r
1325 * @extends Ext.chart.CartesianChart
\r
1327 * @xtype stackedbarchart
\r
1329 Ext.chart.StackedBarChart = Ext.extend(Ext.chart.CartesianChart, {
\r
1332 Ext.reg('stackedbarchart', Ext.chart.StackedBarChart);
\r
1337 * @class Ext.chart.Axis
\r
1338 * Defines a CartesianChart's vertical or horizontal axis.
\r
1341 Ext.chart.Axis = function(config){
\r
1342 Ext.apply(this, config);
\r
1345 Ext.chart.Axis.prototype =
\r
1348 * The type of axis.
\r
1356 * The direction in which the axis is drawn. May be "horizontal" or "vertical".
\r
1358 * @property orientation
\r
1361 orientation: "horizontal",
\r
1364 * If true, the items on the axis will be drawn in opposite direction.
\r
1366 * @property reverse
\r
1372 * A string reference to the globally-accessible function that may be called to
\r
1373 * determine each of the label values for this axis.
\r
1375 * @property labelFunction
\r
1378 labelFunction: null,
\r
1381 * If true, labels that overlap previously drawn labels on the axis will be hidden.
\r
1383 * @property hideOverlappingLabels
\r
1386 hideOverlappingLabels: true
\r
1390 * @class Ext.chart.NumericAxis
\r
1391 * @extends Ext.chart.Axis
\r
1392 * A type of axis whose units are measured in numeric values.
\r
1395 Ext.chart.NumericAxis = Ext.extend(Ext.chart.Axis, {
\r
1399 * The minimum value drawn by the axis. If not set explicitly, the axis minimum
\r
1400 * will be calculated automatically.
\r
1402 * @property minimum
\r
1408 * The maximum value drawn by the axis. If not set explicitly, the axis maximum
\r
1409 * will be calculated automatically.
\r
1411 * @property maximum
\r
1417 * The spacing between major intervals on this axis.
\r
1419 * @property majorUnit
\r
1425 * The spacing between minor intervals on this axis.
\r
1427 * @property minorUnit
\r
1433 * If true, the labels, ticks, gridlines, and other objects will snap to
\r
1434 * the nearest major or minor unit. If false, their position will be based
\r
1435 * on the minimum value.
\r
1437 * @property snapToUnits
\r
1440 snapToUnits: true,
\r
1443 * If true, and the bounds are calculated automatically, either the minimum or
\r
1444 * maximum will be set to zero.
\r
1446 * @property alwaysShowZero
\r
1449 alwaysShowZero: true,
\r
1452 * The scaling algorithm to use on this axis. May be "linear" or "logarithmic".
\r
1461 * @class Ext.chart.TimeAxis
\r
1462 * @extends Ext.chart.Axis
\r
1463 * A type of axis whose units are measured in time-based values.
\r
1466 Ext.chart.TimeAxis = Ext.extend(Ext.chart.Axis, {
\r
1470 * The minimum value drawn by the axis. If not set explicitly, the axis minimum
\r
1471 * will be calculated automatically.
\r
1473 * @property minimum
\r
1479 * The maximum value drawn by the axis. If not set explicitly, the axis maximum
\r
1480 * will be calculated automatically.
\r
1482 * @property maximum
\r
1488 * The spacing between major intervals on this axis.
\r
1490 * @property majorUnit
\r
1496 * The time unit used by the majorUnit.
\r
1498 * @property majorTimeUnit
\r
1501 majorTimeUnit: null,
\r
1504 * The spacing between minor intervals on this axis.
\r
1506 * @property majorUnit
\r
1512 * The time unit used by the minorUnit.
\r
1514 * @property majorTimeUnit
\r
1517 minorTimeUnit: null,
\r
1520 * If true, the labels, ticks, gridlines, and other objects will snap to
\r
1521 * the nearest major or minor unit. If false, their position will be based
\r
1522 * on the minimum value.
\r
1524 * @property snapToUnits
\r
1531 * @class Ext.chart.CategoryAxis
\r
1532 * @extends Ext.chart.Axis
\r
1533 * A type of axis that displays items in categories.
\r
1536 Ext.chart.CategoryAxis = Ext.extend(Ext.chart.Axis, {
\r
1540 * A list of category names to display along this axis.
\r
1542 * @property categoryNames
\r
1545 categoryNames: null
\r
1549 * @class Ext.chart.Series
\r
1550 * Series class for the charts widget.
\r
1553 Ext.chart.Series = function(config) { Ext.apply(this, config); };
\r
1555 Ext.chart.Series.prototype =
\r
1558 * The type of series.
\r
1566 * The human-readable name of the series.
\r
1568 * @property displayName
\r
1575 * @class Ext.chart.CartesianSeries
\r
1576 * @extends Ext.chart.Series
\r
1577 * CartesianSeries class for the charts widget.
\r
1580 Ext.chart.CartesianSeries = Ext.extend(Ext.chart.Series, {
\r
1582 * The field used to access the x-axis value from the items from the data source.
\r
1584 * @property xField
\r
1590 * The field used to access the y-axis value from the items from the data source.
\r
1592 * @property yField
\r
1599 * @class Ext.chart.ColumnSeries
\r
1600 * @extends Ext.chart.CartesianSeries
\r
1601 * ColumnSeries class for the charts widget.
\r
1604 Ext.chart.ColumnSeries = Ext.extend(Ext.chart.CartesianSeries, {
\r
1609 * @class Ext.chart.LineSeries
\r
1610 * @extends Ext.chart.CartesianSeries
\r
1611 * LineSeries class for the charts widget.
\r
1614 Ext.chart.LineSeries = Ext.extend(Ext.chart.CartesianSeries, {
\r
1619 * @class Ext.chart.BarSeries
\r
1620 * @extends Ext.chart.CartesianSeries
\r
1621 * BarSeries class for the charts widget.
\r
1624 Ext.chart.BarSeries = Ext.extend(Ext.chart.CartesianSeries, {
\r
1630 * @class Ext.chart.PieSeries
\r
1631 * @extends Ext.chart.Series
\r
1632 * PieSeries class for the charts widget.
\r
1635 Ext.chart.PieSeries = Ext.extend(Ext.chart.Series, {
\r
1638 categoryField: null
\r