Upgrade to ExtJS 3.1.1 - Released 02/08/2010
[extjs.git] / pkgs / pkg-charts-debug.js
1 /*!
2  * Ext JS Library 3.1.1
3  * Copyright(c) 2006-2010 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
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
9 */\r
10 \r
11 var swfobject = function() {\r
12     \r
13     var UNDEF = "undefined",\r
14         OBJECT = "object",\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
20         \r
21         win = window,\r
22         doc = document,\r
23         nav = navigator,\r
24         \r
25         plugin = false,\r
26         domLoadFnArr = [main],\r
27         regObjArr = [],\r
28         objIdArr = [],\r
29         listenersArr = [],\r
30         storedAltContent,\r
31         storedAltContentId,\r
32         storedCallbackFn,\r
33         storedCallbackObj,\r
34         isDomLoaded = false,\r
35         isExpressInstallActive = false,\r
36         dynamicStylesheet,\r
37         dynamicStylesheetMedia,\r
38         autoHideShow = true,\r
39     \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
43     */  \r
44     ua = function() {\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
53             d = null;\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
57                 plugin = true;\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
63             }\r
64         }\r
65         else if (typeof win.ActiveXObject != UNDEF) {\r
66             try {\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
70                     if (d) {\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
74                     }\r
75                 }\r
76             }\r
77             catch(e) {}\r
78         }\r
79         return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac };\r
80     }(),\r
81     \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
86     */ \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
91         }\r
92         if (!isDomLoaded) {\r
93             if (typeof doc.addEventListener != UNDEF) {\r
94                 doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false);\r
95             }       \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
101                     }\r
102                 });\r
103                 if (win == top) { // if not inside an iframe\r
104                     (function(){\r
105                         if (isDomLoaded) { return; }\r
106                         try {\r
107                             doc.documentElement.doScroll("left");\r
108                         }\r
109                         catch(e) {\r
110                             setTimeout(arguments.callee, 0);\r
111                             return;\r
112                         }\r
113                         callDomLoadFunctions();\r
114                     })();\r
115                 }\r
116             }\r
117             if (ua.wk) {\r
118                 (function(){\r
119                     if (isDomLoaded) { return; }\r
120                     if (!/loaded|complete/.test(doc.readyState)) {\r
121                         setTimeout(arguments.callee, 0);\r
122                         return;\r
123                     }\r
124                     callDomLoadFunctions();\r
125                 })();\r
126             }\r
127             addLoadEvent(callDomLoadFunctions);\r
128         }\r
129     }();\r
130     \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
136         }\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
141             domLoadFnArr[i]();\r
142         }\r
143     }\r
144     \r
145     function addDomLoadEvent(fn) {\r
146         if (isDomLoaded) {\r
147             fn();\r
148         }\r
149         else { \r
150             domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+\r
151         }\r
152     }\r
153     \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
157      */\r
158     function addLoadEvent(fn) {\r
159         if (typeof win.addEventListener != UNDEF) {\r
160             win.addEventListener("load", fn, false);\r
161         }\r
162         else if (typeof doc.addEventListener != UNDEF) {\r
163             doc.addEventListener("load", fn, false);\r
164         }\r
165         else if (typeof win.attachEvent != UNDEF) {\r
166             addListener(win, "onload", fn);\r
167         }\r
168         else if (typeof win.onload == "function") {\r
169             var fnOld = win.onload;\r
170             win.onload = function() {\r
171                 fnOld();\r
172                 fn();\r
173             };\r
174         }\r
175         else {\r
176             win.onload = fn;\r
177         }\r
178     }\r
179     \r
180     /* Main function\r
181         - Will preferably execute onDomLoad, otherwise onload (as a fallback)\r
182     */\r
183     function main() { \r
184         if (plugin) {\r
185             testPlayerVersion();\r
186         }\r
187         else {\r
188             matchVersions();\r
189         }\r
190     }\r
191     \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
198     */\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
204         if (t) {\r
205             var counter = 0;\r
206             (function(){\r
207                 if (typeof t.GetVariable != UNDEF) {\r
208                     var d = t.GetVariable("$version");\r
209                     if (d) {\r
210                         d = d.split(" ")[1].split(",");\r
211                         ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];\r
212                     }\r
213                 }\r
214                 else if (counter < 10) {\r
215                     counter++;\r
216                     setTimeout(arguments.callee, 10);\r
217                     return;\r
218                 }\r
219                 b.removeChild(o);\r
220                 t = null;\r
221                 matchVersions();\r
222             })();\r
223         }\r
224         else {\r
225             matchVersions();\r
226         }\r
227     }\r
228     \r
229     /* Perform Flash Player and SWF version matching; static publishing only\r
230     */\r
231     function matchVersions() {\r
232         var rl = regObjArr.length;\r
233         if (rl > 0) {\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
240                     if (obj) {\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
243                             if (cb) {\r
244                                 cbObj.success = true;\r
245                                 cbObj.ref = getObjectById(id);\r
246                                 cb(cbObj);\r
247                             }\r
248                         }\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
250                             var att = {};\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
257                             var par = {};\r
258                             var p = obj.getElementsByTagName("param");\r
259                             var pl = p.length;\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
263                                 }\r
264                             }\r
265                             showExpressInstall(att, par, id, cb);\r
266                         }\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
270                         }\r
271                     }\r
272                 }\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
275                     if (cb) {\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
279                             cbObj.ref = o;\r
280                         }\r
281                         cb(cbObj);\r
282                     }\r
283                 }\r
284             }\r
285         }\r
286     }\r
287     \r
288     function getObjectById(objectIdStr) {\r
289         var r = null;\r
290         var o = getElementById(objectIdStr);\r
291         if (o && o.nodeName == "OBJECT") {\r
292             if (typeof o.SetVariable != UNDEF) {\r
293                 r = o;\r
294             }\r
295             else {\r
296                 var n = o.getElementsByTagName(OBJECT)[0];\r
297                 if (n) {\r
298                     r = n;\r
299                 }\r
300             }\r
301         }\r
302         return r;\r
303     }\r
304     \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
308         - Win/Mac OS only\r
309         - no Webkit engines older than version 312\r
310     */\r
311     function canExpressInstall() {\r
312         return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312);\r
313     }\r
314     \r
315     /* Show the Adobe Express Install dialog\r
316         - Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75\r
317     */\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
323         if (obj) {\r
324             if (obj.nodeName == "OBJECT") { // static publishing\r
325                 storedAltContent = abstractAltContent(obj);\r
326                 storedAltContentId = null;\r
327             }\r
328             else { // dynamic publishing\r
329                 storedAltContent = obj;\r
330                 storedAltContentId = replaceElemIdStr;\r
331             }\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
340             }\r
341             else {\r
342                 par.flashvars = fv;\r
343             }\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
352                 (function(){\r
353                     if (obj.readyState == 4) {\r
354                         obj.parentNode.removeChild(obj);\r
355                     }\r
356                     else {\r
357                         setTimeout(arguments.callee, 10);\r
358                     }\r
359                 })();\r
360             }\r
361             createSWF(att, par, replaceElemIdStr);\r
362         }\r
363     }\r
364     \r
365     /* Functions to abstract and display alternative content\r
366     */\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
375             (function(){\r
376                 if (obj.readyState == 4) {\r
377                     obj.parentNode.removeChild(obj);\r
378                 }\r
379                 else {\r
380                     setTimeout(arguments.callee, 10);\r
381                 }\r
382             })();\r
383         }\r
384         else {\r
385             obj.parentNode.replaceChild(abstractAltContent(obj), obj);\r
386         }\r
387     } \r
388 \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
393         }\r
394         else {\r
395             var nestedObj = obj.getElementsByTagName(OBJECT)[0];\r
396             if (nestedObj) {\r
397                 var c = nestedObj.childNodes;\r
398                 if (c) {\r
399                     var cl = c.length;\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
403                         }\r
404                     }\r
405                 }\r
406             }\r
407         }\r
408         return ac;\r
409     }\r
410     \r
411     /* Cross-browser dynamic SWF creation\r
412     */\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
416         if (el) {\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
418                 attObj.id = id;\r
419             }\r
420             if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML\r
421                 var att = "";\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
426                         }\r
427                         else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword\r
428                             att += ' class="' + attObj[i] + '"';\r
429                         }\r
430                         else if (i.toLowerCase() != "classid") {\r
431                             att += ' ' + i + '="' + attObj[i] + '"';\r
432                         }\r
433                     }\r
434                 }\r
435                 var par = "";\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
439                     }\r
440                 }\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
444             }\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
452                         }\r
453                         else if (m.toLowerCase() != "classid") { // filter out IE specific attribute\r
454                             o.setAttribute(m, attObj[m]);\r
455                         }\r
456                     }\r
457                 }\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
461                     }\r
462                 }\r
463                 el.parentNode.replaceChild(o, el);\r
464                 r = o;\r
465             }\r
466         }\r
467         return r;\r
468     }\r
469     \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
474         el.appendChild(p);\r
475     }\r
476     \r
477     /* Cross-browser SWF removal\r
478         - Especially needed to safely and completely remove a SWF in Internet Explorer\r
479     */\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
485                 (function(){\r
486                     if (obj.readyState == 4) {\r
487                         removeObjectInIE(id);\r
488                     }\r
489                     else {\r
490                         setTimeout(arguments.callee, 10);\r
491                     }\r
492                 })();\r
493             }\r
494             else {\r
495                 obj.parentNode.removeChild(obj);\r
496             }\r
497         }\r
498     }\r
499     \r
500     function removeObjectInIE(id) {\r
501         var obj = getElementById(id);\r
502         if (obj) {\r
503             for (var i in obj) {\r
504                 if (typeof obj[i] == "function") {\r
505                     obj[i] = null;\r
506                 }\r
507             }\r
508             obj.parentNode.removeChild(obj);\r
509         }\r
510     }\r
511     \r
512     /* Functions to optimize JavaScript compression\r
513     */\r
514     function getElementById(id) {\r
515         var el = null;\r
516         try {\r
517             el = doc.getElementById(id);\r
518         }\r
519         catch (e) {}\r
520         return el;\r
521     }\r
522     \r
523     function createElement(el) {\r
524         return doc.createElement(el);\r
525     }\r
526     \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
529     */  \r
530     function addListener(target, eventType, fn) {\r
531         target.attachEvent(eventType, fn);\r
532         listenersArr[listenersArr.length] = [target, eventType, fn];\r
533     }\r
534     \r
535     /* Flash Player and SWF content version matching\r
536     */\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
543     }\r
544     \r
545     /* Cross-browser dynamic CSS creation\r
546         - Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php\r
547     */  \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
553         if (newStyle) {\r
554             dynamicStylesheet = null;\r
555             dynamicStylesheetMedia = null;\r
556         }\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
565             }\r
566             dynamicStylesheetMedia = m;\r
567         }\r
568         // add style rule\r
569         if (ua.ie && ua.win) {\r
570             if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) {\r
571                 dynamicStylesheet.addRule(sel, decl);\r
572             }\r
573         }\r
574         else {\r
575             if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) {\r
576                 dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}"));\r
577             }\r
578         }\r
579     }\r
580     \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
586         }\r
587         else {\r
588             createCSS("#" + id, "visibility:" + v);\r
589         }\r
590     }\r
591 \r
592     /* Filter to avoid XSS attacks\r
593     */\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
598     }\r
599     \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
601     */\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
609                 }\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
614                 }\r
615                 // cleanup library's main closures to avoid memory leaks\r
616                 for (var k in ua) {\r
617                     ua[k] = null;\r
618                 }\r
619                 ua = null;\r
620                 for (var l in swfobject) {\r
621                     swfobject[l] = null;\r
622                 }\r
623                 swfobject = null;\r
624             });\r
625         }\r
626     }();\r
627     \r
628     return {\r
629         /* Public API\r
630             - Reference: http://code.google.com/p/swfobject/wiki/documentation\r
631         */ \r
632         registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) {\r
633             if (ua.w3 && objectIdStr && swfVersionStr) {\r
634                 var regObj = {};\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
641             }\r
642             else if (callbackFn) {\r
643                 callbackFn({success:false, id:objectIdStr});\r
644             }\r
645         },\r
646         \r
647         getObjectById: function(objectIdStr) {\r
648             if (ua.w3) {\r
649                 return getObjectById(objectIdStr);\r
650             }\r
651         },\r
652         \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
659                     heightStr += "";\r
660                     var att = {};\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
664                         }\r
665                     }\r
666                     att.data = swfUrlStr;\r
667                     att.width = widthStr;\r
668                     att.height = heightStr;\r
669                     var par = {}; \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
673                         }\r
674                     }\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
679                             }\r
680                             else {\r
681                                 par.flashvars = k + "=" + flashvarsObj[k];\r
682                             }\r
683                         }\r
684                     }\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
689                         }\r
690                         callbackObj.success = true;\r
691                         callbackObj.ref = obj;\r
692                     }\r
693                     else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install\r
694                         att.data = xiSwfUrlStr;\r
695                         showExpressInstall(att, par, replaceElemIdStr, callbackFn);\r
696                         return;\r
697                     }\r
698                     else { // show alternative content\r
699                         setVisibility(replaceElemIdStr, true);\r
700                     }\r
701                     if (callbackFn) { callbackFn(callbackObj); }\r
702                 });\r
703             }\r
704             else if (callbackFn) { callbackFn(callbackObj); }\r
705         },\r
706         \r
707         switchOffAutoHideShow: function() {\r
708             autoHideShow = false;\r
709         },\r
710         \r
711         ua: ua,\r
712         \r
713         getFlashPlayerVersion: function() {\r
714             return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };\r
715         },\r
716         \r
717         hasFlashPlayerVersion: hasPlayerVersion,\r
718         \r
719         createSWF: function(attObj, parObj, replaceElemIdStr) {\r
720             if (ua.w3) {\r
721                 return createSWF(attObj, parObj, replaceElemIdStr);\r
722             }\r
723             else {\r
724                 return undefined;\r
725             }\r
726         },\r
727         \r
728         showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) {\r
729             if (ua.w3 && canExpressInstall()) {\r
730                 showExpressInstall(att, par, replaceElemIdStr, callbackFn);\r
731             }\r
732         },\r
733         \r
734         removeSWF: function(objElemIdStr) {\r
735             if (ua.w3) {\r
736                 removeSWF(objElemIdStr);\r
737             }\r
738         },\r
739         \r
740         createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) {\r
741             if (ua.w3) {\r
742                 createCSS(selStr, declStr, mediaStr, newStyleBoolean);\r
743             }\r
744         },\r
745         \r
746         addDomLoadEvent: addDomLoadEvent,\r
747         \r
748         addLoadEvent: addLoadEvent,\r
749         \r
750         getQueryParamValue: function(param) {\r
751             var q = doc.location.search || doc.location.hash;\r
752             if (q) {\r
753                 if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark\r
754                 if (param == null) {\r
755                     return urlEncodeIfNecessary(q);\r
756                 }\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
761                     }\r
762                 }\r
763             }\r
764             return "";\r
765         },\r
766         \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
776                     }\r
777                     if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); }\r
778                 }\r
779                 isExpressInstallActive = false;\r
780             } \r
781         }\r
782     };\r
783 }();\r
784 /**
785  * @class Ext.FlashComponent
786  * @extends Ext.BoxComponent
787  * @constructor
788  * @xtype flash
789  */
790 Ext.FlashComponent = Ext.extend(Ext.BoxComponent, {
791     /**
792      * @cfg {String} flashVersion
793      * Indicates the version the flash content was published for. Defaults to <tt>'9.0.45'</tt>.
794      */
795     flashVersion : '9.0.115',
796
797     /**
798      * @cfg {String} backgroundColor
799      * The background color of the chart. Defaults to <tt>'#ffffff'</tt>.
800      */
801     backgroundColor: '#ffffff',
802
803     /**
804      * @cfg {String} wmode
805      * The wmode of the flash object. This can be used to control layering. Defaults to <tt>'opaque'</tt>.
806      */
807     wmode: 'opaque',
808     
809     /**
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>.
812      */
813     flashVars: undefined,
814     
815     /**
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>.
819      */
820     flashParams: undefined,
821
822     /**
823      * @cfg {String} url
824      * The URL of the chart to include. Defaults to <tt>undefined</tt>.
825      */
826     url: undefined,
827     swfId : undefined,
828     swfWidth: '100%',
829     swfHeight: '100%',
830
831     /**
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>.
835      */
836     expressInstall: false,
837
838     initComponent : function(){
839         Ext.FlashComponent.superclass.initComponent.call(this);
840
841         this.addEvents(
842             /**
843              * @event initialize
844              * 
845              * @param {Chart} this
846              */
847             'initialize'
848         );
849     },
850
851     onRender : function(){
852         Ext.FlashComponent.superclass.onRender.apply(this, arguments);
853
854         var params = Ext.apply({
855             allowScriptAccess: 'always',
856             bgcolor: this.backgroundColor,
857             wmode: this.wmode
858         }, this.flashParams), vars = Ext.apply({
859             allowedDomain: document.location.hostname,
860             elementID: this.getId(),
861             eventHandler: 'Ext.FlashEventProxy.onEvent'
862         }, this.flashVars);
863
864         new swfobject.embedSWF(this.url, this.id, this.swfWidth, this.swfHeight, this.flashVersion,
865             this.expressInstall ? Ext.FlashComponent.EXPRESS_INSTALL_URL : undefined, vars, params);
866
867         this.swf = Ext.getDom(this.id);
868         this.el = Ext.get(this.swf);
869     },
870
871     getSwfId : function(){
872         return this.swfId || (this.swfId = "extswf" + (++Ext.Component.AUTO_ID));
873     },
874
875     getId : function(){
876         return this.id || (this.id = "extflashcmp" + (++Ext.Component.AUTO_ID));
877     },
878
879     onFlashEvent : function(e){
880         switch(e.type){
881             case "swfReady":
882                 this.initSwf();
883                 return;
884             case "log":
885                 return;
886         }
887         e.component = this;
888         this.fireEvent(e.type.toLowerCase().replace(/event$/, ''), e);
889     },
890
891     initSwf : function(){
892         this.onSwfReady(!!this.isInitialized);
893         this.isInitialized = true;
894         this.fireEvent('initialize', this);
895     },
896
897     beforeDestroy: function(){
898         if(this.rendered){
899             swfobject.removeSWF(this.swf.id);
900         }
901         Ext.FlashComponent.superclass.beforeDestroy.call(this);
902     },
903
904     onSwfReady : Ext.emptyFn
905 });
906
907 /**
908  * Sets the url for installing flash if it doesn't exist. This should be set to a local resource.
909  * @static
910  * @type String
911  */
912 Ext.FlashComponent.EXPRESS_INSTALL_URL = 'http:/' + '/swfobject.googlecode.com/svn/trunk/swfobject/expressInstall.swf';
913
914 Ext.reg('flash', Ext.FlashComponent);/**\r
915  * @class Ext.FlashProxy\r
916  * @singleton\r
917  */\r
918 Ext.FlashEventProxy = {\r
919     onEvent : function(id, e){\r
920         var fp = Ext.getCmp(id);\r
921         if(fp){\r
922             fp.onFlashEvent(e);\r
923         }else{\r
924             arguments.callee.defer(10, this, [id, e]);\r
925         }\r
926     }\r
927 }/**\r
928  * @class Ext.chart.Chart\r
929  * @extends Ext.FlashComponent\r
930  * The Ext.chart package provides the capability to visualize data with flash based charting.\r
931  * Each chart binds directly to an Ext.data.Store enabling automatic updates of the chart.\r
932  * To change the look and feel of a chart, see the {@link #chartStyle} and {@link #extraStyle} config options.\r
933  * @constructor\r
934  * @xtype chart\r
935  */\r
936  \r
937  Ext.chart.Chart = Ext.extend(Ext.FlashComponent, {\r
938     refreshBuffer: 100,\r
939     \r
940     /**\r
941      * @cfg {String} backgroundColor\r
942      * @hide\r
943      */\r
944 \r
945     /**\r
946      * @cfg {Object} chartStyle\r
947      * Sets styles for this chart. This contains default styling, so modifying this property will <b>override</b>\r
948      * the built in styles of the chart. Use {@link #extraStyle} to add customizations to the default styling. \r
949      */\r
950     chartStyle: {\r
951         padding: 10,\r
952         animationEnabled: true,\r
953         font: {\r
954             name: 'Tahoma',\r
955             color: 0x444444,\r
956             size: 11\r
957         },\r
958         dataTip: {\r
959             padding: 5,\r
960             border: {\r
961                 color: 0x99bbe8,\r
962                 size:1\r
963             },\r
964             background: {\r
965                 color: 0xDAE7F6,\r
966                 alpha: .9\r
967             },\r
968             font: {\r
969                 name: 'Tahoma',\r
970                 color: 0x15428B,\r
971                 size: 10,\r
972                 bold: true\r
973             }\r
974         }\r
975     },\r
976     \r
977     /**\r
978      * @cfg {String} url\r
979      * The url to load the chart from. This defaults to Ext.chart.Chart.CHART_URL, which should\r
980      * be modified to point to the local charts resource.\r
981      */\r
982     \r
983     /**\r
984      * @cfg {Object} extraStyle\r
985      * Contains extra styles that will be added or overwritten to the default chartStyle. Defaults to <tt>null</tt>.\r
986      * For a detailed list of the options available, visit the YUI Charts site \r
987      * at <a href="http://developer.yahoo.com/yui/charts/#basicstyles">http://developer.yahoo.com/yui/charts/#basicstyles</a><br/>\r
988      * Some of the options availabe:<br />\r
989      * <ul style="padding:5px;padding-left:16px;list-style-type:inherit;">\r
990      * <li><b>padding</b> - The space around the edge of the chart's contents. Padding does not increase the size of the chart.</li>\r
991      * <li><b>animationEnabled</b> - A Boolean value that specifies whether marker animations are enabled or not. Enabled by default.</li>\r
992      * <li><b>font</b> - An Object defining the font style to be used in the chart. Defaults to <tt>{ name: 'Tahoma', color: 0x444444, size: 11 }</tt><br/>\r
993      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">\r
994      *      <li><b>name</b> - font name</li>\r
995      *      <li><b>color</b> - font color (hex code, ie: "#ff0000", "ff0000" or 0xff0000)</li>\r
996      *      <li><b>size</b> - font size in points (numeric portion only, ie: 11)</li>\r
997      *      <li><b>bold</b> - boolean</li>\r
998      *      <li><b>italic</b> - boolean</li>\r
999      *      <li><b>underline</b> - boolean</li>\r
1000      *  </ul>\r
1001      * </li>\r
1002      * <li><b>border</b> - An object defining the border style around the chart. The chart itself will decrease in dimensions to accomodate the border.<br/>\r
1003      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">\r
1004      *      <li><b>color</b> - border color (hex code, ie: "#ff0000", "ff0000" or 0xff0000)</li>\r
1005      *      <li><b>size</b> - border size in pixels (numeric portion only, ie: 1)</li>\r
1006      *  </ul>\r
1007      * </li>\r
1008      * <li><b>background</b> - An object defining the background style of the chart.<br/>\r
1009      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">\r
1010      *      <li><b>color</b> - border color (hex code, ie: "#ff0000", "ff0000" or 0xff0000)</li>\r
1011      *      <li><b>image</b> - an image URL. May be relative to the current document or absolute.</li>\r
1012      *  </ul>\r
1013      * </li>\r
1014      * <li><b>legend</b> - An object defining the legend style<br/>\r
1015      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">\r
1016      *      <li><b>display</b> - location of the legend. Possible values are "none", "left", "right", "top", and "bottom".</li>\r
1017      *      <li><b>spacing</b> - an image URL. May be relative to the current document or absolute.</li>\r
1018      *      <li><b>padding, border, background, font</b> - same options as described above.</li>\r
1019      *  </ul></li>\r
1020      * <li><b>dataTip</b> - An object defining the style of the data tip (tooltip).<br/>\r
1021      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">\r
1022      *      <li><b>padding, border, background, font</b> - same options as described above.</li>\r
1023      *  </ul></li>\r
1024      * <li><b>xAxis and yAxis</b> - An object defining the style of the style of either axis.<br/>\r
1025      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">\r
1026      *      <li><b>color</b> - same option as described above.</li>\r
1027      *      <li><b>size</b> - same option as described above.</li>\r
1028      *      <li><b>showLabels</b> - boolean</li>\r
1029      *      <li><b>labelRotation</b> - a value in degrees from -90 through 90. Default is zero.</li>\r
1030      *  </ul></li>\r
1031      * <li><b>majorGridLines and minorGridLines</b> - An object defining the style of the style of the grid lines.<br/>\r
1032      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">\r
1033      *      <li><b>color, size</b> - same options as described above.</li>\r
1034      *  </ul></li></li>\r
1035      * <li><b>zeroGridLine</b> - An object defining the style of the style of the zero grid line.<br/>\r
1036      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">\r
1037      *      <li><b>color, size</b> - same options as described above.</li>\r
1038      *  </ul></li></li>\r
1039      * <li><b>majorTicks and minorTicks</b> - An object defining the style of the style of ticks in the chart.<br/>\r
1040      *  <ul style="padding:5px;padding-left:26px;list-style-type:circle;">\r
1041      *      <li><b>color, size</b> - same options as described above.</li>\r
1042      *      <li><b>length</b> - the length of each tick in pixels extending from the axis.</li>\r
1043      *      <li><b>display</b> - how the ticks are drawn. Possible values are "none", "inside", "outside", and "cross".</li>\r
1044      *  </ul></li></li>\r
1045      * </ul>\r
1046      */\r
1047     extraStyle: null,\r
1048     \r
1049     /**\r
1050      * @cfg {Object} seriesStyles\r
1051      * Contains styles to apply to the series after a refresh. Defaults to <tt>null</tt>.\r
1052      */\r
1053     seriesStyles: null,\r
1054     \r
1055     /**\r
1056      * @cfg {Boolean} disableCaching\r
1057      * True to add a "cache buster" to the end of the chart url. Defaults to true for Opera and IE.\r
1058      */\r
1059     disableCaching: Ext.isIE || Ext.isOpera,\r
1060     disableCacheParam: '_dc',\r
1061 \r
1062     initComponent : function(){\r
1063         Ext.chart.Chart.superclass.initComponent.call(this);\r
1064         if(!this.url){\r
1065             this.url = Ext.chart.Chart.CHART_URL;\r
1066         }\r
1067         if(this.disableCaching){\r
1068             this.url = Ext.urlAppend(this.url, String.format('{0}={1}', this.disableCacheParam, new Date().getTime()));\r
1069         }\r
1070         this.addEvents(\r
1071             'itemmouseover',\r
1072             'itemmouseout',\r
1073             'itemclick',\r
1074             'itemdoubleclick',\r
1075             'itemdragstart',\r
1076             'itemdrag',\r
1077             'itemdragend',\r
1078             /**\r
1079              * @event beforerefresh\r
1080              * Fires before a refresh to the chart data is called.  If the beforerefresh handler returns\r
1081              * <tt>false</tt> the {@link #refresh} action will be cancelled.\r
1082              * @param {Chart} this\r
1083              */\r
1084             'beforerefresh',\r
1085             /**\r
1086              * @event refresh\r
1087              * Fires after the chart data has been refreshed.\r
1088              * @param {Chart} this\r
1089              */\r
1090             'refresh'\r
1091         );\r
1092         this.store = Ext.StoreMgr.lookup(this.store);\r
1093     },\r
1094 \r
1095     /**\r
1096      * Sets a single style value on the Chart instance.\r
1097      *\r
1098      * @param name {String} Name of the Chart style value to change.\r
1099      * @param value {Object} New value to pass to the Chart style.\r
1100      */\r
1101      setStyle: function(name, value){\r
1102          this.swf.setStyle(name, Ext.encode(value));\r
1103      },\r
1104 \r
1105     /**\r
1106      * Resets all styles on the Chart instance.\r
1107      *\r
1108      * @param styles {Object} Initializer for all Chart styles.\r
1109      */\r
1110     setStyles: function(styles){\r
1111         this.swf.setStyles(Ext.encode(styles));\r
1112     },\r
1113 \r
1114     /**\r
1115      * Sets the styles on all series in the Chart.\r
1116      *\r
1117      * @param styles {Array} Initializer for all Chart series styles.\r
1118      */\r
1119     setSeriesStyles: function(styles){\r
1120         this.seriesStyles = styles;\r
1121         var s = [];\r
1122         Ext.each(styles, function(style){\r
1123             s.push(Ext.encode(style));\r
1124         });\r
1125         this.swf.setSeriesStyles(s);\r
1126     },\r
1127 \r
1128     setCategoryNames : function(names){\r
1129         this.swf.setCategoryNames(names);\r
1130     },\r
1131 \r
1132     setTipRenderer : function(fn){\r
1133         var chart = this;\r
1134         this.tipFnName = this.createFnProxy(function(item, index, series){\r
1135             var record = chart.store.getAt(index);\r
1136             return fn(chart, record, index, series);\r
1137         }, this.tipFnName);\r
1138         this.swf.setDataTipFunction(this.tipFnName);\r
1139     },\r
1140 \r
1141     setSeries : function(series){\r
1142         this.series = series;\r
1143         this.refresh();\r
1144     },\r
1145 \r
1146     /**\r
1147      * Changes the data store bound to this chart and refreshes it.\r
1148      * @param {Store} store The store to bind to this chart\r
1149      */\r
1150     bindStore : function(store, initial){\r
1151         if(!initial && this.store){\r
1152             if(store !== this.store && this.store.autoDestroy){\r
1153                 this.store.destroy();\r
1154             }else{\r
1155                 this.store.un("datachanged", this.refresh, this);\r
1156                 this.store.un("add", this.delayRefresh, this);\r
1157                 this.store.un("remove", this.delayRefresh, this);\r
1158                 this.store.un("update", this.delayRefresh, this);\r
1159                 this.store.un("clear", this.refresh, this);\r
1160             }\r
1161         }\r
1162         if(store){\r
1163             store = Ext.StoreMgr.lookup(store);\r
1164             store.on({\r
1165                 scope: this,\r
1166                 datachanged: this.refresh,\r
1167                 add: this.delayRefresh,\r
1168                 remove: this.delayRefresh,\r
1169                 update: this.delayRefresh,\r
1170                 clear: this.refresh\r
1171             });\r
1172         }\r
1173         this.store = store;\r
1174         if(store && !initial){\r
1175             this.refresh();\r
1176         }\r
1177     },\r
1178 \r
1179     onSwfReady : function(isReset){\r
1180         Ext.chart.Chart.superclass.onSwfReady.call(this, isReset);\r
1181         this.swf.setType(this.type);\r
1182 \r
1183         if(this.chartStyle){\r
1184             this.setStyles(Ext.apply({}, this.extraStyle, this.chartStyle));\r
1185         }\r
1186 \r
1187         if(this.categoryNames){\r
1188             this.setCategoryNames(this.categoryNames);\r
1189         }\r
1190 \r
1191         if(this.tipRenderer){\r
1192             this.setTipRenderer(this.tipRenderer);\r
1193         }\r
1194         if(!isReset){\r
1195             this.bindStore(this.store, true);\r
1196         }\r
1197         this.refresh.defer(10, this);\r
1198     },\r
1199 \r
1200     delayRefresh : function(){\r
1201         if(!this.refreshTask){\r
1202             this.refreshTask = new Ext.util.DelayedTask(this.refresh, this);\r
1203         }\r
1204         this.refreshTask.delay(this.refreshBuffer);\r
1205     },\r
1206 \r
1207     refresh : function(){\r
1208         if(this.fireEvent('beforerefresh', this) !== false){\r
1209                 var styleChanged = false;\r
1210                 // convert the store data into something YUI charts can understand\r
1211                 var data = [], rs = this.store.data.items;\r
1212                 for(var j = 0, len = rs.length; j < len; j++){\r
1213                     data[j] = rs[j].data;\r
1214                 }\r
1215                 //make a copy of the series definitions so that we aren't\r
1216                 //editing them directly.\r
1217                 var dataProvider = [];\r
1218                 var seriesCount = 0;\r
1219                 var currentSeries = null;\r
1220                 var i = 0;\r
1221                 if(this.series){\r
1222                     seriesCount = this.series.length;\r
1223                     for(i = 0; i < seriesCount; i++){\r
1224                         currentSeries = this.series[i];\r
1225                         var clonedSeries = {};\r
1226                         for(var prop in currentSeries){\r
1227                             if(prop == "style" && currentSeries.style !== null){\r
1228                                 clonedSeries.style = Ext.encode(currentSeries.style);\r
1229                                 styleChanged = true;\r
1230                                 //we don't want to modify the styles again next time\r
1231                                 //so null out the style property.\r
1232                                 // this causes issues\r
1233                                 // currentSeries.style = null;\r
1234                             } else{\r
1235                                 clonedSeries[prop] = currentSeries[prop];\r
1236                             }\r
1237                         }\r
1238                         dataProvider.push(clonedSeries);\r
1239                     }\r
1240                 }\r
1241         \r
1242                 if(seriesCount > 0){\r
1243                     for(i = 0; i < seriesCount; i++){\r
1244                         currentSeries = dataProvider[i];\r
1245                         if(!currentSeries.type){\r
1246                             currentSeries.type = this.type;\r
1247                         }\r
1248                         currentSeries.dataProvider = data;\r
1249                     }\r
1250                 } else{\r
1251                     dataProvider.push({type: this.type, dataProvider: data});\r
1252                 }\r
1253                 this.swf.setDataProvider(dataProvider);\r
1254                 if(this.seriesStyles){\r
1255                     this.setSeriesStyles(this.seriesStyles);\r
1256                 }\r
1257             this.fireEvent('refresh', this);\r
1258         }\r
1259     },\r
1260 \r
1261     createFnProxy : function(fn, old){\r
1262         if(old){\r
1263             delete window[old];\r
1264         }\r
1265         var fnName = "extFnProxy" + (++Ext.chart.Chart.PROXY_FN_ID);\r
1266         window[fnName] = fn;\r
1267         return fnName;\r
1268     },\r
1269     \r
1270     onDestroy: function(){\r
1271         Ext.chart.Chart.superclass.onDestroy.call(this);\r
1272         this.bindStore(null);\r
1273         var tip = this.tipFnName;\r
1274         if(!Ext.isEmpty(tip)){\r
1275             delete window[tip];\r
1276         }\r
1277     }\r
1278 });\r
1279 Ext.reg('chart', Ext.chart.Chart);\r
1280 Ext.chart.Chart.PROXY_FN_ID = 0;\r
1281 \r
1282 /**\r
1283  * Sets the url to load the chart from. This should be set to a local resource.\r
1284  * @static\r
1285  * @type String\r
1286  */\r
1287 Ext.chart.Chart.CHART_URL = 'http:/' + '/yui.yahooapis.com/2.7.0/build/charts/assets/charts.swf';\r
1288 \r
1289 /**\r
1290  * @class Ext.chart.PieChart\r
1291  * @extends Ext.chart.Chart\r
1292  * @constructor\r
1293  * @xtype piechart\r
1294  */\r
1295 Ext.chart.PieChart = Ext.extend(Ext.chart.Chart, {\r
1296     type: 'pie',\r
1297 \r
1298     onSwfReady : function(isReset){\r
1299         Ext.chart.PieChart.superclass.onSwfReady.call(this, isReset);\r
1300 \r
1301         this.setDataField(this.dataField);\r
1302         this.setCategoryField(this.categoryField);\r
1303     },\r
1304 \r
1305     setDataField : function(field){\r
1306         this.dataField = field;\r
1307         this.swf.setDataField(field);\r
1308     },\r
1309 \r
1310     setCategoryField : function(field){\r
1311         this.categoryField = field;\r
1312         this.swf.setCategoryField(field);\r
1313     }\r
1314 });\r
1315 Ext.reg('piechart', Ext.chart.PieChart);\r
1316 \r
1317 /**\r
1318  * @class Ext.chart.CartesianChart\r
1319  * @extends Ext.chart.Chart\r
1320  * @constructor\r
1321  * @xtype cartesianchart\r
1322  */\r
1323 Ext.chart.CartesianChart = Ext.extend(Ext.chart.Chart, {\r
1324     onSwfReady : function(isReset){\r
1325         Ext.chart.CartesianChart.superclass.onSwfReady.call(this, isReset);\r
1326 \r
1327         if(this.xField){\r
1328             this.setXField(this.xField);\r
1329         }\r
1330         if(this.yField){\r
1331             this.setYField(this.yField);\r
1332         }\r
1333         if(this.xAxis){\r
1334             this.setXAxis(this.xAxis);\r
1335         }\r
1336         if(this.yAxis){\r
1337             this.setYAxis(this.yAxis);\r
1338         }\r
1339     },\r
1340 \r
1341     setXField : function(value){\r
1342         this.xField = value;\r
1343         this.swf.setHorizontalField(value);\r
1344     },\r
1345 \r
1346     setYField : function(value){\r
1347         this.yField = value;\r
1348         this.swf.setVerticalField(value);\r
1349     },\r
1350 \r
1351     setXAxis : function(value){\r
1352         this.xAxis = this.createAxis('xAxis', value);\r
1353         this.swf.setHorizontalAxis(this.xAxis);\r
1354     },\r
1355 \r
1356     setYAxis : function(value){\r
1357         this.yAxis = this.createAxis('yAxis', value);\r
1358         this.swf.setVerticalAxis(this.yAxis);\r
1359     },\r
1360 \r
1361     createAxis : function(axis, value){\r
1362         var o = Ext.apply({}, value), oldFn = null;\r
1363         if(this[axis]){\r
1364             oldFn = this[axis].labelFunction;\r
1365         }\r
1366         if(o.labelRenderer){\r
1367             var fn = o.labelRenderer;\r
1368             o.labelFunction = this.createFnProxy(function(v){\r
1369                 return fn(v);\r
1370             }, oldFn);\r
1371             delete o.labelRenderer;\r
1372         }\r
1373         return o;\r
1374     }\r
1375 });\r
1376 Ext.reg('cartesianchart', Ext.chart.CartesianChart);\r
1377 \r
1378 /**\r
1379  * @class Ext.chart.LineChart\r
1380  * @extends Ext.chart.CartesianChart\r
1381  * @constructor\r
1382  * @xtype linechart\r
1383  */\r
1384 Ext.chart.LineChart = Ext.extend(Ext.chart.CartesianChart, {\r
1385     type: 'line'\r
1386 });\r
1387 Ext.reg('linechart', Ext.chart.LineChart);\r
1388 \r
1389 /**\r
1390  * @class Ext.chart.ColumnChart\r
1391  * @extends Ext.chart.CartesianChart\r
1392  * @constructor\r
1393  * @xtype columnchart\r
1394  */\r
1395 Ext.chart.ColumnChart = Ext.extend(Ext.chart.CartesianChart, {\r
1396     type: 'column'\r
1397 });\r
1398 Ext.reg('columnchart', Ext.chart.ColumnChart);\r
1399 \r
1400 /**\r
1401  * @class Ext.chart.StackedColumnChart\r
1402  * @extends Ext.chart.CartesianChart\r
1403  * @constructor\r
1404  * @xtype stackedcolumnchart\r
1405  */\r
1406 Ext.chart.StackedColumnChart = Ext.extend(Ext.chart.CartesianChart, {\r
1407     type: 'stackcolumn'\r
1408 });\r
1409 Ext.reg('stackedcolumnchart', Ext.chart.StackedColumnChart);\r
1410 \r
1411 /**\r
1412  * @class Ext.chart.BarChart\r
1413  * @extends Ext.chart.CartesianChart\r
1414  * @constructor\r
1415  * @xtype barchart\r
1416  */\r
1417 Ext.chart.BarChart = Ext.extend(Ext.chart.CartesianChart, {\r
1418     type: 'bar'\r
1419 });\r
1420 Ext.reg('barchart', Ext.chart.BarChart);\r
1421 \r
1422 /**\r
1423  * @class Ext.chart.StackedBarChart\r
1424  * @extends Ext.chart.CartesianChart\r
1425  * @constructor\r
1426  * @xtype stackedbarchart\r
1427  */\r
1428 Ext.chart.StackedBarChart = Ext.extend(Ext.chart.CartesianChart, {\r
1429     type: 'stackbar'\r
1430 });\r
1431 Ext.reg('stackedbarchart', Ext.chart.StackedBarChart);\r
1432 \r
1433 \r
1434 \r
1435 /**\r
1436  * @class Ext.chart.Axis\r
1437  * Defines a CartesianChart's vertical or horizontal axis.\r
1438  * @constructor\r
1439  */\r
1440 Ext.chart.Axis = function(config){\r
1441     Ext.apply(this, config);\r
1442 };\r
1443 \r
1444 Ext.chart.Axis.prototype =\r
1445 {\r
1446     /**\r
1447      * The type of axis.\r
1448      *\r
1449      * @property type\r
1450      * @type String\r
1451      */\r
1452     type: null,\r
1453 \r
1454     /**\r
1455      * The direction in which the axis is drawn. May be "horizontal" or "vertical".\r
1456      *\r
1457      * @property orientation\r
1458      * @type String\r
1459      */\r
1460     orientation: "horizontal",\r
1461 \r
1462     /**\r
1463      * If true, the items on the axis will be drawn in opposite direction.\r
1464      *\r
1465      * @property reverse\r
1466      * @type Boolean\r
1467      */\r
1468     reverse: false,\r
1469 \r
1470     /**\r
1471      * A string reference to the globally-accessible function that may be called to\r
1472      * determine each of the label values for this axis.\r
1473      *\r
1474      * @property labelFunction\r
1475      * @type String\r
1476      */\r
1477     labelFunction: null,\r
1478 \r
1479     /**\r
1480      * If true, labels that overlap previously drawn labels on the axis will be hidden.\r
1481      *\r
1482      * @property hideOverlappingLabels\r
1483      * @type Boolean\r
1484      */\r
1485     hideOverlappingLabels: true\r
1486 };\r
1487 \r
1488 /**\r
1489  * @class Ext.chart.NumericAxis\r
1490  * @extends Ext.chart.Axis\r
1491  * A type of axis whose units are measured in numeric values.\r
1492  * @constructor\r
1493  */\r
1494 Ext.chart.NumericAxis = Ext.extend(Ext.chart.Axis, {\r
1495     type: "numeric",\r
1496 \r
1497     /**\r
1498      * The minimum value drawn by the axis. If not set explicitly, the axis minimum\r
1499      * will be calculated automatically.\r
1500      *\r
1501      * @property minimum\r
1502      * @type Number\r
1503      */\r
1504     minimum: NaN,\r
1505 \r
1506     /**\r
1507      * The maximum value drawn by the axis. If not set explicitly, the axis maximum\r
1508      * will be calculated automatically.\r
1509      *\r
1510      * @property maximum\r
1511      * @type Number\r
1512      */\r
1513     maximum: NaN,\r
1514 \r
1515     /**\r
1516      * The spacing between major intervals on this axis.\r
1517      *\r
1518      * @property majorUnit\r
1519      * @type Number\r
1520      */\r
1521     majorUnit: NaN,\r
1522 \r
1523     /**\r
1524      * The spacing between minor intervals on this axis.\r
1525      *\r
1526      * @property minorUnit\r
1527      * @type Number\r
1528      */\r
1529     minorUnit: NaN,\r
1530 \r
1531     /**\r
1532      * If true, the labels, ticks, gridlines, and other objects will snap to\r
1533      * the nearest major or minor unit. If false, their position will be based\r
1534      * on the minimum value.\r
1535      *\r
1536      * @property snapToUnits\r
1537      * @type Boolean\r
1538      */\r
1539     snapToUnits: true,\r
1540 \r
1541     /**\r
1542      * If true, and the bounds are calculated automatically, either the minimum or\r
1543      * maximum will be set to zero.\r
1544      *\r
1545      * @property alwaysShowZero\r
1546      * @type Boolean\r
1547      */\r
1548     alwaysShowZero: true,\r
1549 \r
1550     /**\r
1551      * The scaling algorithm to use on this axis. May be "linear" or "logarithmic".\r
1552      *\r
1553      * @property scale\r
1554      * @type String\r
1555      */\r
1556     scale: "linear"\r
1557 });\r
1558 \r
1559 /**\r
1560  * @class Ext.chart.TimeAxis\r
1561  * @extends Ext.chart.Axis\r
1562  * A type of axis whose units are measured in time-based values.\r
1563  * @constructor\r
1564  */\r
1565 Ext.chart.TimeAxis = Ext.extend(Ext.chart.Axis, {\r
1566     type: "time",\r
1567 \r
1568     /**\r
1569      * The minimum value drawn by the axis. If not set explicitly, the axis minimum\r
1570      * will be calculated automatically.\r
1571      *\r
1572      * @property minimum\r
1573      * @type Date\r
1574      */\r
1575     minimum: null,\r
1576 \r
1577     /**\r
1578      * The maximum value drawn by the axis. If not set explicitly, the axis maximum\r
1579      * will be calculated automatically.\r
1580      *\r
1581      * @property maximum\r
1582      * @type Number\r
1583      */\r
1584     maximum: null,\r
1585 \r
1586     /**\r
1587      * The spacing between major intervals on this axis.\r
1588      *\r
1589      * @property majorUnit\r
1590      * @type Number\r
1591      */\r
1592     majorUnit: NaN,\r
1593 \r
1594     /**\r
1595      * The time unit used by the majorUnit.\r
1596      *\r
1597      * @property majorTimeUnit\r
1598      * @type String\r
1599      */\r
1600     majorTimeUnit: null,\r
1601 \r
1602     /**\r
1603      * The spacing between minor intervals on this axis.\r
1604      *\r
1605      * @property majorUnit\r
1606      * @type Number\r
1607      */\r
1608     minorUnit: NaN,\r
1609 \r
1610     /**\r
1611      * The time unit used by the minorUnit.\r
1612      *\r
1613      * @property majorTimeUnit\r
1614      * @type String\r
1615      */\r
1616     minorTimeUnit: null,\r
1617 \r
1618     /**\r
1619      * If true, the labels, ticks, gridlines, and other objects will snap to\r
1620      * the nearest major or minor unit. If false, their position will be based\r
1621      * on the minimum value.\r
1622      *\r
1623      * @property snapToUnits\r
1624      * @type Boolean\r
1625      */\r
1626     snapToUnits: true\r
1627 });\r
1628 \r
1629 /**\r
1630  * @class Ext.chart.CategoryAxis\r
1631  * @extends Ext.chart.Axis\r
1632  * A type of axis that displays items in categories.\r
1633  * @constructor\r
1634  */\r
1635 Ext.chart.CategoryAxis = Ext.extend(Ext.chart.Axis, {\r
1636     type: "category",\r
1637 \r
1638     /**\r
1639      * A list of category names to display along this axis.\r
1640      *\r
1641      * @property categoryNames\r
1642      * @type Array\r
1643      */\r
1644     categoryNames: null\r
1645 });\r
1646 \r
1647 /**\r
1648  * @class Ext.chart.Series\r
1649  * Series class for the charts widget.\r
1650  * @constructor\r
1651  */\r
1652 Ext.chart.Series = function(config) { Ext.apply(this, config); };\r
1653 \r
1654 Ext.chart.Series.prototype =\r
1655 {\r
1656     /**\r
1657      * The type of series.\r
1658      *\r
1659      * @property type\r
1660      * @type String\r
1661      */\r
1662     type: null,\r
1663 \r
1664     /**\r
1665      * The human-readable name of the series.\r
1666      *\r
1667      * @property displayName\r
1668      * @type String\r
1669      */\r
1670     displayName: null\r
1671 };\r
1672 \r
1673 /**\r
1674  * @class Ext.chart.CartesianSeries\r
1675  * @extends Ext.chart.Series\r
1676  * CartesianSeries class for the charts widget.\r
1677  * @constructor\r
1678  */\r
1679 Ext.chart.CartesianSeries = Ext.extend(Ext.chart.Series, {\r
1680     /**\r
1681      * The field used to access the x-axis value from the items from the data source.\r
1682      *\r
1683      * @property xField\r
1684      * @type String\r
1685      */\r
1686     xField: null,\r
1687 \r
1688     /**\r
1689      * The field used to access the y-axis value from the items from the data source.\r
1690      *\r
1691      * @property yField\r
1692      * @type String\r
1693      */\r
1694     yField: null\r
1695 });\r
1696 \r
1697 /**\r
1698  * @class Ext.chart.ColumnSeries\r
1699  * @extends Ext.chart.CartesianSeries\r
1700  * ColumnSeries class for the charts widget.\r
1701  * @constructor\r
1702  */\r
1703 Ext.chart.ColumnSeries = Ext.extend(Ext.chart.CartesianSeries, {\r
1704     type: "column"\r
1705 });\r
1706 \r
1707 /**\r
1708  * @class Ext.chart.LineSeries\r
1709  * @extends Ext.chart.CartesianSeries\r
1710  * LineSeries class for the charts widget.\r
1711  * @constructor\r
1712  */\r
1713 Ext.chart.LineSeries = Ext.extend(Ext.chart.CartesianSeries, {\r
1714     type: "line"\r
1715 });\r
1716 \r
1717 /**\r
1718  * @class Ext.chart.BarSeries\r
1719  * @extends Ext.chart.CartesianSeries\r
1720  * BarSeries class for the charts widget.\r
1721  * @constructor\r
1722  */\r
1723 Ext.chart.BarSeries = Ext.extend(Ext.chart.CartesianSeries, {\r
1724     type: "bar"\r
1725 });\r
1726 \r
1727 \r
1728 /**\r
1729  * @class Ext.chart.PieSeries\r
1730  * @extends Ext.chart.Series\r
1731  * PieSeries class for the charts widget.\r
1732  * @constructor\r
1733  */\r
1734 Ext.chart.PieSeries = Ext.extend(Ext.chart.Series, {\r
1735     type: "pie",\r
1736     dataField: null,\r
1737     categoryField: null\r
1738 });